2016-09-14 2 views
2

Я разрабатываю приложение, которое необходимо скопировать много файлов из одной папки в другую, используя QT (5.6.1)QT - QFile операция копирования очень медленно

Для делать это, я был используя метод QFile::copy(). Это хорошо работает, за исключением одного: это чрезвычайно медленно. Выполняется более чем в два раза больше времени, чем одна операция копирования выполняется с помощью обозревателя Windows.

Удивление, почему это было, я вырыл в исходный код QT, и я нашел это в qfile.cpp, который выглядит уместным:

char block[4096]; 
qint64 totalRead = 0; 
while(!atEnd()) { 
    qint64 in = read(block, sizeof(block)); 
    if (in <= 0) 
     break; 
    totalRead += in; 
    if(in != out.write(block, in)) { 
     close(); 
     d->setError(QFile::CopyError, tr("Failure to write block")); 
     error = true; 
     break; 
    } 
} 

Таким образом, от того, что я понимаю, операция копирования с помощью 4096- байтовый буфер. Это очень мало для операции копирования и вполне может быть причиной проблемы. Так что я сделал изменить размер буфера:

char block[4194304]; // 4MB buffer 

Затем я восстановил всю библиотеку QT, чтобы включить эти изменения. Однако вся модификация полностью нарушила метод. Теперь, когда мое приложение пытается вызвать QFile :: Copy(), операция прерывается немедленно (метод даже не запускается, останавливается перед первой строкой в ​​соответствии с отладчиком QtCreator). Отладчик говорит мне:

The inferior stopped because it received a signal from the Operating System. 

Signal name : 
SIGSEGV 
Signal meaning : 
Segmentation fault 

Мой C++ немного ржавый, но я не понимаю, как просто изменить размер выделения массива может полностью нарушить способ ... кто может помочь либо:

1) Расскажите, почему QFile: Copy() настолько медленный (я что-то упускаю? Это не только на моем ПК, протестированном на нескольких разных машинах). И действительно ли коллаптик - это код, который я написал выше или что-то еще? 2) Расскажите, почему это одно изменение полностью ломается QFile

+1

В qtbase есть тесты ('тесты/тесты/corelib/io/qfile'), который пытается прочитать файл на Win32 с использованием разных размеров блоков. Я не уверен, почему 4K был универсально выбран. Возможно, это зависит от технологии жесткого диска? Не могли бы вы попробовать запустить тестовый тест ('readBigFile_Win32') и проверить? – peppe

+1

В Windows лучше всего использовать CopyFileEx, см. [Этот полный пример] (http://stackoverflow.com/q/19136936/1329652) с индикатором прогресса :) –

ответ

1

Ну, изменение размера буфера не принесло пользы, так как это, по-видимому, является просто резервным в случае, если производная функция engine()->copy() терпит неудачу. Я не знаю точно, как работает эта функция, и я не хочу тратить время на изменение основных классов ядра QT, чтобы сделать эту работу.

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

QFile::copy(src, dest); 

с:

CopyFileExW((LPCWSTR)src.utf16(), (LPCWSTR)dest.utf16(), 0, this, 0, 0); 

Обратите внимание, что вы должны #include "windows.h" для этого вызова на работу.

+1

Посмотрите также на мой ответ. Похоже, что с более новыми версиями 'Qt' framework' QFile :: copy() 'выполняется так же быстро, как и исходная реализация. –

+0

Спасибо за обновление! –

4

Причина, по которой ваше изменение нарушилось QFile, заключается в том, что буфер 4M не будет помещаться в стек (размер стека по умолчанию обычно составляет примерно 1M). Быстрое исправление будет:

std::vector<char> vec(4*1024*1024); 
char *block = &vec.front(); 

Вектор выделит большой буфер в куче (и заботиться о deallocating, когда вы сделали), и вы просто указать block в передней части вектора.

Я думаю, что ваш анализ того, почему копия медленная, находится на месте.

+0

Спасибо, я подумал об этом, но я сделал Не думаю, что стек был настолько маленьким, что он попытается, как только восстанавливается источник QT. Может занять некоторое время :) По причине: это МОЖЕТ быть, но я также заметил, что этот код работает только в том случае, если «d-> engine() -> copy (newName)» терпит неудачу. Нужно также проверить это. –

1

Это, похоже, больше не проблема с более новой версией Qt (я использую 5.9.2).Пожалуйста, посмотрите на QFileSystemEngine::copyFile() в https://code.woboq.org/qt5/qtbase/src/corelib/io/qfilesystemengine_win.cpp.html Код использует встроенную функцию CopyFile2. Также мое тестирование подтвердило, что QFile::copy() находится на одном уровне с собственной реализацией в Windows. Кажется, Qt добился определенного прогресса в этой области.

Смежные вопросы