2013-10-08 4 views
0

Я пытаюсь запустить программу для замены определенных данных в файле. Соответствующие части файла, пытающиеся заменить, выглядят следующим образом:C++ перезапись данных файла?

1 Information 15e+10 

2 Information 2e+16 

3 Information 6e+2 

И так далее.

Эти файлы могут быть очень большими в диапазоне нескольких гигабайт и, насколько мне известно, из-за этого с использованием буфера всего файла и перезаписи всего файла невозможно/необоснованно. Ну, это нормально, я просто хочу заменить значения (например, 15e+10).

Это все работает отлично с простой ios::in|ios::out и tellp() если я заменить значение с аналогичным размером значением (15e+10 ->12e+12) или даже если его меньшего размером, как я могу просто добавить дополнительное пространство, которое может быть проигнорировано вниз линия (например, 15e+10 ->4e+10 ). Но я столкнулся с проблемой, если мне нужно заменить значение значением, длина которого больше, чем уже в файле (например, 6e+2 ->16e+10), он будет писать поверх нового символа строки или начинать писать информацию в следующая строка.

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

Если нет, то как я могу открыть 2 файла (1 вход 1 выход), если несколько файлов, о которых идет речь, слишком велики для памяти?

Примечание: Я хотел бы также, чтобы избежать использования boost:: как мне нужно, чтобы иметь возможность запускать это на систему без повышающих библиотеки.

+2

Вам не нужно иметь весь файл в память. Вам нужно только иметь одну запись в памяти в любой момент времени. Однако использование записей переменной длины, которые необходимо обновить на месте для файлов такого размера, в значительной степени гарантируется как кошмар производительности. Записи с фиксированной длиной были бы самым простым решением. –

+0

Не использование текстовых файлов размером в несколько гигабайт может быть другим вариантом. –

+0

Что именно вы имеете в виду, мне нужна только 1 запись в памяти за раз? Я считал (легко ошибаюсь), что наличие открытого файла означало, что информация, которую вы читали на нем, в любом выбранном методе, была сохранена в памяти, а наличие второго файла, открытого для записи, сделало бы это в два раза больше места. Это определенно отвечает на мой вопрос, если это не так, и единственная часть, хранящаяся в памяти, - это то, что было прочитано, в котором должна быть только строка за раз. И Fixed-Length было бы неплохо, но со значительными вариациями (более чем на примере) в то время было бы разумнее выбирать нет. – JCline

ответ

1

Откройте поток для чтения из файла ввода (IN) и второго потока (OUT) для записи в новый файл вывода (tmp).

Читайте с IN и пишите в OUT. Когда вы получите значение от IN, которое вы хотите заменить, замените OUT на значение вместо значения, которое вы получили от IN.

Когда синтаксический анализ завершен, замените первый файл на второй (tmp) файл.

Будет ли это работать на вас?

+0

Мне нравится идея, но в этом случае мне нужно одновременно открыть оба файла file1.open (ios :: in) и file2.open (ios :: out), что означает, что они будут сохранены в памяти, чтобы вы могли быстро их получить, исправить? В этом случае мне нужно будет сделать файлы значительно меньше или мне потребуется использовать суперкомпьютер с >> 8 ГБ оперативной памяти. – JCline

+1

@JCline - Нет, оба файла не хранятся в памяти. Методы файлов C++ и API операционной системы под ним будут управлять буферизацией для вас. Вы можете смело игнорировать размеры файлов, насколько это касается использования памяти. –

0

Используйте lseek()/fseek() для перехода в заданное положение в файле.

+0

Как это решить проблему * перезаписи * (третий случай в OP)? – zakinster

+0

Вы должны настроить пространство для хранения фиксированной длины для каждого элемента, например. 12 байт, тогда вам не нужно беспокоиться о разных длинах элементов. Когда данные короче 12 байт, будет некоторое ослабление. – ern0

0

Вы можете использовать seekp идти к месту и переписать его с <<

Пример:

example.txt (|?| = 1 байт данных)

| A | B | C | \ n | 1 | 2 | 3 | D | E | F | \ n | 4 | 5 | 6 |

//Somewhere in the code 

fstream file; 

open("example.txt"); 

//Somehow find the character distance and store it into "distance" 

seekp(distance);//If distance = 0, it will go to "A" like rewind() but easier for me 

Если расстояние 4, то следующий символ будет переписан в 1

file << "987"; 

И файл будет

| | B | C | \ п | | | | D | E | F | \ n | 4 | 5 | 6 |

НО единственная проблема здесь, когда вам нужно увеличения/уменьшения размера:

Увеличение:

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

| A | B | C | \ n | | | | D | E | F | \ n | 4 | 5 | 6 |

string tempstring; 
seekp(distance); 
file >> tempstring; 
seekp(distance); 
file << content << tempstring; //content is the data 

Уменьшение:

Самое простое решение состоит в написании нулевой символ\0 в избыточном пространстве, как

| A | B | C | \ п | | \ 0 | \ 0 | D | E | F | \ n | 4 | 5 | 6 |

Единственный побочный эффект является размер файла такой же, как до того

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