Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: [РЕШЕНО] Работа с функцией seek
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Ввод/Вывод, Сеть. Межпроцессное взаимодействие
AD
Необходимо установить указатель файла в конец файла. Как это сделать?
Для того, чтобы установить в начало файла есть функция reset(), а для окончания файла?

Cобcтвенно говоря, мне необходимо правильно перевести следующие строки кода на Qt:
int dwPtr = SetFilePointer(*WriteHandle, 0, NULL, FILE_END);
    int dwError;
    if (dwPtr == INVALID_SET_FILE_POINTER) // Test for failure
{
    // Obtain the error code.
    dwError = GetLastError();

    // Deal with failure.
    // . . .

} // End of error handler

    offset = 0;

WriteHandle - указатель на файл (библиотека карт), куда записывается информация из других файлов. ReadHandle - читаемый на данный файл (карта), откуда эту информацию считывают. Мне важно понять как правильно перевести на Qt-шный стиль строчку кода:
int dwPtr = SetFilePointer(*WriteHandle, 0, NULL, FILE_END);

Заранее спасибо.
DEADHUNT
Цитата(AD @ 25.2.2010, 23:15) *
Мне важно понять как правильно перевести на Qt-шный стиль строчку кода:
int dwPtr = SetFilePointer(*WriteHandle, 0, NULL, FILE_END);

Заранее спасибо.

зачем тебе Qt, если можно перевести чисто на C++:
istream &istream::seekg(streamoff off, ios_base::seekdir dir);
AD
Цитата(DEADHUNT @ 26.2.2010, 0:30) *
зачем тебе Qt, если можно перевести чисто на C++:
istream &istream::seekg(streamoff off, ios_base::seekdir dir);

Да я знаю, что можно и вообще чистыми Си-шными функциями обойтись. Нужен Qt, потому что все остальное работает на Qt-шных файлах.
Rocky
Цитата(AD @ 25.2.2010, 23:15) *
Для того, чтобы установить в начало файла есть функция reset(), а для окончания файла?

Ну если на конец, то можно закрыть его (если он был открыт) и открыть в режиме добавления...Тогда курсор железно в конце будет.
Зы. Я например все потоковые операции только через std::ios делаю... Во-первых просто потому что привык, во-вторых никаких потерь "кроссплатформенности"... Вот кстати еще интересно бы сравнить по скорости, кто быстрее.) Потоковые в смысле текстовых файлов.
SABROG
Только два варианта.

QFile file("myfile");
if (!file.open(QIODevice::Append) {
    qDebug() << file.errorString();
    return false;
}


QFile file("myfile");
if (!file.open(QIODevice::ReadWrite) {
    qDebug() << file.errorString();
    return false;
}
file.seek(file.size()); // Qt сама использует этот метод


Ставить отрицательные значения не рекомендую, если для windows это может переместить указатель в обратную сторону, то в реализации для *nix метод вернет ошибку, так как в отличае от виндовой версии там стоит проверка значения смещения.
AD
Цитата(SABROG @ 26.2.2010, 1:54) *
QFile file("myfile");
if (!file.open(QIODevice::ReadWrite) {
    qDebug() << file.errorString();
    return false;
}
file.seek(file.size()); // Qt сама использует этот метод

Такой вариант и сделал. Система попросту зависает (по рабоче-крестьянски, уходит в "глубокий ахтунг"). Фиг знает, почему!

Если делать по первому варианту, я смогу после открытия файла с флагом QIODevice::Append перемещаться по файлу, когда мне это понадобиться?
Litkevich Yuriy
Цитата(AD @ 26.2.2010, 13:17) *
Система попросту зависает (по рабоче-крестьянски, уходит в "глубокий ахтунг"). Фиг знает, почему!
а что возвращает функция size() для этого файла?
AD
Цитата(Litkevich Yuriy @ 26.2.2010, 10:45) *
а что возвращает функция size() для этого файла?

Cейчас обнаружил, что именно на ней и уходит куда-то далеко. Если пытаться через второй вариант, то то же самое при попытке закрыть файл. Не понимаю, как избавиться от этих глюков.
Litkevich Yuriy
AD, а сам файл каких размеров?
AD
Цитата(Litkevich Yuriy @ 26.2.2010, 13:11) *
AD, а сам файл каких размеров?

Litkevich Yuriy, я его ведь формирую как раз в этих строчках! :) Да разного размера он может быть.

Вопрос к тем, кто хорошо знаком с boost, у меня дескриптор файла библиотеки определен как
boost::shared_ptr<QFile> _writeHandle;
. В указанных функциях используется обычный указатель. Я его получаю с помощью следующего вызова:
<функция>(_writeHandle.get());
Из-за этого не могут быть проблемы с открытием, закрытие файла и перемещением по нему?
SABROG
Цитата(AD @ 26.2.2010, 13:27) *
я его ведь формирую как раз в этих строчках! :)


Тогда лучше тебя никто не знает где сейчас стоит указатель. По умолчанию после write() offset = curpos + datalength
AD
Цитата(SABROG @ 26.2.2010, 14:21) *
Тогда лучше тебя никто не знает где сейчас стоит указатель. По умолчанию после write() offset = curpos + datalength

Это я понимаю, я не понимаю, почему потом зависает... Сможете помочь?
SABROG
Цитата(AD @ 26.2.2010, 14:54) *
Сможете помочь?


При наличии материала с которым можно работать.

Цитата(AD @ 26.2.2010, 13:27) *
<функция>(_writeHandle.get());


Если функция твоя, то лучше используй boost::weak_ptr. Так ты сможешь проверять жив ли указатель, даже если boost::shared_ptr его уже грохнул.
AD
Цитата(SABROG @ 26.2.2010, 15:32) *
При наличии материала с которым можно работать.

Так.... Ну судя по всему мне стоит проверить идентичность моих переходов по файлу библиотеки.

Следующий код:
void T::SeekSet(unsigned int shift)
{
  SetFilePointer(*_writeHandle , -_offset + shift, NULL, FILE_CURRENT);
  DWORD dwPtr = SetFilePointer(*_writeHandle , 0, 0, FILE_CURRENT);
  _offset = shift;
}


был перевед в такой:
void T::SeekSet(unsigned int shift)
{
  bool seek = _writeHandle -> seek(-_offset + shift);
  if(seek) _offset = shift;
}

Т.е. код идентичен или же я напортачил где-то?
SABROG
Цитата(AD @ 26.2.2010, 15:45) *
unsigned int shift

В прошлой версии ты ограничился 32 битным смещением и соответственно максимальным размером файла в 4Гб. Может лучше qint64 поставить?

Цитата(AD @ 26.2.2010, 15:45) *
_writeHandle -> seek(-_offset + shift);


Предположим, что -offset = -20, а shift = 19, тогда смещение будет -1. Я выше писал, что отрицательные значения передавать нельзя.
AD
Цитата(SABROG @ 26.2.2010, 18:14) *
В прошлой версии ты ограничился 32 битным смещением и соответственно максимальным размером файла в 4Гб. Может лучше qint64 поставить?

В какой именно, прости?

Цитата(SABROG @ 26.2.2010, 18:14) *
Предположим, что -offset = -20, а shift = 19, тогда смещение будет -1. Я выше писал, что отрицательные значения передавать нельзя.

Как сделать правильно? Передавать модуль разности?
SABROG
Цитата(AD @ 26.2.2010, 18:30) *
В какой именно, прости?

Цитата(AD @ 26.2.2010, 15:45) *
void T::SeekSet(unsigned int shift)


Цитата(AD @ 26.2.2010, 18:30) *
Как сделать правильно? Передавать модуль разности?


Я не знаю логику твоей программы. Что содержится в offset, текущее положение курсора в файле? Что в shift, смещение на которое нужно сдвинуться от текущей позиции? Почему offset всегда передается отрицательным?

Цитата(AD @ 26.2.2010, 15:45) *
SetFilePointer(*_writeHandle , -_offset + shift, NULL, FILE_CURRENT);
DWORD dwPtr = SetFilePointer(*_writeHandle , 0, 0, FILE_CURRENT);


Две идентичные функции, а для одного и того же аргумента значение передается в разном стиле 0 и NULL. Это ты никак со стилем программирования определиться не можешь? ;)
AD
Цитата(SABROG @ 26.2.2010, 21:40) *
Я не знаю логику твоей программы. Что содержится в offset, текущее положение курсора в файле? Что в shift, смещение на которое нужно сдвинуться от текущей позиции? Почему offset всегда передается отрицательным?

Две идентичные функции, а для одного и того же аргумента значение передается в разном стиле 0 и NULL. Это ты никак со стилем программирования определиться не можешь? ;)

Нет, конечно. В старой программке сделано через функции винды. Теперь необходимо сделать в Qt-шном варианте. Я то уже определился со стилем. Первое - это старый вариант, второе - новый!
DEADHUNT
Цитата(AD @ 26.2.2010, 23:11) *
второе - новый!

это почему? вообще лучше nullptr использовать из C++0x.
AD
Цитата(DEADHUNT @ 26.2.2010, 23:16) *
это почему? вообще лучше nullptr использовать из C++0x.

Что именно почему?
Нельзя, потому что компилятор старый, стандарт еще не введен в законнное действие, а у нас авиация - самая консервативная область! ;)
SABROG
Цитата(DEADHUNT @ 26.2.2010, 23:16) *
это почему? вообще лучше nullptr использовать из C++0x.

Пока сама Microsoft ожидает увидеть тип NULL лучше давать ей то чего она хочет. Никто ведь не знает будет nullptr равен NULL или нет. А вот в своем коде лучше использовать 0 или умный указатель, который можно проверить на валидность вместо того, чтобы сравнивать с нулём.

Цитата(AD @ 26.2.2010, 23:11) *
Нет, конечно. В старой программке сделано через функции винды. Теперь необходимо сделать в Qt-шном варианте. Я то уже определился со стилем. Первое - это старый вариант, второе - новый!


Я ответа на свой вопрос так и не увидел. Попробуй что ли добавить qDebug(), пусть выводит смещения которые получаются.
AD
offset - текущее положение в файле, shift - сдвиг. Почему отрицательное - не могу сказать достоверно, код чужой переписываю. Некоторые вещи только догадываться могу. Будем считать, что априори это так и надо.
SABROG
Цитата(AD @ 27.2.2010, 0:47) *
Будем считать, что априори это так и надо.


Отрицательное значение для Windows функции это перемещение в обратную сторону. Как это связано с вопросом перемещением указателя в конец файла я не понял. Разница между QIODevice::seek() и SetFilePointer в том, что первый берет абсолютное смещение в файле, а второй берет относительное смещение от текущей позиции. Конец файла для seek() это seek(size()), а для SetFilePointer это offset+(currentFileSize-offset):
Пример. Размер файла 10 байт. Текущая позиция 5.
currentFileSize = 10
offset = 5
Переменная которая передается в SetFilePointer = 5+(10-5) // 10
...
0+(10-0) = 10
10+(10-10) = 10

Теперь нам надо реализовать тот же функционал перемещения указателя в любую сторону исходя из текущего положения указателя (offset) и переданного смещения (shift). Возьмем всё тот же пример, 5 текущая позиция, 10 размер файла.
-5+0 = -5 перемещаемся на 5 байт назад
-5+1 = -4 на 4 байта назад
-5+2 = -3
-5+3 = -2
-5+4 = -1
-5+5 = 0 стоим на месте
-5+6 = 1 вперед на 1 байт
(хрен знает что за логика такая, то туда то сюда)
qint64 _offset = _writeHandle->pos();
...
SeekSet(shift);
...
void T::SeekSet(unsigned int shift)
{
_offset += -_offset + shift;
_writeHandle->seek(_offset);
}
AD
У меня просьба к модераторам переименовать тему в "Уточнение работы функции seek"! Заранее спасибо.

SABROG, отдельное спасибо. Теперь никаких заеданий нет. СПАСИБО.

Так... ну я разобрался зачем эти перемещения делаются. Я не могу раскрывать все моменты этого кода, но смысл этих перемещений могу сказать. Дело вот в чем. В файл библиотеки записывается вначале содержимое карты, а потом идет перемещение к заголовку библиотеки и записывается заголовок карты.
AD
У меня, возможно еще будут вопросы по seek, относящиеся к этой теме. Пожалуйста, переименуйте! Заранее спасибо!
Litkevich Yuriy
Цитата(AD @ 28.2.2010, 16:50) *
Пожалуйста, переименуйте!
Автор темы может переименовать тему, в режиме редактирования (не "быстрого") первого сообщения темы
AD
Кто-нибудь сможет еще слегка подсказать? Есть ошибки в приведенном коде?
AD
Во блин... Случайно вчерашнее сообщение удалил. Как раз нужное....


Зависаний при чтении/записи больше нет. Но запись в связи с отличной работой функции seek от функции SetFilePointer имеется. Буду уточнять.

Итак в старом варианте следующий код:

// Место вызова функций сдвига для записи в заголовок нужной информации
SeekSet();          /// параметр shift по умолчанию равен 0. Сдвиг на начало записи заголовка карты в библиотеку
Head.Write_();
// какие-то еще действия
SeekEnd();


// Функции сдвигов
void T::SeekSet( unsigned int shift )
{
    SetFilePointer(*WriteHandle, -offset + shift, NULL, FILE_CURRENT);
    DWORD dwPtr = SetFilePointer(*WriteHandle, 0, 0, FILE_CURRENT);
    offset = shift;
};

void T::SeekEnd()
{
    
    int dwPtr = SetFilePointer(*WriteHandle, 0, NULL, FILE_END);
    int dwError;
    if (dwPtr == INVALID_SET_FILE_POINTER) // Test for failure
{
    // Obtain the error code.
    dwError = GetLastError();

    // Deal with failure.
    // . . .

} // End of error handler

    offset = 0;
}


В новом варианте:
// Место вызова функций сдвига для записи в заголовок нужной информации
SeekBegChart(startOffset); // аналогично SeekSet(). Сделал название функции близкое к ее применению
_head.Write_();
// какие-то еще действия
SeekEnd();

/// Перемещение в начало описание карты
void T::SeekBegChart(unsigned int shift)
{
    _offset = shift;
    bool seek = _writeHandle -> seek(_offset);
}

/// Перемещение в конец файла
void T::SeekEnd()
{
    _offset = _writeHandle -> size();
    bool seek = _writeHandle -> seek(_writeHandle -> size());
}


Что в коде не идентично. В чем несоответствие и соответственно ошибка? Заранее спасибо, если кто-то сможет помочь!
SABROG
Если брать winapi код:

-offset + shift


И то как я сделал:

_offset += -_offset + shift;


То разница есть. shift не должен быть нулевым. Если для SetFilePointer это имеет смысл, т.е. оставляет текущий курсор на прежнем месте, то для seek() при моем варианте итоговое значение будет некорректным. Я не знаю бывают ли такие ситуации, когда у вас SetFilePointer вызывается с нулевым смещением, что мне кажется пустой тратой времени CPU. Если такой факт имеет место быть, то код нужно допиливать.
AD

В том то и дело, что если shift равно нулю, то тогда
-_offset + shift = -_offset - а значит идет смещение назад (в данном случае к заголовку).

И посмотрите, пожалуйста, приведенный код, он как раз допиленный, согласно всем объяснениям. startOffset - не равно 0!
SABROG
Цитата(AD @ 1.3.2010, 15:52) *
И посмотрите, пожалуйста, приведенный код, он как раз допиленный, согласно всем объяснениям. startOffset - не равно 0!


Сделайте 2 функции, старый вариант и новый вариант. Вызовите по очереди и в методах где идет seek() помещайте в лист QList<QPair<uint, uint> > offset. В first можно поместить WINAPI вариант, в second Qt. Потом всё это вывести в файл или на экран и посмотреть где идет разница.
AD
Цитата(SABROG @ 1.3.2010, 16:16) *
Сделайте 2 функции, старый вариант и новый вариант. Вызовите по очереди и в методах где идет seek() помещайте в лист QList<QPair<uint, uint> > offset. В first можно поместить WINAPI вариант, в second Qt. Потом всё это вывести в файл или на экран и посмотреть где идет разница.

Мда.... Это разные две программы.... Ладно... что-нибудь постараюсь придумать!
BRE
Как я понял, кто-то хотел реализовать (через одно место) установку позиции файла относительно его начала?
/* Почему для этого не воспользоваться SetFilePointer с установкой флага FILE_BEGIN не понятно. Ну да ладно. */

Как мне кажется этот код:
void T::SeekSet( unsigned int shift )
{
    SetFilePointer(*WriteHandle, -offset + shift, NULL, FILE_CURRENT);
    DWORD dwPtr = SetFilePointer(*WriteHandle, 0, 0, FILE_CURRENT);
    offset = shift;
};


эквивалентен этому:
void T::SeekBegChart(unsigned int shift)
{
    _offset = shift;
    bool seek = _writeHandle -> seek(_offset);
}


И возможно дело не в этой функции.

/* Все таки первая функция это шедевр. Сколько дней на нее смотрю... */

P.S. Кстати, для чего сохранять _offset, если его всегда можно получить через QFile::pos()?

UP:
Это:
DWORD dwPtr = SetFilePointer(*WriteHandle, 0, 0, FILE_CURRENT);
попытка получить текущую позицию? А где используется dwPtr?
AD
Цитата(BRE @ 1.3.2010, 17:42) *
Как я понял, кто-то хотел реализовать (через одно место) установку позиции файла относительно его начала?

Нет. Не совсем так. Помещать следует не в начало файла, в позицию заданную с помощью _offset. В первом варианте - shift = 0, а вот во втором нет. Но вот _offset далеко не нулевое значение. Смысл такой. Есть файл, который хранит что в виде заголовка в начале, а потом идет содержимое других файлов. Так вот заголовки этих других файлов тоже следует писать уже после записи остальных данных - потому что после записи мы знаем смещение этих файлов относительно начало, crc-сумму и прочее....

Цитата(BRE @ 1.3.2010, 17:42) *
UP:
Это:
DWORD dwPtr = SetFilePointer(*WriteHandle, 0, 0, FILE_CURRENT);
попытка получить текущую позицию? А где используется dwPtr?

Да это строка была для проверки. Забыли удалить, судя по всему.

Собственно говоря, можно этот процесс сравнить с процессом написания оглавления в Word. Только представим себе, что оглавление делается не только ко всему документу (заголовку библиотеки), но и к каким отдельным главам (считываемым файлам, содержимое которых записывается в библиотеку). Т.е. вначале делается само содержание этих глав, а потом возвращаемся к странице (месту в файле) где необходимо сделать оглавление и создаем его (Word это умеет делать).
BRE
Мне сложно по одной этой функции судить, что хотели сделать разработчики. Возможно, _offset изменяется где то еще, а не только в этой функции???
Но, если нигде больше это значение не изменяется, то эта функция просто перемещает указатель файла на позицию относительно его начала.
AD
Изменяется. Сейчас делаю лог-файл для записи всех нужных данных. Буду смотреть. Если что сюда еще спрошу....
AD
Ну тему можно закрывать. Последние изменения, которые были указаны в этой теме помогли. Проблема решена. Дальше мне просто нужно было правильно заполнять поле смещений в каждой карте.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2022 IPS, Inc.