c++ - как считывать файлы большого размера?

301
05 мая 2017, 19:31

Нужно скопировать файл с одной дирректории в другую.

Написал программу, в которой есть два объекта типа FILE, с помощью fseek(fin, 0, SEEK_END) получаем размер, а чтение и запись происходят с помощью fread и fwrite.

Файл читаю блоками по 256 байт, вот код:

   // Переходим в конец файла
   fseek(fin, 0, SEEK_END);
   // Размер файла
   unsigned int m_file_size = ftell(fin);
   rewind(fin);
   // BLOCK_SIZE = 256 байт
   for(unsigned int i = 0; i < m_file_size / BLOCK_SIZE; ++i) {
        fread(buffer, sizeof(unsigned char), BLOCK_SIZE, fin);
        fwrite(buffer, sizeof(unsigned char), BLOCK_SIZE, fout);
   }
   // Дальше считываю остаток файла теми же fread и fwrite

Собственно, программа работает корректно с небольшими файлами (пробовал копировать файл размером 1 Гб - скопировал нормально). Однако при копировании фала размером 2.5 Гб. - выходной файл получается больше по размеру, чем входной.

Сам думаю, что проблема как раз в fseek, fread и fwrite, так как они работают с интом, который больше 2.147 Гб. не вместит.

Вопрос такой: что нужно использовать вместо этих трех функций, чтобы программа корректно работала для больших файлов?

UPDATE 1

Код с открытием файла:

// File to read
FILE *fin;
// File to write
FILE *fout;
const int BLOCK_SIZE = 256;
unsigned char buffer[BLOCK_SIZE];
if(!(fin = fopen(file_from_path.toStdString().c_str(), "rb")) == NULL &&
   !(fout = fopen(file_to_path.toStdString().c_str(), "wb")) == NULL) {
    // The end of the file
    fseek(fin, 0, SEEK_END);
    // Get size of the file
    unsigned int m_file_size = ftell(fin);
    // Go to start
    rewind(fin);
    // Read and write by "BLOCK_SIZE" bytes
    for(size_t i = 0; i < m_file_size / BLOCK_SIZE; ++i) {
        // Read "BLOCK_SIZE" bytes to buffer
        fread(buffer, sizeof(unsigned char), BLOCK_SIZE, fin);
        // Write "BLOCK_SIZE" bytes
        fwrite(buffer, sizeof(unsigned char), BLOCK_SIZE, fout);
    }
}
Answer 1

Поскольку в стандарте работа идет с int да long, каковые в большинстве своем 32-битные, я бы использовал нестандартные функции операционной системы или соответствующие расширения компилятора.

Если это VC++, то можно использовать всяческие нестандартные расширения - функции типа _fseeki64, _ftelli64 и иже с ними - например, см. тут.

Кстати, вот это

    fread(buffer, sizeof(unsigned char), BLOCK_SIZE, fin);
    fwrite(buffer, sizeof(unsigned char), BLOCK_SIZE, fout);

некорректно. С чего вы решили, что у вас размер кратен размеру буфера?

    int readed = fread(buffer, sizeof(unsigned char), BLOCK_SIZE, fin);
    fwrite(buffer, sizeof(unsigned char), readed, fout);

правильнее. Но по-хорошему, надо еще и возврат записи проверять.

Ага, вот причина большего размера: fseek/ftell при некорректной работе возвращают -1, что у вас для вашего unsigned m_file_size трансформируется в 4 Гигабайта. Результат понятен...

Вот работающий код. Правда, надо все равно проверять возврат всех функций...

// File to read
FILE *fin;
// File to write
FILE *fout;
const int BLOCK_SIZE = 256;
unsigned char buffer[BLOCK_SIZE];
if(!(fin = fopen("data.in", "rb")) == NULL &&
   !(fout = fopen("data.out", "wb")) == NULL) {
    // The end of the file
    _fseeki64(fin, 0, SEEK_END);
    // Get size of the file
    long long m_file_size = _ftelli64(fin);
    // Go to start
    _fseeki64(fin, 0, SEEK_SET);
    // Read and write by "BLOCK_SIZE" bytes
    for(size_t i = 0; i <= m_file_size / BLOCK_SIZE; ++i) {
        int readed = fread(buffer, sizeof(unsigned char), BLOCK_SIZE, fin);
        fwrite(buffer, sizeof(unsigned char), readed, fout);
    }
    fclose(fin);
    fclose(fout);
}
READ ALSO
Настройка формата аудиоустройства в Windows

Настройка формата аудиоустройства в Windows

Я разрабатываю приложение для аудиоустройства, работающего по стандарту usb audioОдной из задач является выбор формата воспроизведения: количество...

244
building a multi file project in sublime text [требует правки]

building a multi file project in sublime text [требует правки]

When I'm building a project in sublime text using command shift b i getting only 2 options and both of them are about building single fileTherefore main file can see none of my headers

203
С++ | Помогите с кодом на С++

С++ | Помогите с кодом на С++

Приветствую, господаПомогите пожалуйста с "почти" готовыми кодами, которые нужно довести до ума

266
proxy vs decorator

proxy vs decorator

Доброго времени сутокВ своем вопросе рассматриваю паттерны прокси и декоратор исключительно в контексте языка c++

333