C# 从文本文件中删除行的有效方法

C# 从文本文件中删除行的有效方法,c#,performance,file-io,C#,Performance,File Io,我需要从文本文件中删除某一行。最有效的方法是什么?文件可能很大(超过百万条记录) 更新: 下面是我目前正在使用的代码,但我不确定它是否好 internal void DeleteMarkedEntries() { string tempPath=Path.GetTempFileName(); using (var reader = new StreamReader(logPath)) { using (var writer = new StreamWriter(F

我需要从文本文件中删除某一行。最有效的方法是什么?文件可能很大(超过百万条记录)

更新: 下面是我目前正在使用的代码,但我不确定它是否好

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

文本文件是连续的,因此当删除一行时,您必须向上移动以下所有行。 您可以使用文件映射(可以通过PInvoke调用的win32 api)来减轻此操作的痛苦,但您确实应该考虑对文件使用非顺序结构,以便您可以将一行标记为已删除,而无需将其从文件中删除。。。特别是如果它频繁发生的话


如果我记得应该将文件映射Api添加到.Net 4中。

最直接的方法可能是最好的,将整个文件写入一个新文件,写入除不需要的行以外的所有行

或者,打开文件进行随机访问

读到要“删除”行的位置。 跳过要删除的行,读取该字节数(包括CR+LF-如有必要),在已删除的行上写入该字节数,将两个位置向前移动该字节数,并重复该操作,直到文件结束

希望这有帮助

编辑-现在我可以看到您的代码了

if (!_deletedLines.Contains(counter)) 
{                            
    writer.WriteLine(reader.ReadLine());                        
}
行不通,如果这是你不想要的一行,你仍然想读它,只是不想写它。上面的代码既不会读也不会写。新文件将与旧文件完全相同

你想要什么

string line = reader.ReadLine();
if (!_deletedLines.Contains(counter)) 
{                            
    writer.WriteLine(line);                        
}
如果您必须使用文本文件,并且无法切换到数据库,则可能需要在行首指定一个wierd符号,表示“行已删除”。让解析器忽略这些行,比如配置文件中的注释行等

然后有一个定期的“压缩”例程,如Outlook,大多数数据库系统都会这样做,它会重新写入整个文件,不包括删除的行


我强烈赞同Think Before Codeing的答案,建议使用数据库或其他结构化文件。

像以前一样,使用文件映射将文件移动到内存,并在内存上和写入磁盘后进行删除。
读一下这个

根据什么才算是“删除”,最好的解决方案可能是用空格覆盖有问题的行。对于许多目的(包括人类消费),这相当于完全删除该行。如果生成的空行有问题,并且您确信永远不会删除第一行,则可以通过使用两个空格覆盖CRLF,将空格附加到前一行


(根据对博克·布拉特答案的评论)

在非删除行上将文件读入字典,将int设置为0 联机时,您需要将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());
字典输出=新建字典();
//从文件中读取行
...
//如果需要删除行,则将int值设置为1
//否则,将int值设置为0
如果(删除行)
{
输出[行]=1;
}
其他的
{
输出[行]=0;
}
//定义禁止删除列表
列表非删除列表=新列表();
//使用foreach循环遍历非删除列表中的每个项并添加每个键
//对于非远程列表,谁的值等于零(0)。
foreach(输出中的KeyValuePair kvp)
{
如果(kvp.Value==0)
{
添加(kvp.Key);
}
}
//将非远程列表写入输出文件
writeAllines(“输出文件名”,nondeletList.ToArray());

就是这样。

在我的博客中,我对C#中的各种I/O方法进行了基准测试,以确定执行文件I/O的最有效方式。一般来说,最好使用Windows ReadFile和WriteFile函数。读取文件的第二快方法是通过FileStream。要获得良好的性能,请一次读取块中的文件,而不是一次读取一行,然后自行进行解析。您可以从我的博客下载的代码为您提供了一个如何执行此操作的示例。还有一个C#类封装了Windows ReadFile/WriteFile功能,非常易于使用。有关详细信息,请访问我的博客:

Bob Bryan MCSD

试试看{
     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();
     }
扫描仪阅读器=新扫描仪(新文件(“D:/seenu.txt”); System.out.println(“输入序列号:”); 字符串sl1=bufRead.readLine(); System.out.print(“请输入服务器名:”); 字符串名称=bufRead.readLine(); System.out.println(“请输入IPAddress”); 字符串ipa=bufRead.readLine(); System.out.println(“删除行”); PrintWriter writer=new PrintWriter(new FileWriter(新文件(“D:/user.txt”)),true);
//对于(intw=0;如果您有这么大的数据存储,为什么不使用“real”数据库?这是对您可用的工具、当前技能或项目规格的限制吗?这是“上面”的要求。使用真正的数据库对我来说更容易,但不幸的是,我不能使用它。这不好,有一个bug-抱歉:(-见下面我的答案,要求是能够有一个人类可读的文件(但我不确定任何人怎么可能浏览一百万行!)。我对此要求无能为力。您的答案可以通过简短描述您的程序与问题中发布的代码的不同之处来改进。使用字典根本不是一种有效的方法。