44

Source.txt と Target.txt の 2 つのテキスト ファイルがあります。ソースは変更されず、N 行のテキストが含まれます。したがって、Target.txt の特定のテキスト行を削除し、Source.txt の特定のテキスト行に置き換えたいと思います。必要な行数はわかっています。実際には行番号 2 で、両方のファイルです。

私はこのようなものを持っています:

string line = string.Empty;
int line_number = 1;
int line_to_edit = 2;

using StreamReader reader = new StreamReader(@"C:\target.xml");
using StreamWriter writer = new StreamWriter(@"C:\target.xml");

while ((line = reader.ReadLine()) != null)
{
    if (line_number == line_to_edit)
        writer.WriteLine(line);

    line_number++;
}

しかし、ライターを開くと、ターゲット ファイルが消去され、行が書き込まれますが、開くと、ターゲット ファイルにはコピーされた行のみが含まれ、残りは失われます。

私に何ができる?

4

6 に答える 6

65

最も簡単な方法は次のとおりです。

static void lineChanger(string newText, string fileName, int line_to_edit)
{
     string[] arrLine = File.ReadAllLines(fileName);
     arrLine[line_to_edit - 1] = newText;
     File.WriteAllLines(fileName, arrLine);
}

利用方法 :

lineChanger("new content for this line" , "sample.text" , 34);
于 2016-02-19T02:18:30.277 に答える
56

ファイル全体を書き換えずに行を書き換えることはできません (行がたまたま同じ長さでない限り)。ファイルが小さい場合は、ターゲット ファイル全体をメモリに読み込んでから、再度書き出すことが理にかなっています。次のようにできます。

using System;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        int line_to_edit = 2; // Warning: 1-based indexing!
        string sourceFile = "source.txt";
        string destinationFile = "target.txt";

        // Read the appropriate line from the file.
        string lineToWrite = null;
        using (StreamReader reader = new StreamReader(sourceFile))
        {
            for (int i = 1; i <= line_to_edit; ++i)
                lineToWrite = reader.ReadLine();
        }

        if (lineToWrite == null)
            throw new InvalidDataException("Line does not exist in " + sourceFile);

        // Read the old file.
        string[] lines = File.ReadAllLines(destinationFile);

        // Write the new file over the old file.
        using (StreamWriter writer = new StreamWriter(destinationFile))
        {
            for (int currentLine = 1; currentLine <= lines.Length; ++currentLine)
            {
                if (currentLine == line_to_edit)
                {
                    writer.WriteLine(lineToWrite);
                }
                else
                {
                    writer.WriteLine(lines[currentLine - 1]);
                }
            }
        }
    }
}

ファイルが大きい場合は、新しいファイルを作成して、一方のファイルからストリーミングを読み込んで、もう一方のファイルに書き込めるようにすることをお勧めします。これは、一度にファイル全体をメモリに保持する必要がないことを意味します。次のようにできます。

using System;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        int line_to_edit = 2;
        string sourceFile = "source.txt";
        string destinationFile = "target.txt";
        string tempFile = "target2.txt";

        // Read the appropriate line from the file.
        string lineToWrite = null;
        using (StreamReader reader = new StreamReader(sourceFile))
        {
            for (int i = 1; i <= line_to_edit; ++i)
                lineToWrite = reader.ReadLine();
        }

        if (lineToWrite == null)
            throw new InvalidDataException("Line does not exist in " + sourceFile);

        // Read from the target file and write to a new file.
        int line_number = 1;
        string line = null;
        using (StreamReader reader = new StreamReader(destinationFile))
        using (StreamWriter writer = new StreamWriter(tempFile))
        {
            while ((line = reader.ReadLine()) != null)
            {
                if (line_number == line_to_edit)
                {
                    writer.WriteLine(lineToWrite);
                }
                else
                {
                    writer.WriteLine(line);
                }
                line_number++;
            }
        }

        // TODO: Delete the old file and replace it with the new file here.
    }
}

書き込み操作が成功したことを確認したら、後でファイルを移動できます (例外がスローされず、ライターが閉じられます)。

どちらの場合も、行番号に 1 ベースのインデックスを使用しているため、少し混乱することに注意してください。コードで 0 ベースのインデックスを使用する方が理にかなっている場合があります。必要に応じて、プログラムへのユーザー インターフェイスで 1 から始まるインデックスを使用できますが、さらに送信する前に 0 から始まるインデックスに変換してください。

また、古いファイルを新しいファイルで直接上書きすることの欠点は、途中で失敗すると、書き込まれていないデータが永久に失われる可能性があることです。最初に 3 番目のファイルに書き込むことにより、元のデータの別の (修正された) コピーがあることを確認した後にのみ元のデータを削除するので、コンピューターが途中でクラッシュした場合にデータを復元できます。

最後のコメント: あなたのファイルの拡張子は xml であることに気付きました。特定の行を置き換えるのではなく、XML パーサーを使用してファイルの内容を変更する方が合理的かどうかを検討することをお勧めします。

于 2009-12-28T19:17:58.183 に答える
3

作成するときはStreamWriter常に最初からファイルを作成するため、3 番目のファイルを作成してターゲットからコピーし、必要なものを置き換えてから、古いファイルを置き換える必要があります。しかし、必要なのは XML 操作であることがわかるので、XmlDocumentXpath を使用してファイルを使用および変更することをお勧めします。

于 2009-12-28T19:15:32.493 に答える
2

以下が機能するはずです(例のライター部分の代わりに)。残念ながらビルド環境がないので記憶からですが参考になれば幸いです

using (var fs = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite)))
        {
            var destinationReader = StreamReader(fs);
            var writer = StreamWriter(fs);
            while ((line = reader.ReadLine()) != null)
            {
              if (line_number == line_to_edit)
                {
                    writer.WriteLine(lineToWrite);
                }
                else
                {
                    destinationReader .ReadLine();
                }
                line_number++;
            }
        }
于 2009-12-28T19:42:44.010 に答える
2

常に出力ファイルを上書きする新しい StreamReader を使用するのではなく、書き込みアクセスのために出力ファイルを開く必要があります。

StreamWriter stm = null;
fi = new FileInfo(@"C:\target.xml");
if (fi.Exists)
   stm = fi.OpenWrite();

もちろん、出力ファイルの正しい行をシークする必要がありますが、それを読み取ることができないため困難です。そのため、シーク先のバイト オフセットがわかっている場合を除き、読み取り/書き込みが必要になる可能性があります。アクセス。

FileStream stm = fi.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);

このストリームを使用すると、変更したいポイントに到達するまで読み取り、次に書き込むことができます。行ではなくバイトを書き込むことに注意してください。したがって、行を上書きするには、変更する行と同じ数の文字を書き込む必要があります。

于 2009-12-28T19:43:15.620 に答える