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ファイルの最後のレコードが1つだけ取得されます。csvファイル内のすべての行を書き込むにはどうすればよいですか?


むしろa StringBuilderを使用してから、1つを保存しますか?
ヨハン

1
これはあなたが毎日達成するために必要な作業ではない場合、私はcsvファイルに書き込みデータに便利な機能が付属していますLinqPadを、使用することをお勧め:Util.WriteCsv (mydatacollection, @"c:\temp\data.csv");
マルコ

3
余談ですが、csv値がエンコードされていることを確認してください。つまり、そのうちの1つにカンマまたは行末文字が含まれていると、ファイルが混乱する可能性があります。私は通常csvのものにサードパーティのlibを使用します。
Matthijs Wessels 2014

@MatthijsWesselsライブラリの提案はありますか?
Arash Motamedi 16

回答:


311

更新

昔、私はこれを手動で行うことをお勧めしました(これは簡単な質問の簡単な解決策でした)。しかし、これがますます人気になっているため、すべての安全性チェックなどを行うライブラリ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いいえ、2は新しい行です
Johan

4
また、取り除くことができます{2}Environment.NewLineして使用AppendLineするのではなくAppend
KyleMit

37
また、CSVコンテンツにエスケープが必要なコンマがある場合はどうなりますか?見積もりが必要です。そして、見積もりがエスケープする必要がある場合はどうなりますか?CSVファイルを正しく作成することは、この回答が意味するよりもはるかに複雑です。
MgSam 2016年

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つの利点は、入力データの現在の位置を保存することにより、一時停止/再開を実装できることです。

upd。適切な場所に使用して配置


1
あなたはループのためにあなたを置くべき内部のusing声明。そうしないと、ファイルを何度も何度も開くことになります。
オリバー

2
いい答えだ。書式文字列から "{2}"を削除し、同じ行の "image"を "second"に置き換えた場合の正解。また、w.Close();でライターを閉じることを忘れないでください。w.Flush()は必要ありません。
movAX13h 2014年

6
この回答では、文字をエスケープする必要はありません。
MgSam 2016年

次のようにライターを設定すると役立つことも追加できますか:new StreamWriter(path、false、Encoding.UTF8)
Charkins12

数億行ある場合...すべての行をフラッシュする必要がありますか?
Ardianto Suhendar

30

データにカンマと改行が含まれている可能性があるため、csvファイルを手動で書き込むのは難しい場合があります。代わりに既存のライブラリを使用することをお勧めします。

この質問はいくつかのオプションについて言及しています。

C#にCSVリーダー/ライターライブラリはありますか?


4
これが、ここで合理的に正しい唯一の答えです。それを手でしようとする他の悪い答えが非常に多くの賛成票を持っているのは残念です。
MgSam 2016年

17

メンテナンスが非常に簡単なので、2つの解析ソリューションを使用します

// 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 []>になります。次に、「for eaching」の代わりにその上で選択できます。つまり、allines、Select(line => csv.AppendLine(string.Join( "、"、line)))は、IEnumerable <string>を提供します。これはFileに渡すだけで、WriteAllLinesメソッドに渡すことができます。つまり、すべてが遅延していて、すべてをメモリに取り込む必要はありませんが、満足のいく構文が得られます。
RhysC 2016年

私はあなたの方法を使用してcsvファイルに書き込みます。それは素晴らしい!私の最新の実装では 、File.AppendAllLines(filePath, lines, Encoding.ASCII);代わりにを使用する必要があるFile.WriteAllText(filePath, csv.ToString());ので、非常に不格好なことをしています。StringBuilderを使用してcsvを構築した後、それをList <string>に変換して、AppendAllLinesの呼び出し用のIEnumerableを取得します。これは、csv.ToString()をパラメーターとして受け入れ List<string> lines = new List<string>(); lines.Add(csv.ToString(0, csv.Length));ません。これを行うより良い方法はありますか?
パトリシア

12

毎回呼び出す代わりにAppendAllText()、ファイルを1度開いてから、コンテンツ全体を1度書き込むことを考えることができます。

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:申し訳ありませんが、タイプミスです。現在は修正されています。
オリバー

この回答には、拡張子がcsvでなければならないことが含まれています。xlsの場合、データはすべて1つの列に表示されます... csv各列に正しく表示されます。
gman

10

代わりにAppendAllTextを使用してください:

File.AppendAllText(filePath, csv);

AppendAllTextの唯一の欠点は、ファイルが存在しない場合にエラーをスローするため、これを確認する必要があります

ドキュメントを読む前に申し訳ありませんが、ブロンドの瞬間。とにかく、ファイルが存在する場合、WriteAllTextメソッドは、以前にファイルに書き込まれたものを上書きします。

現在のコードが適切な新しい行を使用していないことに注意してください。たとえば、メモ帳では、すべてが1つの長い行として表示されます。コードを次のように変更して、適切な新しい行を追加します。

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

value2、false


ライブラリの構成と可能性について詳しく知りたい場合は、こちらから行うことができます


これを機能させるには、CultureInfoをStreamWriterに渡す必要がある場合があります。
アリフ

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 2017年

1
これを書くためにどのRFCを使用しました .Replace(",", ";") + ',' か?
vt100

20000行と30列を
Vikrant

3

カンマの取り扱い

を使用するときに値の内部でコンマを処理するため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");
}

うまくいけば、これは役に立ちます。


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 2018


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

上書きの問題を取り除く簡単な方法の1つは、次のように使用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 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);
}

これにより、CSVファイルを非常に簡単に書き込むことができます。使用法:

StreamWriter writer = new StreamWriter("myfile.csv");
writer.WriteCSVLine(new[]{"A", "B"});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.