C #에서 CSV 파일로 데이터 쓰기


198

csvC # 언어를 사용하여 행 단위로 파일 에 쓰려고 합니다. 여기 내 기능이 있습니다

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파일의 모든 행을 어떻게 쓸 수 있습니까?


오히려 a StringBuilder를 사용한 다음 하나를 저장 하시겠습니까?
Johan

1
이것이 매일 수행해야하는 작업이 아닌 경우 LinqPad를 사용하는 것이 좋습니다. LinqPad를 사용하면 csv에 데이터를 쓰는 편리한 기능이 제공됩니다.Util.WriteCsv (mydatacollection, @"c:\temp\data.csv");
Marco

3
참고로 csv 값이 인코딩되어 있는지 확인하십시오. 즉, 그중 하나에 쉼표 또는 줄 끝 문자가 포함되어 있으면 파일이 엉망이 될 수 있습니다. 나는 보통 csv에 타사 라이브러리를 사용합니다.
Matthijs Wessels

@MatthijsWessels 라이브러리 제안이 있습니까?
Arash Motamedi

답변:


313

최신 정보

순진한 시절에, 나는 이것을 수동으로 제안하는 것이 좋습니다 (단순한 질문에 대한 간단한 해결책이었습니다). 그러나 이것이 점점 더 인기를 끌기 때문에 모든 안전 점검 등을 수행 하는 라이브러리 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}"

편집하다

다음은 무엇을 설명하는 질문에 대한 링크Environment.NewLine 입니다.


1
@Rajat no, 2는 새로운 라인이기 때문에
Johan

4
{2}Environment.NewLineAppendLineAppend
KyleMit

37
CSV 콘텐츠에 이스케이프 처리해야하는 쉼표가 있으면 어떻게됩니까? 따옴표가 필요합니다. 따옴표를 탈출해야하는 경우 어떻게됩니까? CSV 파일을 올바르게 작성하는 것은이 답변이 의미하는 것보다 훨씬 복잡합니다.
MgSam

1
"exceptionType": "System.UnauthorizedAccessException"
Chit Khine

3
귀하의 솔루션을 시도했지만 나 (프랑스 문화)의 경우 System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator쉼표 대신에 더 잘 작동합니다 .
A.Pissicat

89

더 지루한 길을가는 것이 좋습니다. 특히 파일 크기가 큰 경우.

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

내 솔루션의 또 다른 장점은 입력 데이터에 현재 위치를 저장하여 일시 중지 / 다시 시작을 구현할 수 있다는 것입니다.

올라 갔다. 올바른 장소에 배치


1
당신은 루프 당신을 놓아야 내부using 문. 그렇지 않으면 파일을 계속해서 다시 열 것입니다.
올리버

2
좋은 대답입니다. 형식 문자열에서 "{2}"를 제거하고 같은 줄에서 "image"를 "second"로 바꾸면 정답입니다. 또한 w.Close ();를 사용하여 작성기를 닫는 것을 잊지 마십시오. w.Flush ()는 필요하지 않습니다.
movAX13h

6
이 답변은 문자를 이스케이프해야 할 필요성을 무시합니다.
MgSam

새로운 StreamWriter (path, false, Encoding.UTF8)
Charkins12

몇억 줄이 있다면 ... 모든 줄을 씻어야합니까?
Ardianto Suhendar

31

데이터에 쉼표와 줄 바꿈이 포함될 수 있으므로 CSV 파일을 직접 작성하는 것은 어려울 수 있습니다. 기존 라이브러리를 대신 사용하는 것이 좋습니다.

이 질문에는 몇 가지 옵션이 언급되어 있습니다.

C #에 CSV 리더 / 라이터 라이브러리가 있습니까?


4
이것은 여기서 합리적으로 정답입니다. 손으로 직접 해보려고하는 다른 나쁜 대답들이 너무 많은 투표를 한 것은 부끄러운 일입니다.
MgSam

17

유지 관리가 매우 쉬운 두 가지 구문 분석 솔루션을 사용합니다.

// 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
큰 파일을 만들 때이 방법을 사용하면 메모리 부족 문제가 발생할 수 있습니다. .ToList를 제거하면 allLines는 IEnumerbale <object []>가됩니다. 그런 다음 "각각"대신에 alline, Select (line => csv.AppendLine (string.Join ( ",", line))) 대신 IEnumerable <string>을 선택할 수 있습니다. 이제 WriteAllLines 메서드 대신 File로 전달할 수 있습니다. 이제는 모든 것이 게으르고 모든 것을 메모리에 넣을 필요는 없지만 여전히 만족스러운 구문을 얻습니다.
RhysC

CSV 파일에 쓰는 방법을 사용하고 있습니다. 대단해! 내 최신 구현에는 File.AppendAllLines(filePath, lines, Encoding.ASCII);대신 대신 사용해야 합니다. File.WriteAllText(filePath, csv.ToString()); 그래서 나는 매우 성가신 일을하고 있습니다. StringBuilder를 사용하여 csv를 빌드 한 후 AppendAllLines에 대한 호출에 IEnumerable을 가져 오기 위해 List <string>으로 변환합니다 .csv.ToString ()을 매개 변수로 허용 List<string> lines = new List<string>(); lines.Add(csv.ToString(0, csv.Length));하지 않습니다.
Patricia

12

매번 전화하는 대신 AppendAllText()파일을 한 번 열어서 전체 내용을 한 번 작성하는 것을 생각할 수 있습니다.

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 : 죄송합니다. 오타입니다. 이제 수정되었습니다.
Oliver

이 답변에는 확장자가 csv 여야합니다. xls이면 데이터가 모두 한 열에 표시됩니다. csv 각 열에 올바르게 표시됩니다.
gman

11

AppendAllText를 대신 사용하십시오.

File.AppendAllText(filePath, csv);

AppendAllText의 유일한 단점은 파일이 존재하지 않을 때 오류가 발생한다는 것입니다.

문서 를 읽기 전에 금발의 순간이 있습니다 . 어쨌든 WriteAllText 메서드는 파일이 존재하는 경우 파일에 이전에 작성된 내용을 덮어 씁니다.

현재 코드는 올바른 줄 바꿈을 사용하지 않습니다. 예를 들어 메모장에서는 모두 한 줄로 표시됩니다. 적절한 새 줄을 갖도록 코드를 다음과 같이 변경하십시오.

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

2
@Rajat 아니오, 이미지 데이터 바로 뒤에 줄 바꿈 문자를 씁니다.
그림자 마법사가 당신을 위해 귀입니다

7

바퀴를 재창조하는 대신 라이브러리를 사용할 수 있습니다. CsvHelperCSV 파일을 만들고 읽는 데 좋습니다. 읽기 및 쓰기 작업은 스트림 기반이므로 대량의 데이터가있는 작업도 지원합니다.


다음과 같이 CSV를 작성할 수 있습니다.

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

라이브러리는 리플렉션을 사용하므로 모든 유형을 취하고 직접 구문 분석합니다.

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

value1, true

값 2, 거짓


라이브러리 구성 및 가능성에 대한 자세한 내용을 보려면 여기를 클릭하십시오 .


이 작업을 수행하려면 CultureInfo를 StreamWriter로 전달해야 할 수도 있습니다.
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();
                    }
                }
            }
        }
    }
}

왜 여기에 문자열 작성기가 없습니까?
Seabizkit

1
이것을 작성하기 위해 어떤 RFC를 사용 .Replace(",", ";") + ',' 하셨습니까?
vt100

Vikrant

3

쉼표 처리

을 사용할 때 값 내부의 쉼표를 처리하기 string.Format(...)위해 다음이 효과적이었습니다.

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

그래서 그것을 Johan의 대답과 결합하려면 다음과 같이 보일 것입니다.

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

희망적으로 이것은 도움이됩니다.


2

이 문서는 C #을 사용하여 csv 파일을 만드는 방법에 대한 간단한 자습서로, 자신의 요구에 맞게 편집하고 확장 할 수 있습니다.

먼저 새로운 Visual Studio C # 콘솔 응용 프로그램을 만들어야합니다.

예제 코드는 지정한 위치에 MyTest.csv라는 csv 파일을 만듭니다. 파일의 내용은 처음 3 행에 텍스트가있는 3 개의 명명 된 열이어야합니다.

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
솔루션에 대한 링크는 환영하지만 답변없이 유용한 답변을 얻으십시오 . 링크 주위에 컨텍스트를 추가 하여 동료 사용자가 그 이유와 그 이유를 파악한 다음 페이지의 가장 관련성이 높은 부분을 인용하십시오. 대상 페이지를 사용할 수없는 경우 다시 연결 링크에 불과한 답변은 삭제 될 수 있습니다.
Shree

아 알 겠어요 피드백 감사드립니다. 변경 사항을 강조 표시했습니다. 투표 해주세요.
Bloggins


0

CSV 파일을 쉽게 만들 수있는 또 다른 오픈 소스 라이브러리 인 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);
}

자세한 내용은 사용법에 대한 CodeProject 기사를 참조하십시오.


0

덮어 쓰기 문제를 제거하는 간단한 방법 중 하나 File.AppendText는 파일 끝에 줄을 다음과 같이 추가하는 것입니다.

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_value = 문자열. 빈;

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

이를 통해 CSV 파일을 매우 간단하게 작성할 수 있습니다. 용법:

StreamWriter writer = new StreamWriter("myfile.csv");
writer.WriteCSVLine(new[]{"A", "B"});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.