Writing data into CSV file in C#

后端 未结 15 1202
清酒与你
清酒与你 2020-11-22 17:15

I am trying to write into a csv file row by row using C# language. Here is my function

string first = reader[0].ToString();
string second=image.         


        
相关标签:
15条回答
  • 2020-11-22 17:30

    One simple way to get rid of the overwriting issue is to use File.AppendText to append line at the end of the file as

    void Main()
    {
        using (System.IO.StreamWriter sw = System.IO.File.AppendText("file.txt"))
        {          
            string first = reader[0].ToString();
            string second=image.ToString();
            string csv = string.Format("{0},{1}\n", first, second);
            sw.WriteLine(csv);
        }
    } 
    
    0 讨论(0)
  • 2020-11-22 17:32

    I use a two parse solution as it's very easy to maintain

    // Prepare the values
    var allLines = (from trade in proposedTrades
                    select new object[] 
                    { 
                        trade.TradeType.ToString(), 
                        trade.AccountReference, 
                        trade.SecurityCodeType.ToString(), 
                        trade.SecurityCode, 
                        trade.ClientReference, 
                        trade.TradeCurrency, 
                        trade.AmountDenomination.ToString(), 
                        trade.Amount, 
                        trade.Units, 
                        trade.Percentage, 
                        trade.SettlementCurrency, 
                        trade.FOP, 
                        trade.ClientSettlementAccount, 
                        string.Format("\"{0}\"", trade.Notes),                             
                    }).ToList();
    
    // Build the file content
    var csv = new StringBuilder();
    allLines.ForEach(line => 
    {
        csv.AppendLine(string.Join(",", line));            
    });
    
    File.WriteAllText(filePath, csv.ToString());
    
    0 讨论(0)
  • 2020-11-22 17:32

    Handling Commas

    For handling commas inside of values when using string.Format(...), the following has worked for me:

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

    So to combine it with Johan's answer, it'd look like this:

    //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());
    

    Returning CSV File

    If you simply wanted to return the file instead of writing it to a location, this is an example of how I accomplished it:

    From a Stored Procedure

    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");
    }
    

    From a List

    /* 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");
    }
    

    Hopefully this is helpful.

    0 讨论(0)
  • 2020-11-22 17:33

    Here is another open source library to create CSV file easily, Cinchoo ETL

    List<dynamic> objs = new List<dynamic>();
    
    dynamic rec1 = new ExpandoObject();
    rec1.Id = 10;
    rec1.Name = @"Mark";
    rec1.JoinedDate = new DateTime(2001, 2, 2);
    rec1.IsActive = true;
    rec1.Salary = new ChoCurrency(100000);
    objs.Add(rec1);
    
    dynamic rec2 = new ExpandoObject();
    rec2.Id = 200;
    rec2.Name = "Tom";
    rec2.JoinedDate = new DateTime(1990, 10, 23);
    rec2.IsActive = false;
    rec2.Salary = new ChoCurrency(150000);
    objs.Add(rec2);
    
    using (var parser = new ChoCSVWriter("emp.csv").WithFirstLineHeader())
    {
        parser.Write(objs);
    }
    

    For more information, please read the CodeProject article on usage.

    0 讨论(0)
  • 2020-11-22 17:34

    UPDATE

    Back in my naïve days, I suggested doing this manually (it was a simple solution to a simple question), however due to this becoming more and more popular, I'd recommend using the library CsvHelper that does all the safety checks, etc.

    CSV is way more complicated than what the question/answer suggests.

    Original Answer

    As you already have a loop, consider doing it like this:

    //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());
    

    Or something to this effect. My reasoning is: you won't be need to write to the file for every item, you will only be opening the stream once and then writing to it.

    You can replace

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

    with

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

    if you want to keep previous versions of csv in the same file

    C# 6

    If you are using c# 6.0 then you can do the following

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

    EDIT

    Here is a link to a question that explains what Environment.NewLine does.

    0 讨论(0)
  • 2020-11-22 17:34

    I would highly recommend you to go the more tedious route. Especially if your file size is large.

    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() opens a new file, writes the content and then closes the file. Opening files is a much resource-heavy operation, than writing data into open stream. Opening\closing a file inside a loop will cause performance drop.

    The approach suggested by Johan solves that problem by storing all the output in memory and then writing it once. However (in case of big files) you program will consume a large amount of RAM and even crash with OutOfMemoryException

    Another advantage of my solution is that you can implement pausing\resuming by saving current position in input data.

    upd. Placed using in the right place

    0 讨论(0)
提交回复
热议问题