ofstream::operator<< (streambuf) - медленный способ копирования файла
Мне нужен кроссплатформенный, без внешней библиотеки, способ копирования файла. В моем первом проходе я придумал (обработка ошибок опущена):
char buffer[LEN];
ifstream src(srcFile, ios::in | ios::binary);
ofstream dest(destFile, ios::out | ios::binary);
while (!src.eof()) {
src.read(buffer, LEN);
dest.write(buffer, src.gcount());
}
Это работало хорошо, и я точно знал, что он делал.
Затем я нашел сообщение о stackru (извините, не могу найти ссылку прямо сейчас), в котором говорится, что я могу заменить весь приведенный выше код на:
dest << src.rdbuf();
Что приятно и компактно, но многое скрывает в том, что он делает. Это также оказывается очень медленным, потому что реализация ofstream::operator<< (streambuf) перемещает вещи по 1 символу за раз (используя snetxc () / sputc ()).
Есть ли способ сделать этот метод быстрее? Есть ли недостаток у моего оригинального метода?
Обновление: есть что-то неэффективное в использовании оператора<< (streambuf) в Windows. Цикл.read () /. Write () всегда работает лучше, чем оператор <<.
Кроме того, изменение размера буфера в приведенном выше коде не влияет на размер операций чтения и записи на жесткий диск. Для этого вам нужно установить буферы с помощью stream.rdbuf()->pubsetbuf().
3 ответа
Интересно, если ваш fstream небуферизован по умолчанию. GCC 4.5.2 по умолчанию использует внутренний буфер, но я не думаю, что этого требует стандарт. Вы пытались использовать pubsetbuf (см. Ниже), чтобы установить буфер для ваших входных / выходных потоков.
Быстрый тест в моей системе, если я установил LEN на 0 (и, следовательно, небуферизованный), потребовалось 10 секунд, чтобы скопировать файл размером 1 МБ. С буфером 4 КБ это завершилось менее чем за секунду.
#include <iostream>
#include <fstream>
int main() {
using namespace std;
const char* srcFile = "test.in";
const char* destFile = "test.out";
ifstream src;
ofstream dest;
const int LEN=8192;
char buffer_out[LEN];
char buffer_in[LEN];
if (LEN) {
src.rdbuf()->pubsetbuf(buffer_in, LEN );
dest.rdbuf()->pubsetbuf(buffer_out, LEN);
} else {
src.rdbuf()->pubsetbuf(NULL, 0 );
dest.rdbuf()->pubsetbuf(NULL, 0);
}
src.open(srcFile, ios::in | ios::binary);
dest.open(destFile, ios::out | ios::binary);
dest << src.rdbuf();
}
Попробуйте вместо этого использовать API-интерфейс C stdio, он часто может быть быстрее во многих реализациях (см. Этот поток для некоторых чисел), хотя и не всегда. Например:
// Error checking omitted for expository purposes
char buffer[LEN];
FILE *src = fopen(srcFile, "rb");
FILE *dest = fopen(destFile, "wb");
int n;
while ((n = fread(buffer, 1, LEN, src)) > 0)
{
fwrite(buffer, 1, n, dest);
}
fclose(src);
fclose(dest);
Конечно src.rdbuf
метод медленнее. Он делает чтение и запись одновременно. Если вы не копируете на другой жесткий диск или в другую форму сети или подключенного хранилища, это будет медленнее, чем чтение блока, а затем запись блока.
Тот факт, что код компактен, не делает его быстрее.
Поскольку вы не можете перегрузить operator<<
для std::filebuf
(так как он уже перегружен), вы ничего не можете сделать. Лучше просто использовать метод, который работает достаточно хорошо.