Russian Qt Forum

Qt => Общие вопросы => Тема начата: OS2 от Март 06, 2018, 00:00



Название: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 06, 2018, 00:00
Всем доброго времени суток!

Проблема в следующем: есть строка в wchar_t (тип BSTR), в ней находится содержимое png-файла (pngDATA). Пытаюсь сохранить содержимое в файл:
Код:
QFile* pfIco = new QFile( "MyFile.png");
if( !pfIco->open( QIODevice::WriteOnly ) ) {...}
const int iFileSize = SysStringLen( pngDATA );
QDataStream out(pfIco);
out << QString::fromWCharArray(pngDATA, icoFileSize).toUtf8();
pfIco->close();
delete pfIco; pfIco = nullptr;
Содержимое сохраняется не корректно, пробовал писать в QDataStream так:
Код:
QByteArray ba = QByteArray((char*)pngDATA, icoFileSize);
out << ba;
тоже безуспешно.
Подскажите, кто знает, в чем ошибка?  ???


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: ssoft от Март 06, 2018, 08:47
Не ясно, что требуется то? Сохранить png файл или строку в текстовом виде?

Если файл, то QDataStream и не нужен

Код
C++ (Qt)
QFile* pfIco = new QFile( "MyFile.png");
if( !pfIco->open( QIODevice::WriteOnly ) ) {...}
const int iFileSize = SysStringLen( pngDATA );
pfIco->writeData( pngDATA, iFileSize );
pfIco->close();
delete pfIco; pfIco = nullptr;
 


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: kuzulis от Март 06, 2018, 10:08
Код
C++ (Qt)
const wchar_t *data = ...;
const size_t *dataSize = ...; // in bytes
 
QFile f;
QDataStream out(&f, QIODevice::WriteOnly);
out.writeRawData(reinterpret_cast<const char *>(data), dataSize);
 


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 06, 2018, 10:16
Не ясно, что требуется то? Сохранить png файл или строку в текстовом виде?

Если файл, то QDataStream и не нужен

Код
C++ (Qt)
QFile* pfIco = new QFile( "MyFile.png");
if( !pfIco->open( QIODevice::WriteOnly ) ) {...}
const int iFileSize = SysStringLen( pngDATA );
pfIco->writeData( pngDATA, iFileSize );
pfIco->close();
delete pfIco; pfIco = nullptr;
 

Сохранить необходимо png файл.
При попытке записать BSTR строку:
Код:
pfIco->write( (char*)pngDATA, iFileSize );
данные сохраняются не корректно, png файл не читаем.
Если сохранять так:
Код:
pfIco->write( QString::fromWCharArray(pngDATA, iFileSize).toLocal8Bit(), iFileSize );
то в ряде случаев, некоторые файлы сохраняются не корректно, хотя присутствуют и правильные данные.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 06, 2018, 10:20
Код
C++ (Qt)
const wchar_t *data = ...;
const size_t *dataSize = ...; // in bytes
 
QFile f;
QDataStream out(&f, QIODevice::WriteOnly);
out.writeRawData(reinterpret_cast<const char *>(data), dataSize);
 
Пробовал так. Все данные битые.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: Old от Март 06, 2018, 10:27
Пробовал так. Все данные битые.
Как вы получаете данные на которые указывает pngDATA?


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 06, 2018, 10:37
Данные получаю из COM в виде BSTR строки.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: Old от Март 06, 2018, 10:41
Данные получаю из COM в виде BSTR строки.
Как получаете? Покажите код, которые аллоцирует буфер и читает в него из последовательного порта данные.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 06, 2018, 11:55
Я имел в виду не COM-порт, это COM объект.  8)
Сам я ничего не аллоцирую, получаю готовую строку из библиотеки.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 06, 2018, 13:07
При сохранении строки в файл, не правильно сохраняется 1 байт: вместо 98 записывается 3F (в HEX).
Сейчас сохраняю так:
Код:
const int iSize = SysStringLen( pngDATA );
pfIco->write( QString::fromWCharArray(pngDATA, iSize).toLocal8Bit(),iSize );


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: ViTech от Март 06, 2018, 13:50
При сохранении строки в файл, не правильно сохраняется 1 байт: вместо 98 записывается 3F (в HEX).

Сначала надо проверить, точно ли в буфере данные, пригодные для сохранения в файл (PNG Specification (http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html)). Согласно спецификации первые байты должны быть: 89  50  4e  47  0d  0a  1a  0a. Так что нужно ещё проверить Порядок байтов (https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA_%D0%B1%D0%B0%D0%B9%D1%82%D0%BE%D0%B2) big-endian или little-endian в буфере, и какой порядок нужен для файла. И сохраняйте лучше как ssoft предложил, промежуточные QString, QDataStream и т.п. могут только путаницы добавить. Также следите за правильностью типа и объёма записываемых данных.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 06, 2018, 14:04
Приходят правильные данные (тоесть: в BSTR хранится полностью корректный набор данных), но при записи их в файл подменяется значение с: "98", на: "3F".  :(


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: ViTech от Март 06, 2018, 14:17
но при записи их в файл подменяется значение с: "98", на: "3F".  :(

В файл записывается ровно то, что вы туда отправили, никто ничего не подменяет :).  Скорей всего здесь QString::fromWCharArray(pngDATA, iSize).toLocal8Bit() что-то преобразовывается не так как хотелось бы. Почитайте внимательнее возможные проблемы и рекомендации из моего предыдущего сообщения.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: Kurles от Март 06, 2018, 15:00
Код:
const int iFileSize = SysStringLen( pngDATA );

Я не совсем в теме, но корректно ли длину png файла функцией SysStringLen считать?



Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 06, 2018, 16:18
Докопался до того, что в toLocal8Bit() преобразовывается один единственный символ: "0x98" в: "0x63", по какой причине это происходит - выяснить пока не удалось.
По поводу спецификации png и порядка следования байт - все в порядке, заголовок файла правильный.
SysStringLen() - считает длину корректно.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: kambala от Март 07, 2018, 17:40
toLocal8Bit() конвертирует в текущую кодовую страницу, на русской винде по умолчанию это CP1251 — скорее всего отсюда и проблема


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: Igors от Март 08, 2018, 08:33
По поводу спецификации png и порядка следования байт - все в порядке, заголовок файла правильный.
SysStringLen() - считает длину корректно.
Если пишете в png - то надо писать с помощью тамошнего API, т.е. не просто "строка" (на деревню дедушке), а тег который читатели понимают, напр Title, Author, Description и др. Насколько я помню, там только латиница.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 08, 2018, 14:42
Цитировать
Если пишете в png - то надо писать с помощью тамошнего API, т.е. не просто "строка" (на деревню дедушке), а тег который читатели понимают, напр Title, Author, Description и др. Насколько я помню, там только латиница.
Мне передается содержимое png файла, через BSTR строку, я пытаюсь сохранить эту строку в такойже png файл, при чем здесь тег Title, Author и т.д.???


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: Igors от Март 10, 2018, 10:37
Мне передается содержимое png файла, через BSTR строку, я пытаюсь сохранить эту строку в такойже png файл, при чем здесь тег Title, Author и т.д.???
При том что файл имеет формат и если его нарушить - файл станет нечитаемым. Грубо говоря
Цитировать
заголовок
   - тег1
   - тег2
...
содержимое (картинка, может упакованная)
Куда (в какое место) и что Вы хотите писать?


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 10, 2018, 12:11
Строка это и есть файл (все его содержимое), содержимое этой строки я записываю в файл на диске (например png).


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: kambala от Март 10, 2018, 14:51
если есть возможность, лучше вместо BSTR получать чистые байты, тогда и проблемы не будет. если нет, попробуй toLatin() вместо toLocal8Bit().


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: OS2 от Март 10, 2018, 20:59
Пробовал, сохраняет не правильно, размер файла увеличен в 2 раза, через каждый байт вставляет пустые символы.


Название: Re: Как правильно записать wchar_t в бинарный файл?
Отправлено: kambala от Март 10, 2018, 22:31
это из-за того, что wchar_t двухбайтовый в винде. Можно конечно банально отрезать нули через один после конвертации :)