是否可以在不知道其余部分的情况下更新CSV文件的一部分?

时间:2011-05-04 22:04:59

标签: .net csv

在我正在处理的项目中,我需要从CSV文件中读取,更新每行上的字段,然后将结果保存回CSV文件。我正在寻找一个可以帮助我的图书馆。

我的第一次尝试是使用ADO。这有点像阅读的魅力,但当我尝试更新文件时,我收到错误“此ISAM不支持更新链接表中的数据。”

所以现在我正在寻找替代品(或解决方法)。这些是我的要求:

  1. 我宁愿不定义文件中的每一列。我只需要两列,并担心将来可能会添加其他列。

  2. 我需要能够保留(或至少复制)列标题信息。

  3. 我希望尽可能少了解底层格式/文件(即我不想从头开始编写CSV编写器)。

  4. 我遇到过许多替代读者和几位作家......但是作者都将CSV文件读入预定义的字段集,然后只将这些字段写回新的文件。我想尽量减少硬编码到我的程序中的列结构的信息量。

4 个答案:

答案 0 :(得分:2)

现代文件系统的工作方式只有在新数据与原始数据完全相同时才能更新任何文件。否则,您必须从头开始重写整个文件。如果您可以满足此约束,则可以使用低级文件流。我不知道一个csv软件包支持这个我的头脑,但原因是csv很简单,你可以自己做。

也就是说,如果你要更新每一行,那么重写文件可能并不是什么大不了的事。编写csv记录非常简单。请注意以下C#代码:

public WriteRecord(IEnumerable items, TextWriter outputStream))
{
    string delimiter = "";
    foreach(var item in items)
    {
        outputStream.Write(delimiter);
        outputStream.Write("\"");
        outputStream.Write(item.ToString().Replace("\"", "\"\""));
        outputStream.Write("\"");
        delimiter = ",";
    }
    outputStream.Write(Environment.Newline);
}

当然,如果你想要更复杂的复杂类型,那很好,但是因为你不想将自己限制在特定的未来列安排上,所以这段代码应该没问题。此外,它将补充我自己的CSV parser listed here on Stack Overflow,它不需要提前知道文件中的列。你可以这样做:

var tempPath = @"Some-temp-file-path.csv";
var srcPath = @"input-file-path.csv";
using (var outFile = new StreamWriter(tempPath))
{
    foreach (var items in CSV.FromFile(srcPath))
    {
        items[someInt] = "new value";
        items[otherInt] = "other value";
        WriteRecord(items, outFile);
    }

}
File.Copy(tempPath, srcPath);

答案 1 :(得分:1)

.csv文件是一个平面文件,据我所知,你无法更新文件,除非你有一些方法,比如索引文件系统。

建议将.csv文件读入您​​的程序。

将其存储到SQL Lite或足够的堆内存等数据库中,以保存文件的长度和一些额外的空间来保存更改。

进行更改。

写出文件。

我遗漏了很多关于如何进行更新的细节。希望有很多文件经验的人可以纠正我对你应该做的事情的看法。可能有些Microsoft数据库对象库可以执行此操作,但我不熟悉它们。

答案 2 :(得分:1)

如果您使用的是C#4.0,那么即使您无法锁定单行,File类中也有一些很好的扩展可以帮助您重写csv文件。您应该查看File.ReadLinesFile.WriteAllLines。它们都将IEnumerable作为参数,因此您可以在每行的基础上执行转换。尽管这并不意味着您没有锁定文件,但内存密集程度肯定低于将整个文件保存在内存中。

var lines = File.ReadLines(oldFile);
File.WriteAllLines(newFile, ChangeCSV(lines));

public IEnumerable<string> ChangeCSV(IEnumerable<string> csvLines)
{
  foreach(var line in csvLines)
  {    
    var convertedLine = ... // Do your conversion here for a single line
    yield return convertedLine;
  }
}

编辑:如果您正在寻找一种快速解析csv行的方法,那么this regex expression可以为您解决问题。

答案 3 :(得分:0)

CSV文件是无类型的字符流,因此可以替换单个字符,但不能在不重写整个文件的情况下添加或删除字符。

我强烈建议,根据个人经验,创建一个简单的CSV解析器,如@Joel建议的那样,并为每次更新重新创建整个文件。如果出现错误,尝试就地更新数据很容易破坏整个文件。

请按照以下步骤操作:

  1. 逐字段读取文件。
  2. 如果它是您不关心的字段,请将其添加到临时文件中。
  3. 如果它是您关心的字段,请将新值写入临时文件。
  4. 如果收到错误,请删除临时文件。
  5. 如果没有错误,请交换临时文件和原始文件并删除旧文件。