Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Yegor от Апрель 08, 2015, 16:22



Название: [РЕШЕНО] Редактирование файла с помощью QDataStream
Отправлено: Yegor от Апрель 08, 2015, 16:22
Здравствуйте, уважаемые форумчане!

У меня есть бинарный файл, который я создал с помощью QDataStream. Открыл файл только для записи...
Код
C++ (Qt)
// Open cur tmpl file for reading only.
QFile file(strFilePath);
if(!file.open(QIODevice::WriteOnly))
   throw tr("Can't open file %1\n%2")
       .arg(strFilePath)
       .arg(file.errorString());
 
// Set data stream.
QDataStream out(&file);
out.setByteOrder(QDataStream::LittleEndian); //Set endian.
out.setVersion(QDataStream::Qt_5_4);         //Set byte order.
 
...и далее кидал туда объекты с помощью сериализации.

Код
C++ (Qt)
out << m_strCommnets // The comment text.
.....................
out << other_obj1;
out << other_obj2;
 

В самом начале я сохранил объект m_strComment, далее уже остальные объекты.

Вопрос: как можно в следующий раз открыть файл для редактирования, чтобы изменить лишь эту переменную  m_strComment, а остальные не трогать. При этом используя класс QDataStream?


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: gil9red от Апрель 08, 2015, 16:24
Код
C++ (Qt)
in >> m_strCommnets; // The comment text.
?


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Zerkin от Апрель 08, 2015, 16:30
У стрима device()->seek(0). А дальше как указали выше. Если я вас правильно понял.


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 08, 2015, 17:18
Имхо, длина m_strCommnets должна быть постоянной, чтобы не поплыло ничего


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Yegor от Апрель 08, 2015, 17:38
Я имел ввиду, что нужно считать...
Код
C++ (Qt)
in >> m_strCommnets; // The comment text.
...отредактировать, а затем вернуть отредактированный QString обратно в файл. Чтобы структура файла не нарушилась (позже можно было повторно загружать все объекты). Как внутри одного и того же файла редактировать первый объект?


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Smogg от Апрель 08, 2015, 18:08
Определиться с необходимой и достаточной длинной m_strCommnets. При превышении - принудительно обрезать. При недостатке - забивать хвост строки "невозможными символами" (даже ASCII имеет всякую никчемную дребедень, а юникод и подавно). Таким костыльным макаром строка будет всегда статичного размера.

Как то так?


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 08, 2015, 20:09
При недостатке - забивать хвост строки "невозможными символами"
Я бы посоветовал эти "невозможные символы" заменить нолями. Так в случае отладки не будут морочить голову, если вдруг забудется, что строка фиксированной длинны.


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Igors от Апрель 09, 2015, 08:21
Право, ответы меня удивили
Вопрос: как можно в следующий раз открыть файл для редактирования, чтобы изменить лишь эту переменную  m_strComment, а остальные не трогать. При этом используя класс QDataStream?
Эта затея мертворожденная - никогда не пытайтесь "редактировать" файл данных. Если такая необходимость возникла - значит вместо файла надо юзать СУБД. А файл перезаписывайте всегда "с нуля", в крайнем случае можно "пополнять" (дописывать в хвост), но это редко. 


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Old от Апрель 09, 2015, 09:37
Право, ответы меня удивили
+1 Особенно последний.

А файл перезаписывайте всегда "с нуля", в крайнем случае можно "пополнять" (дописывать в хвост), но это редко. 
Ерунда. Это зависит от задачи.


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 09, 2015, 09:46
Igors, hex редакторы, ведь, не переписывают файлы с 0, если мы просто поправим первый байт в 200Гб файле.


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Old от Апрель 09, 2015, 09:52
Igors, hex редакторы, ведь, не переписывают файлы с 0, если мы просто поправим первый байт в 200Гб файле.
Если "файл" это расписание дня домохозяйки, то его можно хоть по 100 раз на дню перезаписывать. :)
Но в мире есть файлы, которые нужно править не переписывая полностью.


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 09, 2015, 10:01
Если "файл" это расписание дня домохозяйки, то его можно хоть по 100 раз на дню перезаписывать. :)
Если уж на то пошло, то и расписание домохозяйки можно править :)
Главное, чтобы строки были фиксированной ширины


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Igors от Апрель 09, 2015, 10:19
Главное, чтобы строки были фиксированной ширины
Не улавливаете аналогии с "поля", "записи"? Очень быстро приходит ощущение что городится велосипед, причем самый никудышний - какое-то самопальное СУБД. Зачем если это можно сделать цивильно и с куда меньшими затратами.

Но в мире есть файлы, которые нужно править не переписывая полностью.
В мире может и есть, но одобрять желание начинающего копаться seek'ом для перезаписи файла - это просто неграмотно. Самая настоящая "ерунда"  :)


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Old от Апрель 09, 2015, 10:35
В мире может и есть, но одобрять желание начинающего копаться seek'ом для перезаписи файла - это просто неграмотно. Самая настоящая "ерунда"  :)
Неграмотно делать громкие ошибочные заявления от лица всей отрасли. Но вам не привыкать...  ;D


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 09, 2015, 10:45
Не улавливаете аналогии с "поля", "записи"? Очень быстро приходит ощущение что городится велосипед, причем самый никудышний - какое-то самопальное СУБД. Зачем если это можно сделать цивильно и с куда меньшими затратами.
В упор не вижу связи между задачей автора и СУБД.
Как вы запишите в СУБД то, что я запишу в файл в виде структуры:

Строка длинной 30
Количество флоатов
массив флоатов
Количество интов
Массив интов
?

По мне так, для такой простой задачи тянуть в проект СУБД = боль. Особенно, если я не знаком с SQL


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 09, 2015, 10:48
В мире может и есть, но одобрять желание начинающего копаться seek'ом для перезаписи файла - это просто неграмотно. Самая настоящая "ерунда"  :)
Ерунда - перезаписывать файл в 200 Гб, когда вам нужно только поправить первые 2-3 байта ;)


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Bepec от Апрель 09, 2015, 12:43
Поддерживаю __Heaven__, недоумеваю от Igors.

А seek'ом пользуются все, в том числе и драйверы СУБД :)


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Igors от Апрель 09, 2015, 12:50
В упор не вижу связи между задачей автора и СУБД.
Как вы запишите в СУБД то, что я запишу в файл в виде структуры:

Строка длинной 30
Количество флоатов
массив флоатов
Количество интов
Массив интов
?

По мне так, для такой простой задачи тянуть в проект СУБД = боль. Особенно, если я не знаком с SQL
А что Вы сможете здесь "редактировать" если изменилось кол-во флотов и/или интов? Будете делать ветку которая будет писать "когда кол-во не изменилось", потом отслеживать "а изменилось ли" - причем весь файл все равно писать придется.

..перезаписывать файл в 200 Гб, когда вам нужно только поправить первые 2-3 байта ;)
А тут Вы просто не сможете загрузить его весь в память, придется что-то придумывать - и в первую очередь вспоминать о том же СУБД.

Ерунда
Еще раз - и на Ваши посты отвечать перестану


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 09, 2015, 12:55
А что Вы сможете здесь "редактировать" если изменилось кол-во флотов и/или интов? Будете делать ветку которая будет писать "когда кол-во не изменилось", потом отслеживать "а изменилось ли" - причем весь файл все равно писать придется.
В самом начале я сохранил объект m_strComment, далее уже остальные объекты.

Вопрос: как можно в следующий раз открыть файл для редактирования, чтобы изменить лишь эту переменную  m_strComment, а остальные не трогать. При этом используя класс QDataStream?

А тут Вы просто не сможете загрузить его весь в память, придется что-то придумывать - и в первую очередь вспоминать о том же СУБД.
Нет необходимости загружать его весь в память


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Old от Апрель 09, 2015, 13:01
Еще раз - и на Ваши посты отвечать перестану
Все как всегда. :)
Как делать громкие безапелляционные заявления от лица всей отрасли, то вы в первых рядах. А как только сказали, что это ерунда - надули губки. Как видите, не я один так считаю.


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Yegor от Апрель 09, 2015, 13:47
Вижу, что это простое решение, пользоваться seek-ом. Но вот меня мучает вопрос. Во всех ли случаях, когда объект QString имеет фиксированное количество символов, он имеет всегда одинаковый фактический размер в байтах (sizeof(m_strCommnet))?
То есть его размер не зависит от языка ввода, например?


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: gil9red от Апрель 09, 2015, 13:53
Вижу, что это простое решение, пользоваться seek-ом. Но вот меня мучает вопрос. Во всех ли случаях, когда объект QString имеет фиксированное количество символов, он имеет всегда одинаковый фактический размер в байтах (sizeof(m_strCommnet))?
То есть его размер не зависит от языка ввода, например?

Все символы всегда имеют одинаковый размер :)


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 09, 2015, 14:23
Цитировать
QString stores a string of 16-bit QChars, where each QChar corresponds one Unicode 4.0 character


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Smogg от Апрель 09, 2015, 23:20
При недостатке - забивать хвост строки "невозможными символами"
Я бы посоветовал эти "невозможные символы" заменить нолями. Так в случае отладки не будут морочить голову, если вдруг забудется, что строка фиксированной длинны.
Ну, в общем да, никак не обойтись без явного выделения места под "коммент"... Т.е. в пустой файл надо сначала записать блок нулей, где потом будет писаться коммент. И не забывать, что нужно делать seek() перед каждым чтением/записью в зависимости от вида данных.


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Igors от Апрель 10, 2015, 06:32
В самом начале я сохранил объект m_strComment, далее уже остальные объекты.

Вопрос: как можно в следующий раз открыть файл для редактирования, чтобы изменить лишь эту переменную  m_strComment, а остальные не трогать. При этом используя класс QDataStream?
Даже в этом простейшем случае забот хватает. QDataStream запишет свою (текущую) версию которая может не соответствовать записанным данным. Можно конечно зарезервировать фиксированное число байт в начале, сначала писать их через QFile::write, а затем уже заряжать QDataStream. Но тогда начинается возня с toLocal8bit. Да и вообще как-то коряво - чего менять комментарии если начинка старая ?


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 10, 2015, 11:01
QDataStream запишет свою (текущую) версию которая может не соответствовать записанным данным.
Мне казалось, что версию должен писать не Qt.

Код
C++ (Qt)
#include <QCoreApplication>
#include <QDataStream>
#include <QFile>
 
int main(int argc, char *argv[])
{
   QCoreApplication a(argc, argv);
 
   QFile file("D:\\tmp\\bin");
   file.open(QFile::WriteOnly);
   QDataStream out(&file);
   out.setByteOrder(QDataStream::LittleEndian);
   out << QString("text");
 
   out << 1 << 2 << 3;
   return 0;
}
 
Надеюсь, картинка ниже понятная


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 10, 2015, 11:09
Кстати, пока делал пример, заинтересовало:
Почему разработчики Qt выбрали значение по умолчанию  QDataStream::BigEndian ?
Мне казалось, что Little более популярная за счёт x86


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Old от Апрель 10, 2015, 11:25
Кстати, пока делал пример, заинтересовало:
Почему разработчики Qt выбрали значение по умолчанию  QDataStream::BigEndian ?
Мне казалось, что Little более популярная за счёт x86
Думаю, потому, что это сетевой порядок байт.


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 10, 2015, 11:40
А в каких ситуациях играет роль enum Version?


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Igors от Апрель 10, 2015, 11:41
Мне казалось, что версию должен писать не Qt.
Правильно казалось, версию Qt он пишет для структур (напр QFont). А QString просто счетчик и по два байта на символ в юникоде.

Кстати, пока делал пример, заинтересовало:
Почему разработчики Qt выбрали значение по умолчанию  QDataStream::BigEndian ?
Мне казалось, что Little более популярная за счёт x86
Дань традиции, данные на диске в big


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 10, 2015, 11:48
А в каких ситуациях играет роль enum Version?
qint64, float, double


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: __Heaven__ от Апрель 10, 2015, 12:04
Правильно казалось, версию Qt он пишет для структур (напр QFont). А QString просто счетчик и по два байта на символ в юникоде.

Для QString, влияет byteOrder и, как оказалось, version тоже.

Пока искал ответ, в исходниках нашёл забавную строчку :)
Код
C++ (Qt)
if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian))


Название: Re: Редактирование файла с помощью QDataStream
Отправлено: Yegor от Апрель 10, 2015, 12:53
Решение сделал такое:
Код
C++ (Qt)
// Pack comment (arg) - set it to fixed len.
// Do this with comment before saving it to file.
QString packComment ( const QString &strRawComment )
{
   const int raw_comment_len = strRawComment.length(); // Get the length of raw comment string.
   QString strInitial ( COMMENT_LEN, QChar(0x0000) );  // Create initial string, whith fixed len, populated by null charcters.
   QString strResult = strRawComment;                  // To save result and return it.
 
   // Control the len of raw string.
 
   // Bigger.
   if(raw_comment_len > COMMENT_LEN)   // If bigger -
       strResult.resize(COMMENT_LEN); // rersize,
 
   // Smaller.
   else if(raw_comment_len < COMMENT_LEN) // If smaller - create new, where the rest are null characters (0x0000).
       strResult = strInitial.replace(0, raw_comment_len, strRawComment);
 
   // Else equal.
 
   // Return result.
   return strResult;
}
 
// Unpack comment.
// Transform string (which was loaded from file) - to form whitch is suitable for user (remove all null chars (0x0000)).
QString unpackComment ( const QString &packedComment )
{
   // Create new string to be routed and returned.
   QString result = packedComment;
 
   // Route string - remove all null characters.
   result.remove(QChar(0x0000));
 
   // Return result.
   return result;
}
 

Спасибо большое всем за помощь!