Russian Qt Forum
Ноябрь 24, 2024, 14:31 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Насколько правильно такое считывание бинарного файла  (Прочитано 4954 раз)
Alex_C
Гость
« : Март 29, 2012, 18:01 »

Т.к. перехожу с дельфи, хочу правильно писать программы на Qt.
Хочу чтоб сказали, на сколько правильный код. Нужно считать бинарный фаил, описывающий массив "точек", каждая точка представляет из себя такую структуру:
Код:
struct MapPoint
{
    quint16 code;
    qint16 lat;
    qint16 lon;
};
считываю так
Код:
    QFile f(fileName);
    if(!f.open(QIODevice::ReadOnly))
    {
        QMessageBox::critical(0, "Error!", "Can not open " + fileName);
        return false;
    }

    quint64 poinCount = f.size() / (sizeof(quint16) + sizeof(qint16) * 2);

    mapPoints = new QVector<MapPoint>;
    mapPoints->resize(poinCount);

    QDataStream in(&f);

    int i = 0;
    MapPoint m;
    while (!in.atEnd()) {
        in >> m.code >> m.lat >> m.lon;
        mapPoints->append(m);
        i++;
    }

Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Март 29, 2012, 18:12 »

Вы не должны делать никаких предположений о длине данных на диске - она может очень отличаться от sizeof. Ну и f.size() вообще не годится если в файле что-то еще

А главное - все проще. Определите операторы << и >> для Вашей структуры (элемента вектора) и спокойно используйте >> для вектора
Код:
QDataStream in(&f);
in >> mapPoints;
И все дела

Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #2 : Март 29, 2012, 18:19 »

Лучше так:
Код
C++ (Qt)
   QFile file(fileName);
   if(!file.open(QIODevice::ReadOnly)) {
       QMessageBox::critical(0, "Error!", "Can not open " + fileName);
       return false;
   }
 
   QVector<MapPoint> mapPoints;
   QDataStream in(&file);
   in >> mapPoints;
 

Нужно только перегрузить операторы:
Код
C++ (Qt)
QDataStream &operator<<(QDataStream & out, const MapPoint &mp) {
   out << mp.code << mp.lat << mp.lon;
   return out;
}
 
QDataStream &operator>>(QDataStream & in, MapPoint &mp) {
   in >> mp.code >> mp.lat >> mp.lon;  
   return in;
}
 
 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Blackwanderer
Гость
« Ответ #3 : Март 30, 2012, 06:36 »

И не забывайте про QDataStream::setVersion()
Записан
sidsukana
Гость
« Ответ #4 : Март 30, 2012, 06:47 »

Можно так еще, старт позицию и длину сам укажешь. Длина обычно sizeof() - опять же если ты уверен в том что там именно эти данные.
Код
C++ (Qt)
QByteArray buffer = file.readAll();
MapPoint point = *reinterpret_cast<MapPoint*>(buffer.mid(startpos, length).data());
Записан
Alex_C
Гость
« Ответ #5 : Март 30, 2012, 08:53 »

Всем большое спасибо за ответы!
Вопрос по последнему варианту
Код:
QByteArray buffer = file.readAll();
MapPoint point = *reinterpret_cast<MapPoint*>(buffer.mid(startpos, length).data());

Зачем после mid еще data стоит? mid ведь и так QByteArray возвращает?
Записан
sidsukana
Гость
« Ответ #6 : Март 30, 2012, 09:12 »

А у тебя MapPoint в QByteArray разве?) Приведение типа происходит из сырых данных.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Март 30, 2012, 13:41 »

Можно так еще, старт позицию и длину сам укажешь. Длина обычно sizeof() - опять же если ты уверен в том что там именно эти данные.
Код
C++ (Qt)
QByteArray buffer = file.readAll();
MapPoint point = *reinterpret_cast<MapPoint*>(buffer.mid(startpos, length).data());
Это "как не надо делать" - блочное чтение в стиле C пригодное только для POD структур, да и то не всегда. Суть никак не меняется от того что использованы классы и reinterpret_cast вместо "просто приведения"
Записан
sidsukana
Гость
« Ответ #8 : Март 30, 2012, 13:57 »

Ну, можно директивой выравнивания структур воспользоваться.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #9 : Март 30, 2012, 14:09 »

Ну, можно директивой выравнивания структур воспользоваться.
А можно просто один раз по-человечески сделать и забыть)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Март 30, 2012, 14:18 »

Ну, можно директивой выравнивания структур воспользоваться.
Пользовался Улыбающийся Вообще в свое время я довольно долго держался за такое запись/чтение, хотя минусы перли из всех щелей. Просто конец всегда один - это придется вычистить. Поэтому если человек начинает - нет смысла ему это рекомендовать.
А можно просто один раз по-человечески сделать и забыть)
За спиной мощного инструментария легко быть смелым  Улыбающийся
Записан
sidsukana
Гость
« Ответ #11 : Март 30, 2012, 14:20 »

Пользовался Улыбающийся Вообще в свое время я довольно долго держался за такое запись/чтение, хотя минусы перли из всех щелей. Просто конец всегда один - это придется вычистить. Поэтому если человек начинает - нет смысла ему это рекомендовать.

Ну я сейчас тоже перевожу свои тулзы на стримеры))
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #12 : Март 30, 2012, 14:31 »

Цитировать
За спиной мощного инструментария легко быть смелым 
Скорее спокойным за то, что в один прекрасный день, в самый ответственный момент не произойдёт грохинга программы) 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.197 секунд. Запросов: 23.