在 C# 中同时读取和写入文件

本文关键字:文件 读取 | 更新日期: 2023-09-27 18:35:49

我正在尝试用 C# 同时读取和写入文件。我在这里和 MSDNA 中阅读了许多线程,但似乎没有一个符合我的需求。我的文件有一系列用逗号分隔的数字。确切地说,是大量的数字。我数据中的一个示例行是这样的

-0.1171695,0.03270377,2.420116,-0.02128719,0.9612453,0.2460478,-0.1225349,-0.110185,0.07739609,2.500247,-0.2783474,-0.06909045,-0.01818598,0.9578197,-0.1089995,0.456151,2.639686,0.3486561,-0.0008622027,-0.002657401,0.9372466,-0.1170361,0.6441286,2.674476,0.08662115,0.001171953,-0.01347759,0.9961495,-0.2623751,0.3104511,2.600713,-0.002028131,0.004831213,0.9220369,-0.3870664,-0.3145202,0.123338,2.49155,0.217727,0.4528476,-0.2009471,0.8409188,-0.2771441,-0.07509593,2.299996,0.2185546,3.817581E-09,7.635163E-09,0.9758247,-0.2690773,-0.1254997,2.259336,-0.02814693,0.0009682054,-0.03436448,0.9990125,0.01672855,0.3196935,2.572941,0.001961287,0.005368799,0.9392719,0.3431264,0.08505877,0.1033191,2.450031,0.1364797,-0.3903133,0.161962,0.8959894,0.03953359,-0.08940583,2.255897,0.2523192,7.699712E-09,0,0.967644,0.01856858,-0.1507191,2.211281,0.004362902,0.0004109977,0.09378911,0.9955825,-0.1821601,-0.03123568,2.403718,4.035548E-09,-3.067017E-07,0.9231187,-0.384515,-0.2238743,-0.4083549,2.266029,-0.05534944,0.02699615,-0.3286877,0.9424288,-0.2095885,-0.7422835,2.178757,-0.06393463,-0.003723484,-0.0580211,0.9962591,-0.2166772,-0.7653325,2.087598,0.5079094,0.03407073,-0.05760901,0.8588064,-0.05478298,-0.01793054,2.37413,8.070093E-09,-3.066635E-07,0.9232336,0.3842392,0.004473582,-0.3737353,2.252681,-0.09306445,-0.04594634,0.3224528,0.9408783,0.004849254,-0.7096405,2.178587,-0.03546751,0.003154774,0.08854229,0.9954358,-0.005173458,-0.7367281,2.088935,0.5053017,0.02486493,-0.04239483,0.861542,63507242650167

它实际上在写字板中占据了24行。每一行。我想做的是转到每行的最后一行,对其进行更改,然后将其保存回文件中。我找到的所有同步写入器阅读器源代码都在使用 append。我不想在文件末尾附加。我希望从每行中获取最后一个数字,并将修改后的数字放回原处。我希望其余数据保持不变。我该怎么做?

在 C# 中同时读取和写入文件

你想要做的事情违反了Windows和POSIX中低级文件I/O API的限制;具体来说,除了重写整个文件之外,不可能在文件中间插入或删除字节。 有两种常用的"重写整个文件"的方法:

  • 读取整个文件,然后将其写回文件,其中包含所需的更改。完成后,关闭两个文件,删除旧文件,然后将新文件重命名为旧名称。 ("删除旧文件"步骤仅在Windows上是必需的,不幸的是,它引入了一个竞赛窗口,在该窗口中,同时阅读者可能会发现该文件不存在正确的名称。 这是首选技术,因为它更容易正确编码,不需要您暂时将整个文件保存在内存中,如果计算机在操作过程中崩溃,不会损坏文件,1 并保证并发读取器将看到新文件或旧文件,而不是两者的某种组合。 但是,它需要的暂存磁盘空间等于旧文件或新文件中较大的存储空间。

  • 将整个文件读入内存。对文件的内存中表示形式进行更改(可以像大字符串或字符串列表一样简单)。倒带文件句柄并从头开始写回所有内容。(从技术上讲,您只需要在第一次更改之后写入所有内容,但这需要您知道第一次更改的字节偏移量,这通常比它的价值更麻烦。 如果结果比原始结果短,请使用truncate或等效物来切断多余的部分。 这不需要额外的暂存磁盘空间,但并发读取器可能会看到两个文件的乱码组合,如果计算机在操作过程中崩溃,则文件可能会被销毁。 您可以通过文件锁定来缓解并发读取器问题,但请注意,某些文件锁定机制是建议性的,即仅对知道锁定可能正在发生的读取器有效。

1 某些操作系统和/或文件系统要求在重命名之前调用新文件fsync,以确保在重命名计算机在数十分钟长的窗口中崩溃时的数据完整性。 这是这些系统中的错误。

您应该考虑内存映射文件之一:

http://blogs.msdn.com/b/salvapatuel/archive/2009/06/08/working-with-memory-mapped-files-in-net-4.aspx

或者可能是托管的 ESENT 包装器:

http://managedesent.codeplex.com/wikipage?title=PersistentDictionaryDocumentation&referringTitle=Home

应该像这样简单:

List<string> myLines = File.ReadAllLines("file.txt").ToList();
foreach (string s in myLines)
{
    //whatever you're doing to each line
}
File.WriteAllLines("file.txt", myLines);

为什么不用ReadAllLines()读取文件,用Regex.Replace()替换,然后WriteAllLines()

编辑:详细地:

string[] lines = File.WreadAllLines("file.txt");
int lastnum;
for(int i=0;i<lines.Count;i++)
    lines[i]=System.Text.RegularExpressions.Regex.Replace(lines[i], @",('d+)$", m => 
    { 
        lastnum = Convert.ToInt32(m.Groups[1].Value);
        // Do any operations on lastnum
        return "," + lastnum.ToString(); 
    });
File.WriteAllLines("file.txt",lines);

要读取并保存文件:

StringBuilder newTextFile = new StringBuilder();
string[] lines = File.ReadAllLines(@"1.txt");
foreach (string l in lines)
{
   // logic to replace last number, saved in string newLine
   // you can find the last        
   newTextFile.Append(newLine + "'r'n");
}
File.WriteAllText(@"1.txt", newTextFile.ToString());

要更改行(从我的头顶上,测试它!

int locationAt = line.LastIndexOf(',');
string newLine = line.Substring(0, locationAt) + newValue + line.Substring(locationAt);

或:

string[] values = line.Split(',');
values[values.Length - 1] = 'somethingelse';
string newLine = string.Join(",", values);

由于您只更改每行逗号后的最后一个数字,因此您可以做的是逐行读取并获取逗号的最后一个索引,然后获取子字符串。 您可以将所有这些最后的数字添加到列表中。 处理此列表,最后写入文件。