Эффективный способ удалить строку из текстового файла - PullRequest
9 голосов
/ 10 февраля 2009

Мне нужно удалить определенную строку из текстового файла. Каков наиболее эффективный способ сделать это? Файл может быть потенциально большим (более миллиона записей).

UPDATE: ниже приведен код, который я сейчас использую, но я не уверен, что он хорош.

internal void DeleteMarkedEntries() {
    string tempPath=Path.GetTempFileName();
    using (var reader = new StreamReader(logPath)) {
        using (var writer = new StreamWriter(File.OpenWrite(tempPath))) {
            int counter = 0;
            while (!reader.EndOfStream) {
                if (!_deletedLines.Contains(counter)) {
                    writer.WriteLine(reader.ReadLine());
                }
                ++counter;
            }
        }
    }
    if (File.Exists(tempPath)) {
        File.Delete(logPath);
        File.Move(tempPath, logPath);
    }
}

Ответы [ 8 ]

10 голосов
/ 10 февраля 2009

Самый простой способ сделать это, вероятно, самый лучший: записать весь файл в новый файл, записав все строки, кроме той, которую вы не хотите.

Либо откройте файл для произвольного доступа.

Читайте до точки, где вы хотите «удалить» строку. Пропустите строку, которую хотите удалить, и прочитайте это количество байтов (включая CR + LF - если необходимо), запишите это число байтов по удаленной строке, продвиньте оба местоположения на это количество байтов и повторите до конца файла.

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ - Теперь, когда я вижу ваш код

if (!_deletedLines.Contains(counter)) 
{                            
    writer.WriteLine(reader.ReadLine());                        
}

Не будет работать, если это строка, которую вы не хотите, вы все равно хотите прочитать ее , просто не пишите ее . Приведенный выше код не будет ни читать, ни писать. Новый файл будет точно таким же, как и старый.

Вы хотите что-то вроде

string line = reader.ReadLine();
if (!_deletedLines.Contains(counter)) 
{                            
    writer.WriteLine(line);                        
}
3 голосов
/ 10 февраля 2009

Текстовые файлы являются последовательными, поэтому при удалении строки вам нужно будет переместить все следующие строки вверх. Вы можете использовать сопоставление файлов (API-интерфейс win32, который вы можете вызвать через PInvoke), чтобы сделать эту операцию менее болезненной, но вам, безусловно, следует подумать об использовании непоследовательной структуры для вашего файла, чтобы можно было пометить строку как удаленную без реального удаления это из файла ... Особенно, если это случается часто.

Если я помню, в .Net 4 следует добавить File Mapping Api.

2 голосов
/ 04 декабря 2012
     try{
     Scanner reader = new Scanner(new File("D:/seenu.txt")); 
     System.out.println("Enter serial number:");
     String sl1=bufRead.readLine();
     System.out.print("Please Enter The ServerName:");
     String name=bufRead.readLine();
     System.out.println("Please Enter The IPAddress");
     String ipa=bufRead.readLine();

    System.out.println("Line Deleted.");
     PrintWriter writer = new PrintWriter(new FileWriter(new File("D:/user.txt")),true); 
     //for(int w=0; w<n; w++)
       writer.write(reader.nextLine()); 
     reader.nextLine(); 
     while(reader.hasNextLine())
       writer.write(reader.nextLine());
     } catch(Exception e){
       System.err.println("Enjoy the stack trace!");
       e.printStackTrace();
     }
0 голосов
/ 04 марта 2011

В своем блоге я провел сравнительный анализ различных методов ввода-вывода в C #, чтобы определить наиболее эффективный способ ввода-вывода в файл. В целом, вам лучше использовать функции Windows ReadFile и WriteFile. Следующий быстрый способ чтения файлов - через FileStream. Чтобы получить хорошую производительность, читайте файлы по блокам за раз вместо строки за раз, а затем выполняйте собственный анализ. Код, который вы можете скачать с моего блога, дает вам пример того, как это сделать. Существует также класс C #, который инкапсулирует функциональность Windows ReadFile / WriteFile и довольно прост в использовании. Подробности смотрите в моем блоге по адресу:

http://designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp

Боб Брайан MCSD

0 голосов
/ 05 мая 2010

Считайте ваш файл в словарь на не удаляемых строках, установите int в 0 на линии вы должны пометить как удаленное, установите int в 1. Используйте KeyValuePair, чтобы извлечь строки, которые не нужно было удалять, и запишите их в новый файл.

Dictionary<string, int> output = new Dictionary<string, int>();

// read line from file

...

// if need to delete line then set int value to 1

// otherwise set int value to 0
if (deleteLine)
{
    output[line] = 1;
}
else
{
    output[line] = 0;
}

// define the no delete List
List<string> nonDeleteList = new List<string>();

// use foreach to loop through each item in nonDeleteList and add each key
// who's value is equal to zero (0) to the nonDeleteList.
foreach (KeyValuePair<string, int> kvp in output)
{

    if (kvp.Value == 0)

    {

        nonDeleteList.Add(kvp.Key);

    }
}

// write the nondeletelist to the output file
File.WriteAllLines("OUTPUT_FILE_NAME", nonDeleteList.ToArray());

Вот и все.

0 голосов
/ 10 февраля 2009

В зависимости от того, что именно считается «удалением», лучшим решением может быть перезапись ошибочной строки пробелами. Для многих целей (включая потребление человеком) это эквивалентно прямому удалению строки. Если полученная пустая строка является проблемой, и вы уверены, что никогда не удалите первую строку, вы можете добавить пробелы к предыдущей строке, также переписав CRLF двумя пробелами.

(на основании комментария к ответу Борка Блатта)

0 голосов
/ 10 февраля 2009

Переместите файл в память, используя сопоставление файлов, как Подумайте до кодирования , и удалите его в памяти и после записи на диск. Прочитайте Тесты чтения файла - C #
C # доступ к файлу карты памяти

0 голосов
/ 10 февраля 2009

Если у вас абсолютно есть для использования текстового файла и вы не можете переключиться на базу данных, возможно, вы хотите обозначить странный символ в начале строки, который будет означать «строка удалена». Просто попросите ваш парсер игнорировать эти строки, такие как строки комментариев в файлах конфигурации и т. Д.

Затем следует периодическая «компактная» подпрограмма, как в Outlook, и большинство систем баз данных делают это, перезаписывая весь файл, исключая удаленные строки.

Я бы решительно согласился с ответом Think Before Coding с рекомендацией базы данных или другого структурированного файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...