2009-03-21 15 views
31

Mam problem: jak mogę usunąć linię z pliku tekstowego w C#?Jak usunąć linię z pliku tekstowego w języku C#?

+0

On/ona oznacza, jak usunąć programowo, jak sądzę. – splattne

+35

@John Saunders: Czy trudno jest zrozumieć, że OP chce usunąć linię z pliku tekstowego za pomocą C#? Jak to nie jest specyficzne? Bądźmy trochę przyjaźni dla początkujących. –

Odpowiedz

24

Przeczytaj plik, usuń linię z pamięci i ponownie umieść zawartość w pliku (nadpisanie). Jeśli plik jest duży, możesz chcieć odczytać wiersz dla linii i utworzyć plik tymczasowy, później zastępując oryginalny.

17

Zgadzam się z Johnem Saunders, to nie jest tak naprawdę specyficzne dla C#. Jednak, aby odpowiedzieć na twoje pytanie: w zasadzie musisz przepisać plik. Można to zrobić na dwa sposoby.

  • Czytaj cały plik do pamięci (np File.ReadAllLines)
  • Usuń linię przestępstwa (w tym przypadku to chyba najłatwiej przekształcić tablicę ciągów w List<string> następnie usunąć wiersz)
  • Napisz wszystko reszta linii pleców (np File.WriteAllLines) - potencjalnie przekształcić List<string> do tablicy ciągów ponownie stosując ToArray

oznacza to, że trzeba wiedzieć, że masz wystarczająco dużo pamięci chociaż. Alternatywą:

  • Otwarte zarówno plik wejściowy i nowy plik wyjściowy (jako TextReader/TextWriter, np File.OpenText i File.CreateText)
  • Czytaj linię (TextReader.ReadLine) - jeśli nie chcesz, aby usunąć to, zapisz go do pliku wyjściowego (TextWriter.WriteLine)
  • Kiedy czytasz wszystkie linie, bliski zarówno czytelnika i pisarza (jeśli używasz using sprawozdań dla obu, nastąpi to automatycznie)
  • Jeśli chcesz aby zastąpić wejście wyjściem, skasuj e plik wejściowy, a następnie przenieś plik wyjściowy na miejsce.
+0

Jestem w takiej samej sytuacji, w której muszę usunąć nagłówek pliku i dołączyć go do innego pliku. W systemie Windows, jeśli używam funkcji DOS przez C#, czy uważasz, że byłby to wzrost wydajności? Oto polecenie .. > WIĘCEJ +1 "sourcefilepath"> "targetFilePath" –

+0

@ImranAmjad: Nie wiem, ale to nie brzmi, jak byłoby trudno przetestować. Czy jest to szczególnie ważna dla wydajności część Twojego przepływu pracy? –

+0

Tak, rozmiar pliku może być większy niż pół GB i muszę to robić często. Robiąc to z poleceń DOSa, ponosisz cały ciężar i jestem tylko pewien, że jest on szybszy, ponieważ komendy dos ominą wszystkie warstwy systemu operacyjnego. Nie mam pewności co do wielu wewnętrznych elementów. To także oszczędza wiele linii kodu, ale czytelność kodu jest zagrożona dla niektórych osób. –

63

Dla samych dużych plików Chciałbym zrobić coś takiego

string tempFile = Path.GetTempFileName(); 

using(var sr = new StreamReader("file.txt")) 
using(var sw = new StreamWriter(tempFile)) 
{ 
    string line; 

    while((line = sr.ReadLine()) != null) 
    { 
     if(line != "removeme") 
      sw.WriteLine(line); 
    } 
} 

File.Delete("file.txt"); 
File.Move(tempFile, "file.txt"); 

Aktualizacji I pierwotnie napisał to z powrotem w 2009 roku i pomyślałem, że może to być interesujące z aktualizacją. Dziś można osiągnąć stosując powyższe LINQ and deferred execution

var tempFile = Path.GetTempFileName(); 
var linesToKeep = File.ReadLines(fileName).Where(l => l != "removeme"); 

File.WriteAllLines(tempFile, linesToKeep); 

File.Delete(fileName); 
File.Move(tempFile, fileName); 

Powyższy kod jest niemal dokładnie taka sama jak w pierwszym przykładzie, czytając wiersz po wierszu i przy zachowaniu minimalnej ilości danych w pamięci.

Zastrzeżenie może być jednak w porządku. Ponieważ mówimy tu o plikach tekstowych, bardzo rzadko trzeba używać tego dysku jako pośredniego nośnika. Jeśli nie masz do czynienia z bardzo dużymi plikami dzienników, nie powinno być problemu z odczytaniem zawartości w pamięci i unikaniem konieczności radzenia sobie z plikiem tymczasowym.

File.WriteAllLines(fileName, 
    File.ReadLines(fileName).Where(l => l != "removeme").ToList()); 

pamiętać, że .ToList jest niezbędna, żeby wymusić natychmiastowe wykonanie. Zauważ również, że wszystkie przykłady zakładają, że pliki tekstowe są kodowane w UTF-8.

2

ja bym bardzo prosto:

  • Otwórz plik do odczytu/zapisu
  • Odczyt/poszukiwania przez niego aż do początku wiersza, który chcesz usunąć
  • Ustaw wskaźnik zapisu do bieżący wskaźnik odczytu
  • Przeczytaj koniec linii, którą usuwamy i pomiń separatory linii nowej (licząc liczbę znaków w trakcie, będziemy ją nazywać)
  • Przeczytaj bajt po bajcie i napisz każdy bajt do file
  • Po zakończeniu przycinaj plik do (orig_length - nline).
5

ja przedłużony co sugeruje Markus Olsson i wpadł do tej klasy, który dodaje kilka ciągów wyszukiwania i kilka imprezy:

public static class TextLineRemover 
{ 
    public static void RemoveTextLines(IList<string> linesToRemove, string filename, string tempFilename) 
    { 
     // Initial values 
     int lineNumber = 0; 
     int linesRemoved = 0; 
     DateTime startTime = DateTime.Now; 

     // Read file 
     using (var sr = new StreamReader(filename)) 
     { 
      // Write new file 
      using (var sw = new StreamWriter(tempFilename)) 
      { 
       // Read lines 
       string line; 
       while ((line = sr.ReadLine()) != null) 
       { 
        lineNumber++; 
        // Look for text to remove 
        if (!ContainsString(line, linesToRemove)) 
        { 
         // Keep lines that does not match 
         sw.WriteLine(line); 
        } 
        else 
        { 
         // Ignore lines that DO match 
         linesRemoved++; 
         InvokeOnRemovedLine(new RemovedLineArgs { RemovedLine = line, RemovedLineNumber = lineNumber}); 
        } 
       } 
      } 
     } 
     // Delete original file 
     File.Delete(filename); 

     // ... and put the temp file in its place. 
     File.Move(tempFilename, filename); 

     // Final calculations 
     DateTime endTime = DateTime.Now; 
     InvokeOnFinished(new FinishedArgs {LinesRemoved = linesRemoved, TotalLines = lineNumber, TotalTime = endTime.Subtract(startTime)}); 
    } 

    private static bool ContainsString(string line, IEnumerable<string> linesToRemove) 
    { 
     foreach (var lineToRemove in linesToRemove) 
     { 
      if(line.Contains(lineToRemove)) 
       return true; 
     } 
     return false; 
    } 

    public static event RemovedLine OnRemovedLine; 
    public static event Finished OnFinished; 

    public static void InvokeOnFinished(FinishedArgs args) 
    { 
     Finished handler = OnFinished; 
     if (handler != null) handler(null, args); 
    } 

    public static void InvokeOnRemovedLine(RemovedLineArgs args) 
    { 
     RemovedLine handler = OnRemovedLine; 
     if (handler != null) handler(null, args); 
    } 
} 

public delegate void Finished(object sender, FinishedArgs args); 

public class FinishedArgs 
{ 
    public int TotalLines { get; set; } 
    public int LinesRemoved { get; set; } 
    public TimeSpan TotalTime { get; set; } 
} 

public delegate void RemovedLine(object sender, RemovedLineArgs args); 

public class RemovedLineArgs 
{ 
    public string RemovedLine { get; set; } 
    public int RemovedLineNumber { get; set; } 
} 

Zastosowanie:

 TextLineRemover.OnRemovedLine += (o, removedLineArgs) => Console.WriteLine(string.Format("Removed \"{0}\" at line {1}", removedLineArgs.RemovedLine, removedLineArgs.RemovedLineNumber)); 
     TextLineRemover.OnFinished += (o, finishedArgs) => Console.WriteLine(string.Format("{0} of {1} lines removed. Time used: {2}", finishedArgs.LinesRemoved, finishedArgs.TotalLines, finishedArgs.TotalTime.ToString())); 
     TextLineRemover.RemoveTextLines(new List<string> { "aaa", "bbb" }, fileName, fileName + ".tmp"); 
5

Aby usunąć pozycję z plik tekstowy, najpierw przenieś cały tekst do listy i usuń dowolny element. Następnie napisz tekst zapisany na liście do pliku tekstowego

List<string> quotelist=File.ReadAllLines(filename).ToList(); 
      string firstItem= quotelist[0]; 
      quotelist.RemoveAt(0); 
      File.WriteAllLines(filename, quotelist.ToArray()); 
      return firstItem; 
+1

Co powiesz na "drugą połówkę" (dobrze, pozostałe 0,05 procent), którzy nie mają ReadAllLines() lub WriteAllLines() w swojej wersji .NET? –

2

Witajcie, napisałem metodę usuwania linii z plików. Program ten wykorzystuje using System.IO

Zobacz mój kod:

void File_DeleteLine(int Line, string Path) 
    { 
     StringBuilder sb = new StringBuilder(); 
     using (StreamReader sr = new StreamReader(Path)) 
     { 
      int Countup = 0; 
      while (!sr.EndOfStream) 
      { 
       Countup++; 
       if (Countup != Line) 
       { 
        using (StringWriter sw = new StringWriter(sb)) 
        { 
         sw.WriteLine(sr.ReadLine()); 
        } 
       } 
       else 
       { 
        sr.ReadLine(); 
       } 
      } 
     } 
     using (StreamWriter sw = new StreamWriter(Path)) 
     { 
      sw.Write(sb.ToString()); 
     } 
    } 
0

Dlaczego nie można korzystać z tego? Najpierw należy utworzyć tablicę:

string[] lines = File.ReadAllLines(openFileDialog1.FileName); 

Następnie spojrzeć w górę linię należy usunąć i zastąpić go „”:

lines[x].Replace(lines[x], ""); 

Gotowe!

+1

To nie * usuwa * linię z pliku, wszystko co robi, powoduje, że linia 'x' jest pusta. Dlatego gdybyś robił to bardzo często, skończyłbyś z garstką pustych zwrotów w pliku, co mogłoby zepsuć indeksy. – carefulnow1