Задача: прочитать в 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));
}