C # 'da CSV dosyasına veri yazma


198

csvC # dilini kullanarak satır satır bir dosyaya yazmaya çalışıyorum . İşte benim fonksiyonum

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

Tüm işlev bir döngü içinde çalışır ve her satır csvdosyaya yazılmalıdır . Benim durumumda, sonraki satır mevcut satırın üzerine yazar ve sonunda, son olan csv dosyasında tek bir kayıt alıyorum. csvDosyadaki tüm satırları nasıl yazabilirim ?


A yerine kullanın StringBuilderve sonra bir tasarruf yapmak?
Johan

1
Bu, günlük olarak yerine getirmeniz gereken bir görev değilse, bir csv'ye veri yazmak için kullanışlı bir işlevle gelen LinqPad kullanmanızı öneririz:Util.WriteCsv (mydatacollection, @"c:\temp\data.csv");
Marco

3
Yan notta, csv değerlerinizin kodlandığından emin olun. Yani bunlardan biri virgül veya satır sonu karakteri içeriyorsa dosyanızı bozabilir. Genellikle csv şeyler için üçüncü taraf bir lib kullanıyorum.
Matthijs Wessels

@MatthijsWessels Herhangi bir kütüphane önerisi var mı?
Arash Motamedi

Yanıtlar:


313

GÜNCELLEME

Geri naif günlerimde, bunu manuel olarak yapmayı önerdim ( basit bir soru için basit bir çözümdü), ancak bu daha popüler hale gelmesi nedeniyle , tüm güvenlik kontrollerini yapan CsvHelper kütüphanesini kullanmanızı tavsiye ederim .

CSV, sorunun / cevabın önerdiğinden çok daha karmaşıktır.

Orijinal Yanıt

Zaten bir döngünüz olduğu için, bunu şu şekilde yapmayı düşünün:

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

Ya da bu etki için bir şey. Benim nedenim: her öğe için dosyaya yazmanız gerekmeyecek, akışı yalnızca bir kez açıp üzerine yazacaksınız.

Değiştirebilirsiniz

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

ile

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

csv'nin önceki sürümlerini aynı dosyada tutmak istiyorsanız

C # 6

C # 6.0 kullanıyorsanız, aşağıdakileri yapabilirsiniz

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

DÜZENLE

İşte ne olduğunu açıklayan bir soru bağlantısıEnvironment.NewLine .


1
@Rajat no, çünkü 2 yeni bir satır
Johan

4
Ayrıca kurtulabilir {2}ve yerine Environment.NewLinekullanabilirsinizAppendLineAppend
KyleMit

37
Ve CSV içeriğinizin kaçması gereken bir virgül olduğunda ne olur? Alıntılara ihtiyacınız var. Ve bir teklifin kaçması gerektiğinde ne olur? CSV dosyalarını doğru bir şekilde oluşturmak, bu cevabın ima ettiğinden çok daha karmaşıktır.
MgSam

1
Bir "exceptionType" aldım: "System.UnauthorizedAccessException",
Chit Khine

3
Çözümünüzü denedim, ama benim için (fransız kültürü) System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparatorvirgül yerine daha iyi çalışıyor .
A.Pissicat

89

Çok daha sıkıcı bir rotaya gitmenizi tavsiye ederim. Özellikle dosya boyutunuz büyükse.

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()yeni bir dosya açar, içeriği yazar ve sonra dosyayı kapatır. Dosyaları açmak, veriyi açık akışa yazmaktan çok kaynak ağırlıklı bir işlemdir. Bir dosyayı döngü içinde açmak / kapatmak performans düşüşüne neden olur.

Johan'ın önerdiği yaklaşım bu sorunu tüm çıktıları hafızaya kaydedip bir kez yazarak çözer. Ancak (büyük dosyalar için) program büyük miktarda RAM tüketecek ve hatta çökecekOutOfMemoryException

Çözümümün bir diğer avantajı, giriş verilerindeki geçerli konumu kaydederek duraklatma \ devam ettirme uygulayabilmenizdir.

Post. Kullanarak doğru yere yerleştirilmiş


1
Sen bir döngü için koymalıyız using açıklamada. Aksi takdirde dosyayı tekrar tekrar açacaksınız.
Oliver

2
İyi cevap. Biçim dizesinden "{2}" öğesini kaldırır ve "image" ifadesini aynı satırda "second" ile değiştirirseniz, yanıtı düzeltin. Ayrıca, yazarı w.Close () ile kapatmayı unutmayın; w.Flush () gerekli değildir.
movAX13h

6
Bu cevap karakterlerden kaçma ihtiyacını yok sayar.
MgSam

Ayrıca, yazarınızı şu şekilde ayarlamanıza yardımcı olduğunu ekleyebilir miyiz: yeni StreamWriter (yol, yanlış,
Kodlama.UTF8

birkaç yüz milyon hattınız varsa ... her hattı yıkamalı mısınız?
Ardianto Suhendar


17

Bakımı çok kolay olduğu için iki ayrıştırma çözümü kullanıyorum

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

1
Büyük dosyalar oluştururken bu yaklaşımla bellek baskısıyla karşılaşabilirsiniz. .ToList öğesini kaldırdıysanız, allLines bir IEnumerbale <nesnesi []> olur. Daha sonra "hering için" yerine allines yerine bunu seçebilirsiniz, (I = En <erable> dizesi verecek olan (line => csv.AppendLine (string.Join (",", line))) öğesini seçin. Bu artık Dosyaya ancak WriteAllLines yöntemine aktarılabilir. Bu, artık her şeyin tembel olduğu ve her şeyi belleğe çekmeniz gerekmediği anlamına geliyor, ancak yine de memnun olduğunuz sözdizimini alıyorsunuz.
RhysC

Ben bir csv dosyasına yazmak için yöntemini kullanıyorum. Bu harika! En son uygulamam File.AppendAllLines(filePath, lines, Encoding.ASCII);yerine kullanmamı gerektiriyor . File.WriteAllText(filePath, csv.ToString()); Yani, çok aksak bir şey yapıyorum. StringBuilder kullanarak csv oluşturduktan sonra csv.ToString () parametre olarak kabul etmeyecek AppendAllLines çağrısı için bir IEnumerable almak için bir List <string> dönüştürmek: Bunu yapmak için List<string> lines = new List<string>(); lines.Add(csv.ToString(0, csv.Length));daha iyi bir yolu var mı?
Patricia

12

Her seferinde çağırmak yerine AppendAllText()dosyayı bir kez açmayı düşünebilir ve ardından tüm içeriği bir kez yazabilirsiniz:

var file = @"C:\myOutput.csv";

using (var stream = File.CreateText(file))
{
    for (int i = 0; i < reader.Count(); i++)
    {
        string first = reader[i].ToString();
        string second = image.ToString();
        string csvRow = string.Format("{0},{1}", first, second);

        stream.WriteLine(csvRow);
    }
}

@ aMazing: Üzgünüm, bir yazım hatası. Şimdi düzeltildi.
Oliver

Bu yanıt, uzantının csv olması gerektiğini içerir. Eğer xls ise, verilerin tümü bir sütunda görünecektir ... csv her sütunda doğru bir şekilde görünecektir.
gman

11

Bunun yerine AppendAllText kullanın:

File.AppendAllText(filePath, csv);

AppendAllText öğesinin tek dezavantajı, dosya olmadığında hata atmasıdır, bu yüzden bu işaretlenmelidir

Üzgünüm, belgeleri okumadan önce sarışın an . Her neyse, WriteAllText yöntemi, dosya varsa önceden dosyaya yazılan her şeyin üzerine yazar.

Mevcut kodunuzun uygun yeni satırlar kullanmadığını unutmayın, örneğin Not Defteri'nde hepsini tek bir uzun satır olarak göreceksiniz. Doğru yeni satırlara sahip olmak için kodu şu şekilde değiştirin:

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

2
@Rajat no, bu görüntü verilerinizin hemen ardından yeni satır karakterini yazacaktır.
Gölge Sihirbazı Sizin İçin

7

Tekerleği yeniden icat etmek yerine bir kütüphane kullanılabilir. CsvHelpercsv dosyaları oluşturmak ve okumak için mükemmeldir. Okuma ve yazma işlemleri akış tabanlıdır ve bu nedenle büyük miktarda veri içeren işlemleri de destekler.


Csv'nizi aşağıdaki gibi yazabilirsiniz.

using(var textWriter = new StreamWriter(@"C:\mypath\myfile.csv"))
{
    var writer = new CsvWriter(textWriter, CultureInfo.InvariantCulture);
    writer.Configuration.Delimiter = ",";

    foreach (var item in list)
    {
        writer.WriteField( "a" );
        writer.WriteField( 2 );
        writer.WriteField( true );
        writer.NextRecord();
    }
}

Kütüphane yansıma kullandığından, herhangi bir türü alır ve doğrudan ayrıştırır.

public class CsvRow
{
    public string Column1 { get; set; }
    public bool Column2 { get; set; }

    public CsvRow(string column1, bool column2)
    {
        Column1 = column1;
        Column2 = column2;
    }
}

IEnumerable<CsvRow> rows = new [] {
    new CsvRow("value1", true),
    new CsvRow("value2", false)
};
using(var textWriter = new StreamWriter(@"C:\mypath\myfile.csv")
{
    var writer = new CsvWriter(textWriter, CultureInfo.InvariantCulture);
    writer.Configuration.Delimiter = ",";
    writer.WriteRecords(rows);
}

değer1 gerçek

deger2, yalancı


Kütüphanecilerin yapılandırmaları ve olasılıkları hakkında daha fazla bilgi edinmek isterseniz, burada yapabilirsiniz .


Bunun çalışması için CultureInfo'yu StreamWriter'a iletmeniz gerekebilir.
alif

6
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;

public partial class CS : System.Web.UI.Page
{
    protected void ExportCSV(object sender, EventArgs e)
    {
        string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
        using (SqlConnection con = new SqlConnection(constr))
        {
            using (SqlCommand cmd = new SqlCommand("SELECT * FROM Customers"))
            {
                using (SqlDataAdapter sda = new SqlDataAdapter())
                {
                    cmd.Connection = con;
                    sda.SelectCommand = cmd;
                    using (DataTable dt = new DataTable())
                    {
                        sda.Fill(dt);

                        //Build the CSV file data as a Comma separated string.
                        string csv = string.Empty;

                        foreach (DataColumn column in dt.Columns)
                        {
                            //Add the Header row for CSV file.
                            csv += column.ColumnName + ',';
                        }

                        //Add new line.
                        csv += "\r\n";

                        foreach (DataRow row in dt.Rows)
                        {
                            foreach (DataColumn column in dt.Columns)
                            {
                                //Add the Data rows.
                                csv += row[column.ColumnName].ToString().Replace(",", ";") + ',';
                            }

                            //Add new line.
                            csv += "\r\n";
                        }

                        //Download the CSV file.
                        Response.Clear();
                        Response.Buffer = true;
                        Response.AddHeader("content-disposition", "attachment;filename=SqlExport.csv");
                        Response.Charset = "";
                        Response.ContentType = "application/text";
                        Response.Output.Write(csv);
                        Response.Flush();
                        Response.End();
                    }
                }
            }
        }
    }
}

neden burada string-builder yok?
Seabizkit

1
Bunu yazmak için hangi RFC'yi kullandınız .Replace(",", ";") + ',' ?
vt100


3

Virgüllerle Çalışma

Kullanırken değerlerin içindeki virgüllerle başa çıkmak string.Format(...)için aşağıdakiler benim için çalıştı:

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

Bu yüzden Johan'ın cevabı ile birleştirmek şöyle olurdu:

//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 Dosyasını Döndürme

Dosyayı bir konuma yazmak yerine döndürmek istiyorsanız, bu dosyayı nasıl başardığımın bir örneğidir:

Saklı Yordamdan

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

Listeden

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

Umarım bu yardımcı olur.


2

Bu, kendi gereksinimlerinize uyacak şekilde düzenleyebileceğiniz ve genişletebileceğiniz C # kullanarak csv dosyaları oluşturma konusunda basit bir öğreticidir.

Öncelikle yeni bir Visual Studio C # konsol uygulaması oluşturmanız gerekir, bunu yapmak için izlenmesi gereken adımlar vardır.

Örnek kod, belirttiğiniz konumda MyTest.csv adlı bir csv dosyası oluşturur. Dosyanın içeriği ilk 3 satırda metin içeren 3 adlandırılmış sütun olmalıdır.

https://tidbytez.com/2018/02/06/how-to-create-a-csv-file-with-c/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace CreateCsv
{
    class Program
    {
        static void Main()
        {
            // Set the path and filename variable "path", filename being MyTest.csv in this example.
            // Change SomeGuy for your username.
            string path = @"C:\Users\SomeGuy\Desktop\MyTest.csv";

            // Set the variable "delimiter" to ", ".
            string delimiter = ", ";

            // This text is added only once to the file.
            if (!File.Exists(path))
            {
                // Create a file to write to.
                string createText = "Column 1 Name" + delimiter + "Column 2 Name" + delimiter + "Column 3 Name" + delimiter + Environment.NewLine;
                File.WriteAllText(path, createText);
            }

            // This text is always added, making the file longer over time
            // if it is not deleted.
            string appendText = "This is text for Column 1" + delimiter + "This is text for Column 2" + delimiter + "This is text for Column 3" + delimiter + Environment.NewLine;
            File.AppendAllText(path, appendText);

            // Open the file to read from.
            string readText = File.ReadAllText(path);
            Console.WriteLine(readText);
        }
    }
}

2
Bir çözümün bağlantısı hoş karşılanır, ancak lütfen cevabınızın onsuz faydalı olduğundan emin olun: bağlantınızın çevresine bağlam ekleyin, böylece diğer kullanıcılarınız ne olduğu ve neden orada olduğu hakkında bir fikir sahibi olacak, ardından sayfanın en alakalı bölümünü alıntılayacağız ' hedef sayfanın kullanılamaması durumunda bağlantı kuruluyor. Bir bağlantıdan biraz daha fazlası olan yanıtlar silinebilir.
Shree

Ah, anlıyorum. Geri dönüşünüz için teşekkür ederiz. Değişiklikleri vurguladım. Lütfen oy verin.
Bloggins


0

İşte kolayca CSV dosyası oluşturmak için başka bir açık kaynak kütüphanesi, 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);
}

Daha fazla bilgi için lütfen kullanım ile ilgili CodeProject makalesini okuyun .


0

Üzerine yazma sorunundan kurtulmanın basit bir yolu File.AppendText, dosyanın sonuna satır eklemek için kullanmaktır .

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
enter code here

string string_value = string.Empty;

        for (int i = 0; i < ur_grid.Rows.Count; i++)
        {
            for (int j = 0; j < ur_grid.Rows[i].Cells.Count; j++)
            {
                if (!string.IsNullOrEmpty(ur_grid.Rows[i].Cells[j].Text.ToString()))
                {
                    if (j > 0)
                        string_value= string_value+ "," + ur_grid.Rows[i].Cells[j].Text.ToString();
                    else
                    {
                        if (string.IsNullOrEmpty(string_value))
                            string_value= ur_grid.Rows[i].Cells[j].Text.ToString();
                        else
                            string_value= string_value+ Environment.NewLine + ur_grid.Rows[i].Cells[j].Text.ToString();
                    }
                }
            }
        }


        string where_to_save_file = @"d:\location\Files\sample.csv";
        File.WriteAllText(where_to_save_file, string_value);

        string server_path = "/site/Files/sample.csv";
        Response.ContentType = ContentType;
        Response.AppendHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(server_path));
        Response.WriteFile(server_path);
        Response.End();

0
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 WriteFields(this StreamWriter writer, params string[] fields) => WriteFields(writer, (IEnumerable<string>)fields);
}

Bu, oldukça basit bir şekilde bir csv dosyası yazmanıza izin vermelidir. Kullanımı:

StreamWriter writer = new StreamWriter("myfile.csv");
writer.WriteCSVLine(new[]{"A", "B"});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.