0

我正在尝试在 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。我不希望在文件末尾追加。我希望从每行中获取最后一个数字,然后将修改后的数据放回原处。我希望其余数据保持不变。我该怎么做?

4

6 回答 6

3

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

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

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

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

于 2013-10-16T17:20:41.687 回答
1

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

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

于 2013-10-16T17:25:32.067 回答
1

为什么不用 读取文件,用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);
于 2013-10-16T17:27:08.620 回答
1

应该像这样简单:

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);
于 2013-10-16T17:32:33.063 回答
0

要读取和保存文件:

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);
于 2013-10-16T17:25:27.893 回答
0

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

于 2013-10-16T17:27:32.097 回答