Альтернатива fwrite() для больших файлов на 32-битной системе
Я пытаюсь создать большие файлы (4-8 ГБ) с кодом C.
Теперь я использую fopen()
с параметрами 'wb'
, чтобы открыть двоичный файл файла и fwrite()
в цикле for
для записи байтов в файл. Я пишу один байт в каждой итерации цикла. Нет проблем, пока файл не станет больше или равен 4294967296 байт (4096 МБ). Это похоже на ограничение памяти в 32-битной ОС, потому что когда он записывает этот открытый файл, он все еще находится в ОЗУ. Я прав? Симптом заключается в том, что созданный файл имеет меньший размер, чем я хочу. Разница составляет 4096 МБ, например. когда я хочу 6000 МБ файла, он создает 6000 МБ - 4096 МБ = 1904 МБ файла.
Не могли бы вы предложить другой способ выполнить эту задачу?
С уважением:)
Часть кода:
unsigned long long int number_of_data = (unsigned int)atoi(argv[1])*1024*1024; //MB
char x[1]={atoi(argv[2])};
fp=fopen(strcat(argv[3],".bin"),"wb");
for(i=0;i<number_of_data;i++) {
fwrite(x, sizeof(x[0]), sizeof(x[0]), fp);
}
fclose(fp);
Ответы
Ответ 1
fwrite
здесь не проблема. Проблема - это значение, которое вы вычисляете для number_of_data
.
Вы должны быть осторожны с любым непреднамеренным 32-битным литьем при работе с 64-битными целыми числами. Когда я их определяю, я обычно делаю это на нескольких дискретных шагах, осторожно на каждом шагу:
unsigned long long int number_of_data = atoi(argv[1]); // Should be good for up to 2,147,483,647 MB (2TB)
number_of_data *= 1024*1024; // Convert to MB
Оператор присваивания (*=
) будет действовать на l-значение (unsigned long long int
), поэтому вы можете доверять ему, чтобы он работал с 64-битным значением.
Это может выглядеть неоптимизированным, но достойный компилятор удалит все ненужные шаги.
Ответ 2
У вас не должно возникнуть проблем с созданием больших файлов в Windows, но я заметил, что если вы используете 32-битную версию поиска в файле, то, похоже, она решила, что это 32-битный файл и, следовательно, не может быть больше 4 ГБ. У меня был успех с использованием _open, _lseeki64 и _write при работе s > 4 ГБ файлами в Windows. Например:
static void
create_file_simple(const TCHAR *filename, __int64 size)
{
int omode = _O_WRONLY | _O_CREAT | _O_TRUNC;
int fd = _topen(filename, omode, _S_IREAD | _S_IWRITE);
_lseeki64(fd, size, SEEK_SET);
_write(fd, "ABCD", 4);
_close(fd);
}
Вышеупомянутый файл создаст файл объемом более 4 ГБ без проблем. Тем не менее, это может быть медленным, так как при вызове _write() там файловая система должна фактически распределять блоки диска для вас. Вы можете быстрее найти небольшой разрешенный файл, если вам нужно его случайно заполнить. Если вы будете заполнять файл последовательно с самого начала, то указанный выше код будет в порядке. Обратите внимание: если вы действительно хотите использовать буферизованное IO, предоставленное fwrite, вы можете получить FILE * из дескриптора файла библиотеки C, используя fdopen().
(В случае, если кто-то задается вопросом, префиксы TCHAR, _topen и underscore - это все приличия MSVС++).
UPDATE
Исходный вопрос заключается в использовании последовательного вывода для N байтов значения V. Таким образом, простая программа, которая должна фактически выдать желаемый файл:
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <io.h>
#include <tchar.h>
int
_tmain(int argc, TCHAR *argv[])
{
__int64 n = 0, r = 0, size = 0x100000000LL; /* 4GB */
char v = 'A';
int fd = _topen(argv[1], _O_WRONLY | _O_CREAT| _O_TRUNC, _S_IREAD | _S_IWRITE);
while (r != -1 && n < count) {
r = _write(fd, &v, sizeof(value));
if (r >= 0) n += r;
}
_close(fd);
return 0;
}
Однако это будет очень медленным, поскольку мы пишем только один байт за раз. Это то, что можно улучшить, используя большой буфер или используя буферизованный ввод-вывод, вызывая fdopen на дескрипторе (fd) и переключаясь на fwrite.
Ответ 3
У Yuo нет проблем с fwrite()
. Проблема, кажется, в том, что вы
unsigned long long int number_of_data = (unsigned int)atoi(argv[1])*1024*1024; //MB
который действительно должен быть скорее чем-то вроде
uint16_t number_of_data = atoll(argv[1])*1024ULL*1024ULL;
unsigned long long
все равно будет нормально, но unsigned int * int * int
предоставит вам unsinged int
независимо от того, насколько велика ваша целевая переменная.