【问题标题】:C# Read and Write to the same fileC#读取和写入同一个文件
【发布时间】:2014-05-26 13:12:26
【问题描述】:

我正在经历一个循环,对于每次运行,我都希望打开一个 txt/csv 文件并搜索在循环中分配的值。如果该值存在于 txt 文件中,我希望在该行上写入它。

这可以吗?我一直在玩 StreamReader 和 StreamWriter,但从未真正成功地读取和写入同一个文件。

我一开始尝试过,但显然 StreamReader 使文件“忙”,因此 StreamWriter 无法访问它。

private void WriteTempTXT()
{

    StreamReader sr = new StreamReader(@tmpfile);
    StreamWriter sw = new StreamWriter(@tmpfile);

}

有没有办法做到这一点?

【问题讨论】:

标签: c# file


【解决方案1】:

首先,可以做到。您可以创建具有读/写访问权限的FileStream,然后直接写入流。这是一个概念证明:

using (var v = new StreamWriter(File.Create("a.txt"))) {
    v.WriteLine("1234A67890");
}

FileStream fs = new FileStream("a.txt", FileMode.Open, FileAccess.ReadWrite);
while (fs.ReadByte() != 'A') {} // Dangerous.  Loops until 'A' found, infinite loop if none.
fs.Position--;
fs.WriteByte((byte)'5');
fs.Close();  // contents of a.txt now 1234567890

但是,这种方法存在许多基本问题:

  1. 文件损坏的风险。如果程序崩溃(或断电等),文件可能会处于不一致的状态。
  2. 无法始终使用StreamReader/StreamWriter。 两者都将数据存储在内部缓冲区中,如果同时写入和读取底层流,该缓冲区可能会变得陈旧。您可以致电 DiscardBufferedData,但 MSDN 指出“此方法会降低性能,仅在绝对必要时才应调用。”
  3. 复杂性。在文件中就地插入文本是一项昂贵的操作,需要将所有后续数据转移到内存中。

相反,除非有压倒性的考虑(例如,文件相对于可用存储空间很大),否则您可能需要考虑这种方法:

  1. 创建一个新的临时文件。 (您可以为此使用System.IO.Path.GetTempFileName())。
  2. 将现有文件读入临时文件,进行必要的更改。 (使用StreamReader 读取旧文件,使用StreamWriter 写入新文件。)
  3. 用临时文件覆盖现有文件。

此方法在概念上相似,但不会产生同时读取和写入同一流的风险和复杂性。

【讨论】:

    【解决方案2】:

    在 CSV 文件中写入一行有两个问题:

    1. 文件不是基于行的。如果新行的编码数据与原始行的字节数完全相同,则只能替换文件中的一行。

    2. CSV 数据不是基于行的。换行符用作记录分隔符,但由于值也可以包含换行符,因此您无法可靠地逐行读取 CSV 文件(除非在特殊情况下您确定任何值都不会包含新的行)。

    如果新行的编码数据与旧行的长度不同,那么您必须重写文件的其余部分,以便为添加的字节腾出空间或删除未使用的字节。

    通常的做法是读取整个文件并将其解析成记录,更改记录,然后将整个文件写回。

    【讨论】:

    • 这样做 15000 次,我们在这里谈论的性能方面是什么?
    • 我不同意 (2),在处理 csv 文件时,您可以安全地使用 ReadLine()。不过不确定不同的编码。
    • @Sinatr:你错了。例如,如果您尝试读取记录 1,2,"Hello\r\nworld",ReadLine 方法将为您提供部分记录 1,2,"Hello。
    • @user3218338:读写15000个文件,自然需要很长时间。如果您一遍又一遍地更改同一个文件,那么您自然应该阅读一次,进行所有更改,并在完成后将其写回。
    • @Guffa,哦,没有考虑将换行符作为内容的一部分(并且似乎无法正确阅读写入)。那么是的,你是对的。我用.Replace("\xd\xa", "\\n") 替换字符串中的换行符,然后返回.Replace("\\n", "\xd\xa")。
    【解决方案3】:

    首先你需要跟进这个Example

    然后使用类

    string path = Server.MapPath("Twitter Overview Report1.csv"); 
        using (CsvFileReader reader = new CsvFileReader(path))
        {
            CsvRow row = new CsvRow();
            while (reader.ReadRow(row))
            {
                foreach (string s in row)
                {
                    string s_row = row[0].ToString();
                    s_row.Replace("mahmoude", "Ghandour");
                }
                Console.WriteLine();
            }
        }
        using (CsvFileWriter writer = new CsvFileWriter(path))
        {
    
        }
    

    【讨论】:

      猜你喜欢
      • 2011-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多