我需要从文本文件中删除某一行。这样做最有效的方法是什么?文件可能很大(超过百万条记录)。
更新: 下面是我目前正在使用的代码,但我不确定它是否合适。
internal void DeleteMarkedEntries() {
string tempPath=Path.GetTempFileName();
using (var reader = new StreamReader(logPath)) {
using (var writer = new StreamWriter(File.OpenWrite(tempPath))) {
int counter = 0;
while (!reader.EndOfStream) {
if (!_deletedLines.Contains(counter)) {
writer.WriteLine(reader.ReadLine());
}
++counter;
}
}
}
if (File.Exists(tempPath)) {
File.Delete(logPath);
File.Move(tempPath, logPath);
}
}
答案 0 :(得分:10)
最直接的做法可能是最好的,将整个文件写入新文件,写下除了你不想要的那些之外的所有行。
或者,打开文件进行随机访问。
读到您要“删除”该行的位置。 跳过要删除的行,并读取该字节数(包括CR + LF - 如果需要),在删除的行上写入该字节数,按字节数提前两个位置并重复直到文件结束。
希望这有帮助。
编辑 - 现在我可以看到您的代码
了if (!_deletedLines.Contains(counter))
{
writer.WriteLine(reader.ReadLine());
}
无法使用,如果您不想要的话,您仍然想要阅读,只是不写。上面的代码既不会读取也不会写入。新文件将与旧文件完全相同。
你想要像
这样的东西string line = reader.ReadLine();
if (!_deletedLines.Contains(counter))
{
writer.WriteLine(line);
}
答案 1 :(得分:3)
文本文件是连续的,因此在删除行时,您必须向上移动以下所有行。 你可以使用文件映射(你可以通过PInvoke调用的win32 api)使这个操作不那么痛苦,但你肯定应该考虑使用非顺序结构为你的文件,这样你就可以将一行标记为已删除,而无需真正删除它来自文件...特别是如果它应该经常发生。
如果我记得文件映射Api应该添加到.Net 4。
答案 2 :(得分:2)
try{
Scanner reader = new Scanner(new File("D:/seenu.txt"));
System.out.println("Enter serial number:");
String sl1=bufRead.readLine();
System.out.print("Please Enter The ServerName:");
String name=bufRead.readLine();
System.out.println("Please Enter The IPAddress");
String ipa=bufRead.readLine();
System.out.println("Line Deleted.");
PrintWriter writer = new PrintWriter(new FileWriter(new File("D:/user.txt")),true);
//for(int w=0; w<n; w++)
writer.write(reader.nextLine());
reader.nextLine();
while(reader.hasNextLine())
writer.write(reader.nextLine());
} catch(Exception e){
System.err.println("Enjoy the stack trace!");
e.printStackTrace();
}
答案 3 :(得分:0)
如果您绝对 使用文本文件并且无法切换到数据库,可能您想在行的开头指定一个奇怪的符号来表示“删除行”。只需让你的解析器忽略这些行,比如配置文件中的注释行等。
然后有一个像Outlook这样的定期“紧凑”例程,大多数数据库系统都会这样做,它会重写整个文件,不包括删除的行。
我强烈推荐使用Think Before Coding推荐数据库或其他结构化文件的答案。
答案 4 :(得分:0)
使用文件映射将文件移动到内存,如Think Before Coding所做的那样,并在内存和写入磁盘后删除。
阅读此File Read Benchmarks - C#
C# accessing memory map file
答案 5 :(得分:0)
根据确切的“删除”内容,您的最佳解决方案可能是用空格覆盖违规行。出于多种目的(包括人类消费),这相当于完全删除该行。如果生成的空白行有问题,并且您确定永远不会删除第一行,则可以通过用两个空格覆盖CRLF来将空格附加到上一行。
(基于对Bork Blatt的回答的评论)
答案 6 :(得分:0)
在我的博客中,我对C#中的各种I / O方法进行了基准测试,以确定最有效的文件I / O方式。通常,最好使用Windows ReadFile和WriteFile函数。读取文件的下一个最快方法是通过FileStream。要获得良好的性能,请一次读取块中的文件,而不是一次读取一行,然后进行自己的解析。您可以从我的博客下载的代码为您提供了如何执行此操作的示例。还有一个C#类封装了Windows ReadFile / WriteFile功能,并且非常易于使用。有关详细信息,请访问我的博客:
http://designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp
Bob Bryan MCSD
答案 7 :(得分:-1)
在非删除行上将文件读入字典,将int设置为0 在线你需要标记为已删除的set int为1.使用KeyValuePair来提取 不需要删除的行,并将它们写入新文件。
Dictionary<string, int> output = new Dictionary<string, int>();
// read line from file
...
// if need to delete line then set int value to 1
// otherwise set int value to 0
if (deleteLine)
{
output[line] = 1;
}
else
{
output[line] = 0;
}
// define the no delete List
List<string> nonDeleteList = new List<string>();
// use foreach to loop through each item in nonDeleteList and add each key
// who's value is equal to zero (0) to the nonDeleteList.
foreach (KeyValuePair<string, int> kvp in output)
{
if (kvp.Value == 0)
{
nonDeleteList.Add(kvp.Key);
}
}
// write the nondeletelist to the output file
File.WriteAllLines("OUTPUT_FILE_NAME", nonDeleteList.ToArray());
就是这样。