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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Вопрос про QFile::write()  (Прочитано 9298 раз)
alex12
Гость
« : Апрель 15, 2009, 21:43 »

Всем привет!

Меня давно мучает вопрос:

Делаю запись в файл. Должен ли я ВСЕГДА делать вот так:
Код:
while( len )  {
  a = file.write( ptr, len );
  if( a < 0 ) break;
  ptr += a;
  len -= a;
}

или можно не заморачиваться:

Код:
file.write( ptr, len );

и забить на проверку количества реально записанных байт? В реальной жизни никогда не видел ошибок, если, конечно, не писать по 1GB за раз. Есть ли практический смысл в постоянной проверке реально записанных байт?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #1 : Апрель 15, 2009, 21:54 »

А если место на диске закончилось?
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #2 : Апрель 15, 2009, 22:04 »

а зачем цикл?
Пытайся записать всё, проверь, если неполучилось, скажи об этом пользователю.
Записан

Юра.
whirlwind
Гость
« Ответ #3 : Апрель 15, 2009, 22:05 »

не уверен, но по-моему, в linux'е запросто можно удалить файл, пока вы в него пишете.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #4 : Апрель 15, 2009, 22:08 »

и забить на проверку количества реально записанных байт?

Забивать на проверку нестоит
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #5 : Апрель 15, 2009, 22:21 »

не уверен, но по-моему, в linux'е запросто можно удалить файл, пока вы в него пишете.
Файл не будет удален, пока не закроется последний дескриптор. Т.е. писать в него можно будет, но при close() он исчезнет.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
alex12
Гость
« Ответ #6 : Апрель 15, 2009, 22:57 »

По-моему тут возможны несколько вариантов:

  • а) Файловая система всегда блокирует write до тех пор, пока все данные не уйдут на диск (в буфер ОС). Количество реально записанных байт всегда будет совпадать с требуемым.
  • б) Если файловая система сильно загружена, то она примет сколько сможет и возвратит количество байт меньше требуемого. Причем это не будет считаться ошибкой! Программист сам должен отслеживать такую ситуацию.
  • в) Произошла ошибка ФС (например, закончилось место) и вызов завершается с -1.

Случай в) не рассматриваем ибо тут все понятно. Вопрос в том, как себя ведет QFile? По вариану а) или б)? Вот, например, QTcpSocket ведет себя по сценарию б). Если нужно отправить много данных, то нужно обязательно следить сколько байт ушло в линию.

С сделал простенький тест. Записываю оооочень большой файл блоками разной длины и в случае чего вывожу на консоль.
Так вот, практика показывает, что я не смог получить ни разу ситуации б). Всегда все работает по а). Система WinXP MinGW Qt 4.5.0.

Есть ли теоретическое обоснование этого факта? Как обстоят дела на других платформах?

Код:
#include <QtCore>

#define BLOCK     10*1024*1024
#define TOTAL   1024*1024*1024

int main(int argc, char *argv[])
{
  int i,a;
  QByteArray ba;
  ba.resize( BLOCK );
 
  QFile file("out.dat"); 
  file.open( QIODevice::WriteOnly | QIODevice::Truncate );
 
  for( i=0; i<((TOTAL)/(BLOCK)); i++ )  {
    a = file.write( ba );
    if( a != BLOCK ) qDebug() << a;
  }

  return 0;
}
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #7 : Апрель 15, 2009, 23:01 »

На сколько я знаю, варианта Б не может быть как такового - или записано все, или ничего.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alex Custov
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2063


Просмотр профиля
« Ответ #8 : Апрель 16, 2009, 01:55 »

+

http://www.linux.org.ru/view-message.jsp?msgid=3591104&lastmod=1238980775134
Записан
mugabe
Гость
« Ответ #9 : Апрель 16, 2009, 04:29 »

qfsfileengine_win.cpp:
Код
C++ (Qt)
qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
{
   Q_Q(QFSFileEngine);
 
   if (fh || fd != -1) {
       // stdio / stdlib mode.
       return writeFdFh(data, len);
   }
 
   // Windows native mode.
   if (fileHandle == INVALID_HANDLE_VALUE)
       return -1;
 
   qint64 bytesToWrite = DWORD(len); // <- lossy
 
   // Writing on Windows fails with ERROR_NO_SYSTEM_RESOURCES when
   // the chunks are too large, so we limit the block size to 32MB.
   static const DWORD maxBlockSize = 32 * 1024 * 1024;
 
   qint64 totalWritten = 0;
   do {
       DWORD blockSize = qMin<DWORD>(bytesToWrite, maxBlockSize);
       DWORD bytesWritten;
       if (!WriteFile(fileHandle, data + totalWritten, blockSize, &bytesWritten, NULL)) {
           if (totalWritten == 0) {
               // Note: Only return error if the first WriteFile failed.
               q->setError(QFile::WriteError, qt_error_string());
               return -1;
           }
           break;
       }
       if (bytesWritten == 0)
           break;
       totalWritten += bytesWritten;
       bytesToWrite -= bytesWritten;
   } while (totalWritten < len);
   return qint64(totalWritten);
}
 


qfsfileengine.cpp:
Код
C++ (Qt)
qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
{
   Q_Q(QFSFileEngine);
   qint64 result;
   qint64 written = 0;
 
   do {
       // Write blocks of 4k to avoid platform limitations (Windows commonly
       // bails out if you read or write too large blocks at once).
       qint64 bytesToWrite = qMin<qint64>(4096, len - written);
       if (fh) {
           do {
               // Buffered stdlib mode.
               result = qint64(fwrite(data + written, 1, size_t(bytesToWrite), fh));
           } while (result == 0 && errno == EINTR);
           if (bytesToWrite > 0 && result == 0)
               result = -1;
       } else {
           do {
               // Unbuffered stdio mode.
               result = QT_WRITE(fd, data + written, bytesToWrite);
           } while (result == -1 && errno == EINTR);
       }
       if (result > 0)
           written += qint64(result);
   } while (written < len && result > 0);
 
   // If we read anything, return that with success. Otherwise, set an error,
   // and return the last return value.
   if (result > 0)
       return written;
   q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, qt_error_string(errno));
   return result;
}
 

делать первым способом не только не обязательно, но и вредно.
если, конечно, не собираетесь отслеживать процесс записи в файл.
Записан
alex12
Гость
« Ответ #10 : Апрель 16, 2009, 11:07 »

qfsfileengine_win.cpp:
Код
C++ (Qt)
qint64 QFSFileEnginePrivate::nativeWrite(const char *data, qint64 len)
...
 
qfsfileengine.cpp:
Код
C++ (Qt)
qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
...
 
...
делать первым способом не только не обязательно, но и вредно.
если, конечно, не собираетесь отслеживать процесс записи в файл.

Спасибо. Теперь все понятно. QFile гарантирует запись всех данных и сам делает циклическую запись. Жаль, что этого нигде не написано явно в документации. Или я просто не нашел...
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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