Удалить первую строку из файла
Возможный дубликат:
Удаление первой строки текстового файла в С#
Какой бы самый быстрый и умный способ удалить первую строку из огромного (думаю, 2-3 ГБ) файла?
-
Я думаю, что вам, вероятно, не удастся переписать весь фрагмент файла, но я могу ошибаться.
-
Может ли использование файлов с отображением памяти каким-то образом помочь решить эту проблему?
-
Можно ли добиться такого поведения, действуя непосредственно в файловой системе (например, NTFS) - скажем, обновите соответствующие данные inode
и измените начальный сектор файла, чтобы первая строка игнорировалась? Если да, будет ли этот подход действительно хрупким или есть много других приложений, кроме самого OS
, которые делают что-то похожее?
Ответы
Ответ 1
NTFS
по умолчанию на большинстве томов (но, что немаловажно, не все!) хранит данные в 4096
байтовых фрагментах. На них ссылается запись $MFT
, которую вы не можете редактировать напрямую, потому что она запрещена операционной системой (по соображениям здравомыслия). В результате нет никакой возможности использовать файловую систему для того, чтобы сделать что-то, приближающееся к тому, что вы хотите (другими словами, вы не можете напрямую отменить обрезку файла на NTFS даже в размерах порции файловой системы.)
Из-за того, как файлы хранятся в файловой системе, единственным ответом является то, что вы должны полностью переписать весь файл. Или укажите другой способ хранения ваших данных. файл размером 2-3 ГБ является массовым и сумасшедшим, особенно учитывая, что вы ссылались на строки, означающие, что эти данные являются, по меньшей мере, частью текстовой информации.
Вы должны изучить возможность размещения этих данных в базе данных? Или организовать его немного более эффективно, по крайней мере.
Ответ 2
Вы можете перезаписать каждый символ, который хотите стереть, с помощью '\x7f'
. Затем, читая в файле, ваш читатель игнорирует этот символ. Это предполагает, что у вас есть текстовый файл, который никогда не использует символ DEL
, конечно.
std::istream &
my_getline (std::istream &in, std::string &s,
char del = '\x7f', char delim = '\n') {
std::getline(in, s, delim);
std::size_t beg = s.find(del);
while (beg != s.npos) {
std::size_t end = s.find_first_not_of(del, beg+1);
s.erase(beg, end-beg);
beg = s.find(del, beg+1);
}
return in;
}
Как указывает Хенк, вы можете выбрать другого персонажа, который будет действовать как ваш DELETE
. Но преимущество заключается в том, что эта техника работает независимо от того, какую строку вы хотите удалить (она не ограничена первой строкой) и не требует использования файловой системы.
Используя модифицированный считыватель, вы можете периодически "дефрагментировать" файл. Или дефрагментация может происходить естественным образом, когда содержимое передается/сливается в другой файл или архивируется на другой компьютер.
Изменить: Вы явно не говорите об этом, но я предполагаю, что это для какого-то приложения ведения журнала, где цель состоит в том, чтобы установить верхнюю границу размера файла журнала. Однако, если это цель, гораздо проще просто использовать коллекцию небольших файлов журнала. Скажем, вы сохранили файлы журналов размером 10 МБ, с общим журналом, ограниченным 4 ГБ. Таким образом, это будет около 400 файлов. Если начат 401-й файл, для каждой строки, написанной там, вы можете использовать маркер DELETE
в последовательных строках в первом файле. Когда все строки отмечены для удаления, сам файл можно удалить, и вы снова получите около 400 файлов. Не существует скрытого поведения O (n 2), пока первый файл не будет закрыт, когда строки будут удалены.
Но проще всего позволить вашей системе ведения журнала сохранить 1-й и 401-й файлы как есть и удалить 1-й файл при переходе в 402-й файл.
Ответ 3
Даже если вы можете удалить ведущий блок, это будет по крайней мере сектор (512 байт), возможно, не соответствует размеру вашей строки.
Рассмотрим оболочку (возможно, даже вспомогательный файл), чтобы начать чтение с определенного смещения.
Ответ 4
Идея (нет волшебной пыли, только тяжелая работа ниже):
используйте файловую систему пользовательского режима, например http://www.eldos.com/cbfs/ или http://dokan-dev.net/en/, чтобы WRAP вокруг вашей реальной файловой системы и создать небольшую систему учета, чтобы отслеживать, сколько файлов "съедено" спереди. В определенное время, когда файл становится слишком большим, перепишите файл в другой и начните.
Как насчет этого?
EDIT:
если вы идете в виртуальную файловую систему, тогда вы можете использовать фрагменты файла меньшего размера (256 МБ), которые можно склеить в один "виртуальный" файл с нужным смещением. Таким образом вам больше не понадобится перезаписывать файл.
MORE:
Отражение идеи о "переписывании" первых нескольких строк с помощью "ничего" - не делайте этого, вместо этого добавляйте одно 64-разрядное целое к FRONT файла и используйте любой метод, который вы хотите пропустить, что многие байты, например Stream
, который будет обертывать исходный поток и смещать его чтение.
Я предполагаю, что может быть лучше, если вы решите использовать обертку на стороне клиента.
Ответ 5
Разбить файл пополам, первый - меньший кусок.
Удалите первую строку, а затем присоедините ее к другой.