24.02.2011, 11:17 | #1 |
Участник
|
Открыть текстовый файл ansi (win1251) на нерусифицированной Windows.
Задача: прочитать в axapta текстовый файл, сохраненный в кодировке Windows-1251 (ansi) на нелокализованной Windows. Смена региональных настроек ОС недопустима. Версия axapta DAX40SP2.
В-общем, поискал, порылся, сделал следующим образом, может, что получше предложите. За реализацию WinApi функции преобразования текста ansi->utf8 спасибо AndyD. Пробовал через Binary и получение массива символов через COMVariant и SafeArray. Потом в цикле сдвиг зоны кодов символов 192-255 ("А".."я") на 848 вперед. Работает, но медленно. Может, как-то упростить и сделать через .NET (на форуме можно найти функции преобразования ansi->utf8, но, как я понял, там могу быть проблемы с подключением references у пользователей. Не сообразил, как можно преобразовать строку и сразу с ней работать, без сохранения файла с конвертированным текстом и открытия оного как utf-8 через TextBuffer. Тут тоже какие-то оптимизации возможны, я думаю. P.S. Кстати, вся эта канитель возникла при импорте банковской выписки, сохраненной в формате 1С. Не нашли возможности формировать эту выписку сразу в Unicode, что исключило бы проблемы с чтением файла. X++: client static void kird_fileAnsi2utf8_forum(Args _args) { TextBuffer tb = new TextBuffer(); FileName filenameANSI = "c:\\TEMP\\ansi.txt"; FileName filenameUTF8 = "c:\\TEMP\\utf8.txt"; str text; #define.CP_WinCyrillic(1251) // windows cyrillic #define.CP_UTF8(65001) // UTF-8 str Ansi2Utf8(str Ansi) // THANKS AndyD { DLL _kernelDLL = new DLL("KERNEL32"); DLLFunction MultiByteToWideChar = new DLLFunction(_kernelDLL, "MultiByteToWideChar"); DLLFunction WideCharToMultiByte = new DLLFunction(_kernelDLL, "WideCharToMultiByte"); Binary buf, buf1; int len; str res; ; res = ""; if (Ansi) { buf = new Binary(strlen(Ansi)+1); // тут нужно +1, иначе код сваливается с ошибкой. buf.string(0, Ansi); buf1 = new Binary((strlen(Ansi) + 1) * 2); MultiByteToWideChar.returns(ExtTypes::DWord); MultiByteToWideChar.arg(ExtTypes::DWord, ExtTypes::DWord, ExtTypes::Pointer, ExtTypes::DWord, ExtTypes::Pointer, ExtTypes::DWord); if (MultiByteToWideChar.call(#CP_WinCyrillic, 0, buf, strlen(Ansi) + 1, buf1, strlen(Ansi) + 1)) { WideCharToMultiByte.returns(ExtTypes::DWord); WideCharToMultiByte.arg(ExtTypes::DWord, ExtTypes::DWord, ExtTypes::Pointer, ExtTypes::DWord, ExtTypes::Pointer, ExtTypes::DWord, ExtTypes::DWord, ExtTypes::DWord); len = WideCharToMultiByte.call(#CP_UTF8, 0, buf1, strlen(Ansi) + 1, buf, 0, 0, 0); if (len) { buf = new Binary(len); if (WideCharToMultiByte.call(#CP_UTF8, 0, buf1, strlen(Ansi) + 1, buf, len, 0, 0)) res = buf.string(0); } } } return res; } void saveIO() // сохраняем через AsciiIo, т.к. работает быстрее в 5-10 раз, чем сохранение через TextBuffer.toFile() { AsciiIo aSCIIFile; ; aSCIIFile = new AsciiIo(filenameUTF8, "w"); aSCIIFile.write(text); return; } ; // OPEN FILE tb = new TextBuffer(); if (! tb.fromFile(filenameANSI)) throw error('bad open ansi'); text = tb.getText(); info(strfmt("ansi: %1", text)); // CONVERT TEXT text = num2char(0xEF)+num2char(0xBB)+num2char(0xBF)+ // utf-8 file header. it is needed. Ansi2Utf8(text); // SAVE FILE IN UTF-8 saveIO(); // OPEN FILE AS UTF-8 tb = new TextBuffer(); tb.fromFile(filenameUTF8, FileEncoding::UTF8); text = tb.getText(); info(strfmt("utf8: %1", text)); } |
|
|
За это сообщение автора поблагодарили: Vasil (1). |
25.02.2011, 14:42 | #2 |
Участник
|
Если не ошибаюсь, то именно в версии Ax4.0 появился новый класс TextIo() наследник от AsciiIo. Однако у него в методе new() в качестве третьего (не обязательного) параметра можно указать признак кодовой страницы в которой и следует читать/писать данные в этом файле.
|
|
|
За это сообщение автора поблагодарили: Denicce (2). |
27.02.2011, 17:38 | #3 |
Участник
|
.NET библиотеки, которые Вам нужны, уже подключены в References
Смотрите тут Код выглядел бы примерно так: X++: System.Text.Encoding encoding1251 = System.Text.Encoding::GetEncoding("1251"); System.Text.Encoding encodingUTF8 = System.Text.Encoding::get_UTF8(); CLRObject allBytes1251; CLRObject allBytesUTF8; str text; ; allBytes1251 = System.IO.File::ReadAllBytes("My file"); allBytesUTF8 = System.Text.Encoding::Convert(encoding1251, encodingUTF8, allBytes1251); System.IO.File::WriteAllBytes("My file unicode", allBytesUTF8); Жаль мне только не удалось скомпилировать его АХ ругается на метод Convert
__________________
http://www.axdevposts.blogspot.com Пришел, уведел.... отойди, дай другому увидеть! |
|
27.02.2011, 20:25 | #4 |
Участник
|
allBytes1251 и allBytesUTF8 надо определять как System.Byte[].
Кроме того, должно быть так GetEncoding("windows-1251") или GetEncoding(1251)
__________________
Axapta v.3.0 sp5 kr2 |
|
28.02.2011, 10:39 | #5 |
Участник
|
Цитата:
тут согласен полностью
__________________
http://www.axdevposts.blogspot.com Пришел, уведел.... отойди, дай другому увидеть! |
|
28.02.2011, 11:46 | #6 |
Участник
|
Э-м.
Как-то вы процитировали неаккуратно. Не понятно, с чем вы согласны, а с чем нет Но вот такой код нормально компилируется и выполняется на DAX2009 SP5 и WIN2008R2 x64 X++: System.Text.Encoding encoding1251 = System.Text.Encoding::GetEncoding(1251); System.Text.Encoding encodingUTF8 = System.Text.Encoding::get_UTF8(); System.Byte[] allBytes1251; System.Byte[] allBytesUTF8; ; allBytes1251 = System.IO.File::ReadAllBytes(@"c:\Temp\1.txt"); allBytesUTF8 = System.Text.Encoding::Convert(encoding1251, encodingUTF8, allBytes1251); System.IO.File::WriteAllBytes(@"c:\Temp\2.txt", allBytesUTF8);
__________________
Axapta v.3.0 sp5 kr2 |
|
28.02.2011, 12:25 | #7 |
Участник
|
Вы правы по поводу названия кодовой страницы.
И то что компилируется в AX2009 тоже верно, но у человека АХ 4.0, а там такой код не компилируется (пробовал AX4.0 SP2 WIN2003 x64). ругается на эту строчку: X++: System.Byte[] allBytes1251;
__________________
http://www.axdevposts.blogspot.com Пришел, уведел.... отойди, дай другому увидеть! |
|
28.02.2011, 13:29 | #8 |
Участник
|
Цитата:
|
|
28.02.2011, 14:40 | #9 |
Участник
|
Потому что, вот Открыть текстовый файл ansi (win1251) на нерусифицированной Windows.
Я, собственно, с plumbum беседовал
__________________
Axapta v.3.0 sp5 kr2 |
|
03.03.2011, 15:25 | #10 |
Участник
|
Переделал на TextIO, все работает. Всем спасибо!
P.S. Через .NET не вышло, как предложили plumbum и AndyD. Последний раз редактировалось Denicce; 03.03.2011 в 15:54. |
|
Теги |
ansi, text, textbuffer, textio, unicode, кодовая страница, текстовый файл, asciio |
|
Похожие темы | ||||
Тема | Ответов | |||
Как открыть файл | 4 | |||
Web-портал: открыть файл | 4 | |||
Client Axapta 3.0 SP4 и Linux. Как запустить? | 10 | |||
Экспорт в текстовый файл с разделителями | 7 | |||
Экспорт накладных в текстовый файл | 20 |
|