我有两个文本文件,Source.txt和Target.txt。源将永远不会被修改并包含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:\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++;
}
}
}
但是当我打开Writer时,目标文件被删除,它会写入行,但是,当打开时,目标文件只包含复制的行,其余的则丢失。
我该怎么办?
答案 0 :(得分:43)
如果不重写整个文件,则无法重写行(除非行的长度恰好相同)。如果您的文件很小,那么将整个目标文件读入内存然后再将其写出可能是有意义的。你可以这样做:
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索引。
此外,使用新文件直接覆盖旧文件的缺点是,如果它在中途失败,那么您可能会永久丢失未写入的任何数据。首先写入第三个文件,只有在确定有另一个(更正的)副本后才删除原始数据,这样如果计算机中途崩溃,您可以恢复数据。
最后一句:我注意到你的文件有一个xml扩展名。您可能想要考虑使用XML解析器修改文件内容而不是替换特定行更有意义。
答案 1 :(得分:34)
最简单的方法是:
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);
答案 2 :(得分:3)
创建StreamWriter
时,它始终从头开始创建文件,您必须创建第三个文件并从目标复制并替换您需要的文件,然后替换旧文件。
但是我可以看到你需要的是XML操作,你可能想要使用XmlDocument
并使用Xpath修改你的文件。
答案 3 :(得分: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++;
}
}
答案 4 :(得分: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);
使用此流,您可以阅读,直到您想要进行更改,然后写。请记住,您正在编写字节而不是行,因此要覆盖一行,您需要编写与要更改的行相同数量的字符。