AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 24.02.2011, 11:17   #1  
Denicce is offline
Denicce
Участник
 
62 / 54 (2) ++++
Регистрация: 22.03.2005
Адрес: Москва
Lightbulb Открыть текстовый файл 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  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Если не ошибаюсь, то именно в версии Ax4.0 появился новый класс TextIo() наследник от AsciiIo. Однако у него в методе new() в качестве третьего (не обязательного) параметра можно указать признак кодовой страницы в которой и следует читать/писать данные в этом файле.
За это сообщение автора поблагодарили: Denicce (2).
Старый 27.02.2011, 17:38   #3  
plumbum is offline
plumbum
Участник
Соотечественники
 
182 / 86 (3) ++++
Регистрация: 07.12.2007
Адрес: Vienna, AT
.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);
P.S.
Жаль мне только не удалось скомпилировать его
АХ ругается на метод Convert
__________________
http://www.axdevposts.blogspot.com
Пришел, уведел.... отойди, дай другому увидеть!
Старый 27.02.2011, 20:25   #4  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
allBytes1251 и allBytesUTF8 надо определять как System.Byte[].
Кроме того, должно быть так GetEncoding("windows-1251") или GetEncoding(1251)
__________________
Axapta v.3.0 sp5 kr2
Старый 28.02.2011, 10:39   #5  
plumbum is offline
plumbum
Участник
Соотечественники
 
182 / 86 (3) ++++
Регистрация: 07.12.2007
Адрес: Vienna, AT
Цитата:
Сообщение от AndyD Посмотреть сообщение
allBytes1251 и allBytesUTF8 надо определять как System.Byte[].
Кроме того, должно быть так GetEncoding("windows-1251") или GetEncoding(1251)
пробовал, не выходит...

Цитата:
Сообщение от AndyD Посмотреть сообщение
allBytes1251 и allBytesUTF8 надо определять как System.Byte[].
Кроме того, должно быть так GetEncoding("windows-1251") или GetEncoding(1251)
тут согласен полностью
__________________
http://www.axdevposts.blogspot.com
Пришел, уведел.... отойди, дай другому увидеть!
Старый 28.02.2011, 11:46   #6  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
Э-м.
Как-то вы процитировали неаккуратно. Не понятно, с чем вы согласны, а с чем нет
Но вот такой код нормально компилируется и выполняется на 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  
plumbum is offline
plumbum
Участник
Соотечественники
 
182 / 86 (3) ++++
Регистрация: 07.12.2007
Адрес: Vienna, AT
Вы правы по поводу названия кодовой страницы.
И то что компилируется в AX2009 тоже верно, но у человека АХ 4.0, а там такой код не компилируется (пробовал AX4.0 SP2 WIN2003 x64). ругается на эту строчку:

X++:
System.Byte[]       allBytes1251;
__________________
http://www.axdevposts.blogspot.com
Пришел, уведел.... отойди, дай другому увидеть!
Старый 28.02.2011, 13:29   #8  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Цитата:
Сообщение от AndyD Посмотреть сообщение
Э-м.
Как-то вы процитировали неаккуратно. Не понятно, с чем вы согласны, а с чем нет
Но вот такой код нормально компилируется и выполняется на DAX2009 SP5 и WIN2008R2 x64
X++:
    allBytes1251         = System.IO.File::ReadAllBytes(@"c:\Temp\1.txt");
Почему не File.ReadAllText?
Старый 28.02.2011, 14:40   #9  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
Потому что, вот Открыть текстовый файл ansi (win1251) на нерусифицированной Windows.
Я, собственно, с plumbum беседовал
__________________
Axapta v.3.0 sp5 kr2
Старый 03.03.2011, 15:25   #10  
Denicce is offline
Denicce
Участник
 
62 / 54 (2) ++++
Регистрация: 22.03.2005
Адрес: Москва
Переделал на TextIO, все работает. Всем спасибо!

P.S.
Через .NET не вышло, как предложили plumbum и AndyD.

Последний раз редактировалось Denicce; 03.03.2011 в 15:54.
Теги
ansi, text, textbuffer, textio, unicode, кодовая страница, текстовый файл, asciio

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Как открыть файл novic DAX: Программирование 4 02.04.2010 11:18
Web-портал: открыть файл cherv DAX: Программирование 4 19.05.2008 16:42
Client Axapta 3.0 SP4 и Linux. Как запустить? Daiver DAX: Администрирование 10 28.06.2007 15:59
Экспорт в текстовый файл с разделителями EAlex DAX: Программирование 7 14.07.2004 15:17
Экспорт накладных в текстовый файл SNG DAX: Программирование 20 13.11.2003 16:31

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 17:54.