2014-10-15 16 views
-2

У меня есть большой файл (16 Gb) с миллионами записей. Каждая запись имеет 20-байтовую структуру.Разделить файл на несколько файлов

Теперь мне нужно разбить этот файл на несколько временных новых файлов (по 100 Мб каждый) и в то же время сохранить эту структуру неповрежденной (не срезать середину 20 байтов).

Каков наилучший алгоритм для расчета размера для новых файлов?

+0

Зависит. Каков формат вашего файла? Какой язык - C или C++? Выбери один_. –

+0

'system (" split -b "+ std :: to_string ((100ul << 20)/20 * 20) +" '"+ filename +"' ");' (почему C++) – sehe

+0

Вы не предоставили никаких контекст. Если это одноразовая задача, а не постоянная обязанность выполняться в контексте более крупной программы на C/C++, то это не вопрос C/C++. Предложение dd - лучший ответ, если вы находитесь в системе * nix, и вам не придется писать строку кода. dd может быть даже оптимизирован с небольшим усилием. Я использовал его для перемещения терабайтов для отделов govmint, где быстрая или временная задержка увидела бы меня, что я очень серьезно смотрю на людей, у которых есть подготовка к оружию ... –

ответ

3

Если каждая запись всегда 20 байт, вы будете в точности соответствовать 5242880 записям в файле размером 100 МБ (100 * 1024 * 1024).

Таким образом, должно быть довольно очевидно, как это сделать, нет никакого риска повредить запись, если вы всегда читаете и записываете кратность 20 байтов за раз. Так как ваш желаемый размер среза 100 МБ является таким кратным, используйте это. Если вы делаете это на ПК настольного класса или что-то в этом роде, буфер ввода-вывода 100 МБ довольно большой, но не экстремальный.

Итак, вы собираетесь сделать что-то вроде этого:

bool chunkify(const char *filename, size_t chunkSize) 
{ 
    void *buffer = malloc(chunkSize); 
    FILE *in; 
    bool ok = true; 

    if (buffer == NULL) 
    return false; 

    if ((fin = fopen(filename, "rb")) != NULL) 
    { 
    size_t got; 
    unsigned int count = 0; 

    while(ok && (got = fread(buffer, 1, chunkSize, fin)) > 0) 
    { 
     FILE *fout; 
     char outname[1024]; 
     snprintf(outname, sizeof outname, "%s-%u", filename, count++); 
     if ((fout = fopen(outname, "wb")) != NULL) 
     { 
     ok &= fwrite(buffer, got, 1, fout); 
     fclose(fout); 
     } 
    } 
    fclose(fin); 
    } 
    free(buffer); 
    return ok; 
} 

Примечания: выше не тестировался пол сложного кода I/O означает, как только отправная точка. Вероятно, у вас могут быть ошибки.

+2

Просто немного разобраться: напишите 100 МБ файлов с 20 размер блока байтов. Это займет много времени, поэтому, возможно, используйте кратные 20 байтов? В терминах bash - 'dd if = sourceFile of = destFile bs = 20 count = 5242880' – Yann

+0

В качестве примера я поставил 16 ГБ. Окончательный размер изменится.
Мне нужно все это для внешней сортировки .. для создания кусков. –

+0

@AlexK Размер ввода не имеет значения, вы будете делать то же самое, если это 20 байт, как будто это 16 ГБ. – unwind

2

Лучший алгоритм арифметический!

Ближайший кратный 20 байт записей до 100 МБ составляет 5 242 880 записей, и на самом деле он составляет точно 100 МБ.

Таким образом, вы можете просто расколоть свой файл на куски 100 МБ и сделать это.

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