web-dev-qa-db-ja.com

C#でテキストファイルから行を削除する方法は?

問題があります:C#でテキストファイルから行を削除するにはどうすればよいですか?

42
alinpopescu

ファイルを読み取り、メモリ内の行を削除し、内容をファイルに戻します(上書き)。ファイルが大きい場合は、行ごとに読み取って、一時ファイルを作成し、後で元のファイルを置き換えることができます。

27
Sascha

very大きなファイルの場合、私はこのようなことをします

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");

Update私はもともと2009年にこれを書き直しましたが、アップデートで面白いかもしれないと思いました。今日、 LINQおよび遅延実行 を使用して上記を達成できました

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

File.WriteAllLines(tempFile, linesToKeep);

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

上記のコードは、最初の例とほぼ同じで、1行ずつ読み取り、メモリに最小限のデータを保持しています。

ただし、免責事項が必要な場合があります。ここではテキストファイルについて説明しているので、ディスクを中間ストレージメディアとして使用する必要はほとんどありません。非常に大きなログファイルを処理していない場合は、代わりに内容をメモリに読み込むのに問題はなく、一時ファイルを処理する必要はありません。

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

.ToListは、即時実行を強制するためにここで重要です。また、すべての例では、テキストファイルがUTF-8でエンコードされていることを前提としています。

74
Markus Olsson

私はジョン・サンダースに同意します、これは実際にはC#固有ではありません。ただし、質問に答えるには、基本的にファイルを書き換える必要があります。これを行うには2つの方法があります。

  • ファイル全体をメモリに読み込みます(例:File.ReadAllLines
  • 問題のある行を削除します(この場合、文字列配列をList<string>に変換してから行を削除するのがおそらく最も簡単です)
  • 残りの行をすべて書き戻します(例:File.WriteAllLines)-ToArrayを使用して、潜在的にList<string>を文字列配列に変換します。

つまり、十分なメモリがあることを知る必要があります。別の方法:

  • 入力ファイルと新しい出力ファイルの両方を開きます(TextReader/TextWriterとして、例えばFile.OpenTextFile.CreateTextで)
  • 行を読む(TextReader.ReadLine)-削除したくない場合は、出力ファイルに書き込む(TextWriter.WriteLine
  • すべての行を読んだら、リーダーとライターの両方を閉じます(両方にusingステートメントを使用する場合、これは自動的に行われます)
  • 入力を出力で置き換える場合は、入力ファイルを削除してから、出力ファイルを所定の場所に移動します。
19
Jon Skeet

テキストファイルからアイテムを削除するには、まずすべてのテキストをリストに移動し、必要なアイテムを削除します。次に、リストに保存されているテキストをテキストファイルに書き込みます。

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

Markus Olssonが提案したものを拡張し、複数の検索文字列といくつかのイベントを追加するこのクラスを思い付きました。

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; }
}

使用法:

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");
6
Håvard Fjær

ファイルから行を削除するメソッドを書きました。

このプログラムはusing System.IOを使用します。

私のコードを参照してください:

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());
    }
}
3
Leonhard P.

私はとても単純に:

  • 読み取り/書き込み用にファイルを開きます
  • 削除する行の先頭まで読み取り/検索します
  • 書き込みポインターを現在の読み取りポインターに設定します
  • 削除する行の最後まで読み通し、改行区切り文字をスキップします(進行中の文字数をカウントし、nlineと呼びます)
  • バイト単位で読み取り、各バイトをファイルに書き込みます
  • 終了したら、ファイルを(orig_length-nline)に切り捨てます。
3
Adam Hawes

なぜこれを使用できないのですか?まず、配列を作成します。

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

次に、削除する必要がある行を検索し、「」に置き換えます。

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

できた!

0
Marty Brant