在 C# 中编辑文本文件的特定行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1971008/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Edit a specific Line of a Text File in C#
提问by Luis
I have two text files, Source.txt and Target.txt. The source will never be modified and contain N lines of text. So, I want to delete a specific line of text in Target.txt, and replace by an specific line of text from Source.txt, I know what number of line I need, actually is the line number 2, both files.
我有两个文本文件,Source.txt 和 Target.txt。源永远不会被修改并包含 N 行文本。所以,我想删除Target.txt中的特定行文本,并用Source.txt中的特定行文本替换,我知道我需要多少行,实际上是第2行,这两个文件。
I haven something like this:
我有这样的事情:
string line = string.Empty;
int line_number = 1;
int line_to_edit = 2;
using (StreamReader reader = new StreamReader(@"C:\source.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++;
}
}
}
But when I open the Writer, the target file get erased, it writes the lines, but, when opened, the target file only contains the copied lines, the rest get lost.
但是当我打开 Writer 时,目标文件被删除,它会写入行,但是,当打开时,目标文件只包含复制的行,其余的都丢失了。
What can I do?
我能做什么?
采纳答案by Mark Byers
You can't rewrite a line without rewriting the entire file (unless the lines happen to be the same length). If your files are small then reading the entire target file into memory and then writing it out again might make sense. You can do that like this:
您不能在不重写整个文件的情况下重写一行(除非这些行恰好具有相同的长度)。如果您的文件很小,那么将整个目标文件读入内存然后再次将其写出可能是有意义的。你可以这样做:
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]);
}
}
}
}
}
If your files are large it would be better to create a new file so that you can read streaming from one file while you write to the other. This means that you don't need to have the whole file in memory at once. You can do that like this:
如果您的文件很大,最好创建一个新文件,以便您可以在写入另一个文件时从一个文件读取流。这意味着您不需要一次将整个文件保存在内存中。你可以这样做:
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.
}
}
You can afterwards move the file once you are sure that the write operation has succeeded (no excecption was thrown and the writer is closed).
一旦您确定写入操作成功(没有抛出异常并且写入器已关闭),您就可以随后移动文件。
Note that in both cases it is a bit confusing that you are using 1-based indexing for your line numbers. It might make more sense in your code to use 0-based indexing. You can have 1-based index in your user interface to your program if you wish, but convert it to a 0-indexed before sending it further.
请注意,在这两种情况下,您对行号使用基于 1 的索引都有些令人困惑。在您的代码中使用基于 0 的索引可能更有意义。如果您愿意,您可以在程序的用户界面中使用基于 1 的索引,但在进一步发送之前将其转换为 0 索引。
Also, a disadvantage of directly overwriting the old file with the new file is that if it fails halfway through then you might permanently lose whatever data wasn't written. By writing to a third file first you only delete the original data after you are sure that you have another (corrected) copy of it, so you can recover the data if the computer crashes halfway through.
此外,用新文件直接覆盖旧文件的缺点是,如果中途失败,那么您可能会永久丢失未写入的任何数据。通过首先写入第三个文件,您只有在确定您有另一个(更正)副本后才删除原始数据,因此如果计算机中途崩溃,您可以恢复数据。
A final remark: I noticed that your files had an xml extension. You might want to consider if it makes more sense for you to use an XML parser to modify the contents of the files instead of replacing specific lines.
最后一句话:我注意到你的文件有一个 xml 扩展名。您可能需要考虑使用 XML 解析器来修改文件的内容而不是替换特定行是否更有意义。
回答by Pablo Retyk
When you create a StreamWriter
it always create a file from scratch, you will have to create a third file and copy from target and replace what you need, and then replace the old one.
But as I can see what you need is XML manipulation, you might want to use XmlDocument
and modify your file using Xpath.
当您创建StreamWriter
它时,它总是从头开始创建一个文件,您将不得不创建第三个文件并从目标复制并替换您需要的内容,然后替换旧的。但正如我所看到的,您需要的是 XML 操作,您可能希望XmlDocument
使用 Xpath来使用和修改您的文件。
回答by Rune FS
I guess the below should work (instead of the writer part from your example). I'm unfortunately with no build environment so It's from memory but I hope it helps
我想下面应该工作(而不是你的例子中的作者部分)。不幸的是,我没有构建环境,所以它来自记忆,但我希望它有所帮助
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++;
}
}
回答by John Knoeller
You need to Open the output file for write access rather than using a new StreamReader, which always overwrites the output file.
您需要打开输出文件以进行写访问,而不是使用新的 StreamReader,它总是会覆盖输出文件。
StreamWriter stm = null;
fi = new FileInfo(@"C:\target.xml");
if (fi.Exists)
stm = fi.OpenWrite();
Of course, you will still have to seek to the correct line in the output file, which will be hard since you can't read from it, so unless you already KNOW the byte offset to seek to, you probably really want read/write access.
当然,您仍然必须在输出文件中寻找正确的行,这将很难,因为您无法从中读取,因此除非您已经知道要寻找的字节偏移量,否则您可能真的想要读/写使用权。
FileStream stm = fi.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
with this stream, you can read until you get to the point where you want to make changes, then write. Keep in mind that you are writing bytes, not lines, so to overwrite a line you will need to write the same number of characters as the line you want to change.
使用此流,您可以阅读直到到达要进行更改的点,然后再写入。请记住,您正在写入字节,而不是行,因此要覆盖一行,您需要写入与要更改的行相同数量的字符。
回答by Bruce Afruz
the easiest way is :
最简单的方法是:
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);
}
usage :
用法 :
lineChanger("new content for this line" , "sample.text" , 34);