Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Pixel от Сентябрь 12, 2012, 14:02



Название: Обращение к данным по индексу
Отправлено: Pixel от Сентябрь 12, 2012, 14:02
Прочитал статью, про работу с данными в Qt и возник вопрос. Можно ли обращаться к конкретным данным, не читая при этом весь кусок файла, идущий перед нужными данными. Как я понял это работа с базами данных, но вразумительной статьи про них я не нашел. Подскажите, если не сложно, простенький способ обратиться к нужному куску данных или статейку про работе с БД для новичков.


Название: Re: Обращение к данным по индексу
Отправлено: mutineer от Сентябрь 12, 2012, 14:05
Про какие данные ты говоришь? Где они лежат? Если ты про чтение из файла, то есть метод seek()


Название: Re: Обращение к данным по индексу
Отправлено: Pixel от Сентябрь 12, 2012, 14:17
двоичные данные. Пример: есть структура с данными. Нужно сохранить много таких структур и записать в файл. Далее нужно будет обращаться к конкретной структуре, зная ее индекс или адрес или что угодно, что позволило бы обратиться к этой структуре, не считывая предыдущие.


Название: Re: Обращение к данным по индексу
Отправлено: mutineer от Сентябрь 12, 2012, 14:23
seek тебе в помощь


Название: Re: Обращение к данным по индексу
Отправлено: Pixel от Сентябрь 12, 2012, 14:29
Можно по подробней? чей это метод? QDataStream? QFile? Другой?
как его использовать? Нашел такой метод в QFile. Ну вот допустим я узнал, что по индексу 3 есть запись. Как мне теперь обратиться к структуре под номером 3?


Название: Re: Обращение к данным по индексу
Отправлено: Serr500 от Сентябрь 12, 2012, 14:34
Сначала QFile::seek. Если вернуло true, то QFile::read.

P.S. RTFM!


Название: Re: Обращение к данным по индексу
Отправлено: mutineer от Сентябрь 12, 2012, 14:41
Можно по подробней? чей это метод? QDataStream? QFile? Другой?
как его использовать? Нашел такой метод в QFile. Ну вот допустим я узнал, что по индексу 3 есть запись. Как мне теперь обратиться к структуре под номером 3?

Методом seek пропустить первые две структуры (2 * размер структуры в байтах) и вычитать третью


Название: Re: Обращение к данным по индексу
Отправлено: Serr500 от Сентябрь 12, 2012, 14:48
mutineer
А щас он захреначит в файл class через QFile::write(this, sizeof(*this)) вместе с VMT и будет удивляться, почему оно падает.  ;)


Название: Re: Обращение к данным по индексу
Отправлено: Pixel от Сентябрь 12, 2012, 15:09
Честно говоря, я пока вообще не могу понять как и что можно записывать. Во всех примерах, что я читаю работают только с дата стримом, и ничего кроме этого:
struct str
{
    QString name;
};

...

QFile file("base.txt");
file.open(QIODevice::WriteOnly);
str dat;
dat.name="name";
QDataStream in(&file);
in<<dat.name;

у меня сделать не получается.
Метод Write я вообще не понял как работает.
Из документации:
write ( const char * data, qint64 maxSize )
второй аргумент это размер первого, а вот что в первом указывать я не понял. Структуру нельзя, данные структуры нельзя. Как что то туда записать?


Название: Re: Обращение к данным по индексу
Отправлено: Bepec от Сентябрь 12, 2012, 15:30
Смотрим. Есть метод write ( const QByteArray & ) допустим.

Значит нам что надо сделать ? Правильно - запихать в QByteArray структуру, записать эту структуру. На обратной стороне (ты знаешь размер структуры) считать данные из QByteArray в том же порядке.

С QDataStream в принципе так же.

PS % на 70 уверен что это сработает. Ибо в последний раз сериализовал через Qt очень давно :D


Название: Re: Обращение к данным по индексу
Отправлено: Serr500 от Сентябрь 12, 2012, 15:33
С QDataStream в принципе так же.
Ему ещё позиционирование нужно и, скорее всего, нелинейное (вперёд-назад). А QDataStream позиционирование не поддерживает (только вперёд). Поэтому придётся брать QFile.


Название: Re: Обращение к данным по индексу
Отправлено: xokc от Сентябрь 12, 2012, 15:43
Давай сюда описание своей структуры. Запишем её в файл.


Название: Re: Обращение к данным по индексу
Отправлено: Igors от Сентябрь 12, 2012, 15:55
А щас он захреначит в файл class через QFile::write(this, sizeof(*this)) вместе с VMT и будет удивляться, почему оно падает.  ;)
Так это неизбежный этап познания  :)

Метод Write я вообще не понял как работает.
Из документации:
write ( const char * data, qint64 maxSize )
второй аргумент это размер первого, а вот что в первом указывать я не понял. Структуру нельзя, данные структуры нельзя. Как что то туда записать?
Этот метод предназначен для сохранения низкоуровневых данных, когда сохраненный на диске образ совпадает (байт в байт) с представлением объекта в памяти. Для чуть более сложного объекта (ну хоть QString) такое read/write не проходит, записанные данные не удается прочитать.

Я предлагаю такое решение: пишете через QDataStream, используя удобные операторы  <<. По ходу дела запоминаете позицию и размер записи напр так
Код
C++ (Qt)
... // открыли файл для записи
QDataStream strm(&theFile);
qint64 theDataStart = -1, theDataSize = -1;
...
theDataStart = strm.device()->pos();  // запомнили позицию первой записи
strm << theData;           // цивильно записали
theDataSize = strm.device()->pos() - theDataStart;  // запомнили размер записи на диске
 
Теперь читаем nth запись
Код
C++ (Qt)
void ReadRecNo( QDataStream & strm, int recNo, MyData & theData )
{
strm.device()->seek(theDataStart + theDataSize * recNo);
strm >> theData;          
}
 

Edit: ну разумеется это предполагает что все записи одного размера. Если это не так то надо создавать массив/контейнер theDataStart


Название: Re: Обращение к данным по индексу
Отправлено: Pixel от Сентябрь 12, 2012, 16:06
Всем спасибо! вроде как получилось. Вот:
    QFile file("base.txt");
    file.open(QIODevice::WriteOnly);

    str dat, dat2;
    dat.name="name";

    QByteArray arr;
    arr.resize(sizeof(dat));

    memmove(arr.data(), &dat, sizeof(dat));

    file.write(arr, sizeof(dat));

    file.close();
    arr.clear();

    file.open(QIODevice::ReadOnly);

    if (file.seek(0))
    {
        arr=file.read(sizeof(dat));
        memmove(&dat2, arr.data(), sizeof(dat));
    }

    qDebug()<<dat2.name;

Как то так. Выводит: "name". Посмотрите, такой способ корректен, ничего не напутал не намудрил?)


Название: Re: Обращение к данным по индексу
Отправлено: Igors от Сентябрь 12, 2012, 16:11
Как то так. Выводит: "name". Посмотрите, такой способ корректен, ничего не напутал не намудрил?)
Mда, видимо в естественный процесс эволюции лучше не вмешиваться  :)

Пользуйтесь тегом для обрамления кода


Название: Re: Обращение к данным по индексу
Отправлено: Пантер от Сентябрь 12, 2012, 16:14
Пациент скорее мёртв, чем жив....


Название: Re: Обращение к данным по индексу
Отправлено: xokc от Сентябрь 12, 2012, 16:16
Посмотрите, такой способ корректен, ничего не напутал не намудрил?)
Намудрил так, что даже странно, что не попутал.
Код
C++ (Qt)
struct str
{
   QString name;
};
 
inline QDataStream &operator <<(QDataStream &steam, const str &data)
{
   stream << data.name;
   return stream;
}
 
inline QDataStream &operator >>(QDataStream &steam, str &data)
{
   stream >> data.name;
   return stream;
}
 

Запись в файл:
Код
C++ (Qt)
str data;
data.name = "aaaaa";
...
QDataStream strm(&theFile);
strm << data;  
 

Чтение из файла:
Код
C++ (Qt)
str data;
QDataStream strm(&theFile);
strm >> data;
 


Название: Re: Обращение к данным по индексу
Отправлено: Serr500 от Сентябрь 12, 2012, 20:24
Е... мой старый ... !!!
Код:
str dat;
QByteArray arr;
file.write(arr, sizeof(dat));
Это даже хуже, чем я предполагал.  :-[


Название: Re: Обращение к данным по индексу
Отправлено: Pixel от Сентябрь 12, 2012, 20:43
xokc, это я все знаю, стандартная запись через поток. А как мне считать структуру из середины не прочесывая предыдущие?
Serr500, вы пишите намеками. Я только начал изучать Qt, я их не понимаю. Сложно что ли написать пример как сделал это господин xokc, только по сабжу? Если лень, то дайте хотя бы ссылку на статью, только на ту, которая мне объяснит мою проблему, а не просто "работа с данными на Qt". Таких я уже прочитал уйму, но ни в одной не решается моя проблема, иначе я бы сюда не обращался.


Название: Re: Обращение к данным по индексу
Отправлено: Serr500 от Сентябрь 12, 2012, 20:51
Serr500, вы пишите намеками. Я только начал изучать Qt, я их не понимаю.
Вы не понимаете не Qt, а основы языка C++.

Сложно что ли написать пример как сделал это господин xokc, только по сабжу?
А зачем? Господин xokc уже всё написал.

xokc, это я все знаю, стандартная запись через поток. А как мне считать структуру из середины не прочесывая предыдущие?
У Вас вдобавок к незнанию Qt и C++ ещё и невнимательность:
Я предлагаю такое решение: пишете через QDataStream, используя удобные операторы  <<. По ходу дела запоминаете позицию и размер записи напр так
Код:
... // открыли файл для записи
QDataStream strm(&theFile);
qint64 theDataStart = -1, theDataSize = -1;
...
theDataStart = strm.device()->pos();  // запомнили позицию первой записи
strm << theData;           // цивильно записали
theDataSize = strm.device()->pos() - theDataStart;  // запомнили размер записи на диске
Теперь читаем nth запись
Код:
void ReadRecNo( QDataStream & strm, int recNo, MyData & theData )
{
 strm.device()->seek(theDataStart + theDataSize * recNo);
 strm >> theData;           
}

Edit: ну разумеется это предполагает что все записи одного размера. Если это не так то надо создавать массив/контейнер theDataStart
Объедините то, что написали xokc и Igors и задача будет решена.


Название: Re: Обращение к данным по индексу
Отправлено: V1KT0P от Сентябрь 12, 2012, 20:53
xokc, это я все знаю, стандартная запись через поток. А как мне считать структуру из середины не прочесывая предыдущие?
Serr500, вы пишите намеками. Я только начал изучать Qt, я их не понимаю. Сложно что ли написать пример как сделал это господин xokc, только по сабжу? Если лень, то дайте хотя бы ссылку на статью, только на ту, которая мне объяснит мою проблему, а не просто "работа с данными на Qt". Таких я уже прочитал уйму, но ни в одной не решается моя проблема, иначе я бы сюда не обращался.
Все зависит от условий задачи.
Например если у нас структура фиксированного размера и необходимо один раз записать и потом считывать, то для доступа к структуре перемещаемся в файле в позицию РАЗМЕР_СТРУКТУРЫ * НОМЕР_СТРУКТУРЫ.
Если структуры не фиксированного размера, но опять-же нам надо один раз записать и потом считывать, то заводим два файла, в первый тупо по порядку складываем структуры, а во второй смещение каждой структуры. В результате для доступа к структуре переходим во втором файле в позицию НОМЕР_СТРУКТУРЫ * РАЗМЕР_СМЕЩЕНИЯ_СТРУКТУРЫ и читаем оттуда переменную СМЕЩЕНИЕ_СТРУКТУРЫ размером РАЗМЕР_СМЕЩЕНИЯ_СТРУКТУРЫ. Далее переходим в первом файле в позицию СМЕЩЕНИЕ_СТРУКТУРЫ и считываем структуру.
Если же надо еще и добавлять/удалять/изменять то лучше ищи готовую библиотеку, ибо ты для более сложных вещей еще не готов.


Название: Re: Обращение к данным по индексу
Отправлено: Serr500 от Сентябрь 12, 2012, 20:57
Pixel, вот вам задачка на знание языка C++ (не Qt!):
Код:
struct Struct 
{
    char* str;
} S;
S.str = "bla-bla-bla";

QFile File("file.out");
File.open(QIODevice::ReadWrite);
File.write(&S, sizeof(S));
Что будет в файле?


Название: Re: Обращение к данным по индексу
Отправлено: Igors от Сентябрь 12, 2012, 22:45
Если структуры не фиксированного размера, но опять-же нам надо один раз записать и потом считывать, то заводим два файла, в первый тупо по порядку складываем структуры, а во второй смещение каждой структуры. В результате для доступа к структуре переходим во втором файле в позицию НОМЕР_СТРУКТУРЫ * РАЗМЕР_СМЕЩЕНИЯ_СТРУКТУРЫ и читаем оттуда переменную СМЕЩЕНИЕ_СТРУКТУРЫ размером РАЗМЕР_СМЕЩЕНИЯ_СТРУКТУРЫ. Далее переходим в первом файле в позицию СМЕЩЕНИЕ_СТРУКТУРЫ и считываем структуру.
Что-то уж очень тупо таскать/сбивать 2 файла :) Лучше все в одном с TOC как напр это было в wad файлах

Если же надо еще и добавлять/удалять/изменять то лучше ищи готовую библиотеку, ибо ты для более сложных вещей еще не готов.
Ну не надо "надувать щеки", там ничего сложного  :)


Название: Re: Обращение к данным по индексу
Отправлено: V1KT0P от Сентябрь 12, 2012, 23:15
Что-то уж очень тупо таскать/сбивать 2 файла :) Лучше все в одном с TOC как напр это было в wad файлах

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


Название: Re: Обращение к данным по индексу
Отправлено: xokc от Сентябрь 13, 2012, 08:52
xokc, это я все знаю, стандартная запись через поток. А как мне считать структуру из середины не прочесывая предыдущие?
Если Вы собираетесь записывать в файл структуры разных размеров (а я надеюсь, что Вы понимаете, что размеры данных, находящихся в тех структурах, которые Вы нам показали будут разными в зависимости от длинны строки), то простого решения для обеспечения прямого доступа к данным в файле не получится.
Если нужно использовать только один файл и нельзя использовать готовые решения, то я бы делал в начале файла область для индексов, где указывал бы откуда надо читать данные. Но это уже совсем другая задача. Никто за Вас тут её решать не будет.