我试图用c#语言一行一行地写入csv文件。这是我的函数

string first = reader[0].ToString();
string second=image.ToString();
string csv = string.Format("{0},{1}\n", first, second);
File.WriteAllText(filePath, csv);

整个函数在循环中运行,每一行都应该写入csv文件。在我的例子中,下一行覆盖了现有的行,最后,我在csv文件中只得到一条记录,这是最后一条记录。如何写入csv文件中的所有行?


当前回答

处理逗号

对于在使用string.Format(…)时处理值中的逗号,以下方法对我有用:

var newLine = string.Format("\"{0}\",\"{1}\",\"{2}\"",
                              first,
                              second,
                              third                                    
                              );
csv.AppendLine(newLine);

所以把它和约翰的答案结合起来,看起来是这样的:

//before your loop
var csv = new StringBuilder();

//in your loop
  var first = reader[0].ToString();
  var second = image.ToString();
  //Suggestion made by KyleMit
  var newLine = string.Format("\"{0}\",\"{1}\"", first, second);
  csv.AppendLine(newLine);  

//after your loop
File.WriteAllText(filePath, csv.ToString());

返回CSV文件

如果你只是想返回文件,而不是把它写到一个位置,这是我如何完成它的一个例子:

从存储过程

public FileContentResults DownloadCSV()
{
  // I have a stored procedure that queries the information I need
  SqlConnection thisConnection = new SqlConnection("Data Source=sv12sql;User ID=UI_Readonly;Password=SuperSecure;Initial Catalog=DB_Name;Integrated Security=false");
  SqlCommand queryCommand = new SqlCommand("spc_GetInfoINeed", thisConnection);
  queryCommand.CommandType = CommandType.StoredProcedure;

  StringBuilder sbRtn = new StringBuilder();

  // If you want headers for your file
  var header = string.Format("\"{0}\",\"{1}\",\"{2}\"",
                             "Name",
                             "Address",
                             "Phone Number"
                            );
  sbRtn.AppendLine(header);

  // Open Database Connection
  thisConnection.Open();
  using (SqlDataReader rdr = queryCommand.ExecuteReader())
  {
    while (rdr.Read())
    {
      // rdr["COLUMN NAME"].ToString();
      var queryResults = string.Format("\"{0}\",\"{1}\",\"{2}\"",
                                        rdr["Name"].ToString(),
                                        rdr["Address"}.ToString(),
                                        rdr["Phone Number"].ToString()
                                       );
      sbRtn.AppendLine(queryResults);
    }
  }
  thisConnection.Close();

  return File(new System.Text.UTF8Encoding().GetBytes(sbRtn.ToString()), "text/csv", "FileName.csv");
}

从列表中

/* To help illustrate */
public static List<Person> list = new List<Person>();

/* To help illustrate */
public class Person
{
  public string name;
  public string address;
  public string phoneNumber;
}

/* The important part */
public FileContentResults DownloadCSV()
{
  StringBuilder sbRtn = new StringBuilder();

  // If you want headers for your file
  var header = string.Format("\"{0}\",\"{1}\",\"{2}\"",
                             "Name",
                             "Address",
                             "Phone Number"
                            );
  sbRtn.AppendLine(header);

  foreach (var item in list)
  {
      var listResults = string.Format("\"{0}\",\"{1}\",\"{2}\"",
                                        item.name,
                                        item.address,
                                        item.phoneNumber
                                       );
      sbRtn.AppendLine(listResults);
    }
  }

  return File(new System.Text.UTF8Encoding().GetBytes(sbRtn.ToString()), "text/csv", "FileName.csv");
}

希望这对你们有帮助。

其他回答

public static class Extensions
{
    public static void WriteCSVLine(this StreamWriter writer, IEnumerable<string> fields)
    {
        const string q = @"""";
        writer.WriteLine(string.Join(",",
            fields.Select(
                v => (v.Contains(',') || v.Contains('"') || v.Contains('\n') || v.Contains('\r')) ? $"{q}{v.Replace(q, q + q)}{q}" : v
                )));
    }

    public static void WriteCSVLine(this StreamWriter writer, params string[] fields) => WriteCSVLine(writer, (IEnumerable<string>)fields);
}

这将允许您非常简单地编写csv文件。用法:

StreamWriter writer = new ("myfile.csv");
writer.WriteCSVLine("A", "B"); // A,B

我强烈建议你走更乏味的路线。尤其是当你的文件很大的时候。

using(var w = new StreamWriter(path))
{
    for( /* your loop */)
    {
        var first = yourFnToGetFirst();
        var second = yourFnToGetSecond();
        var line = string.Format("{0},{1}", first, second);
        w.WriteLine(line);
        w.Flush();
    }
}

file. appendalltext()打开一个新文件,写入内容,然后关闭文件。与将数据写入开放流相比,打开文件是一个耗费大量资源的操作。在循环中打开/关闭文件会导致性能下降。

Johan建议的方法解决了这个问题,方法是将所有输出存储在内存中,然后只写入一次。然而(在大文件的情况下),您的程序将消耗大量的RAM,甚至崩溃与OutOfMemoryException

我的解决方案的另一个优点是,您可以通过保存输入数据中的当前位置来实现暂停/恢复。

乌利希期刊指南。把使用放在正确的地方

手动编写csv文件可能很困难,因为数据可能包含逗号和换行符。我建议您使用现有的库。

这个问题提到了几个选项。

c#中有CSV读取器/写入器库吗?

更新

回到我的naïve时代,我建议手动做这件事(这是一个简单问题的简单解决方案),然而由于这变得越来越流行,我建议使用库CsvHelper来做所有的安全检查,等等。

CSV比问题/答案所暗示的要复杂得多。

原来的答案

因为你已经有了一个循环,考虑这样做:

//before your loop
    var csv = new StringBuilder();

//in your loop
    var first = reader[0].ToString();
    var second = image.ToString();
    //Suggestion made by KyleMit
    var newLine = string.Format("{0},{1}", first, second);
    csv.AppendLine(newLine);  

//after your loop
    File.WriteAllText(filePath, csv.ToString());

或者类似的东西。 我的理由是:你不需要为每一项写入文件,你只需要打开流一次,然后写入它。

你可以替换

File.WriteAllText(filePath, csv.ToString());

File.AppendAllText(filePath, csv.ToString());

如果您希望将CSV的以前版本保存在同一文件中

C# 6

如果您正在使用c# 6.0,那么您可以执行以下操作

var newLine = $"{first},{second}"

EDIT

这里有一个问题的链接,解释了什么环境。换行符。

你可以使用AppendAllText代替:

File.AppendAllText(filePath, csv);

正如WriteAllText的文档所说:

如果目标文件已经存在,那么它将被覆盖

此外,请注意您当前的代码没有使用适当的新行,例如在记事本中,您将看到它都是一个长行。将代码更改为这样,以获得正确的新行:

string csv = string.Format("{0},{1}{2}", first, image, Environment.NewLine);