18

これは私が持っているものです。できます。しかし、もっと簡単で良い方法はありますか?

ASPX ページの 1 つに、ダウンロード リンクがあります...

<asp:HyperLink ID="HyperLinkDownload" runat="server" NavigateUrl="~/Download.aspx">Download as CSV file</asp:HyperLink>

そして、Download.aspx.vb コード ビハインドを取得しました...

Public Partial Class Download
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'set header
        Response.Clear()
        Response.ContentType = "text/csv"
        Dim FileName As String = "books.csv"
        Response.AppendHeader("Content-Disposition", "attachment;filename=" + FileName)

        'generate file content
        Dim db As New bookDevelopmentDataContext
        Dim Allbooks = From b In db.books _
                       Order By b.Added _
                       Select b
        Dim CsvFile As New StringBuilder
        CsvFile.AppendLine(CsvHeader())
        For Each b As Book In Allbooks
            CsvFile.AppendLine(bookString(b))
        Next

        'write the file
        Response.Write(CsvFile.ToString)
        Response.End()
    End Sub

    Function CsvHeader() As String
        Dim CsvLine As New StringBuilder
        CsvLine.Append("Published,")
        CsvLine.Append("Title,")
        CsvLine.Append("Author,")
        CsvLine.Append("Price")
        Return CsvLine.ToString
    End Function

    Function bookString(ByVal b As Book) As String
        Dim CsvLine As New StringBuilder
        CsvLine.Append(b.Published.ToShortDateString + ",")
        CsvLine.Append(b.Title.Replace(",", "") + ",")
        CsvLine.Append(b.Author.Replace(",", "") + ",")
        CsvLine.Append(Format(b.Price, "c").Replace(",", ""))
        Return CsvLine.ToString
    End Function

End Class
4

8 に答える 8

23

CSV フォーマットにはいくつかの落とし穴があります。次の質問を自問したことがありますか。

  • カンマが埋め込まれたデータはありますか?
  • 二重引用符が埋め込まれたデータはありますか?
  • 改行を含むデータはありますか?
  • Unicode 文字列をサポートする必要がありますか?

上記のコードにはいくつかの問題があります。まずコンマのこと...コンマを取り除いています:

CsvLine.Append(Format(b.Price, "c").Replace(",", ""))

なんで?CSV では、カンマを引用符で囲む必要があります。

CsvLine.Append(String.Format("\"{0:c}\"", b.Price))

(またはそのようなもの...私のVBはあまり良くありません)。コンマがあるかどうかわからない場合は、引用符で囲みます。文字列に引用符がある場合は、それらを二重にしてエスケープする必要があります。"になり""ます。

b.Title.Replace("\"", "\"\"")

次に、必要に応じてこれを引用符で囲みます。文字列に改行がある場合は、文字列を引用符で囲む必要があります...はい、CSV ファイルでは文字どおりの改行を使用できます。人間には奇妙に見えますが、それはすべて良いことです。

優れた CSV ライターには、ある程度の考慮が必要です。優れた CSV リーダー (パーサー) は単純に難しいものです (いいえ、正規表現は CSV を解析するのに十分ではありません... それはそこまでの約 95% しか得られません)。

そして、Unicode... またはより一般的には I18N (国際化) の問題があります。たとえば、書式設定された価格からコンマを削除しています。ただし、これは、価格が米国で期待どおりに設定されていることを前提としています。フランスでは、数値の形式が逆になっています (コンマの代わりにピリオドが使用され、その逆も同様です)。結論として、可能な限りカルチャに依存しない書式設定を使用してください。

ここでの問題はCSV の生成ですが、必然的に CSV を解析する必要があります。.NET で私が見つけた (無料の) 最高のパーサーは、CodeProject のFast CSV Readerです。実際に製品コードで使用しましたが、非常に高速で、非常に使いやすいです。

于 2008-09-04T17:19:59.437 に答える
9

すべての CSV データを次のような関数に渡します。

Function PrepForCSV(ByVal value As String) As String
    return String.Format("""{0}""", Value.Replace("""", """"""))
End Function

また、html を提供していない場合は、完全な Web ページではなく、おそらく http ハンドラー (.as h x ファイル) が必要です。Visual Studio で新しいハンドラーを作成する場合、既存のコードをメイン メソッドにコピーするだけで機能し、パフォーマンスがわずかに向上する可能性があります。

于 2008-09-04T17:26:20.890 に答える
4

クエリ自体で bookString() に相当するものを作成できます。これが私がより簡単な方法だと思うものです。

protected void Page_Load(object sender, EventArgs e)
{
    using (var db = new bookDevelopmentDataContext())
    {
        string fileName = "book.csv";
        var q = from b in db.books
                select string.Format("{0:d},\"{1}\",\"{2}\",{3:F2}", b.Published, b.Title.Replace("\"", "\"\""), b.Author.Replace("\"", "\"\""), t.price);

        string outstring = string.Join(",", q.ToArray());

        Response.Clear();
        Response.ClearHeaders();
        Response.ContentType = "text/csv";
        Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}", fileName));
        Response.Write("Published,Title,Author,Price," + outstring);
        Response.End();
    }
}
于 2008-09-18T23:53:38.250 に答える
3

コロン区切りの値コンバーターが必要な場合は、FileHelpersというサードパーティのオープン ソースがあります。どのオープンソース ライセンスに基づいているかはわかりませんが、かなり役に立ちました。

于 2008-09-04T17:55:45.700 に答える
2

Pageクラスに関連する多くのオーバーヘッドがあります。CSVファイルを吐き出すだけで、ポストバック、サーバーコントロール、キャッシュなどの必要がないため、これを.ashx拡張子のハンドラーにする必要があります。ここを参照してください

于 2008-09-05T18:32:03.903 に答える
2

Simonが言ったことに加えて、CSVハウツーガイドを読んで、出力がどの落とし穴にも出てこないことを確認することをお勧めします。

サイモンが言ったことを明確にするために:

次に、必要に応じてこれを引用符で囲みます

二重引用符( "")を含むフィールドは、完全に二重引用符で囲む必要があります。パーサーで先頭と末尾の空白を(自分でトリミングするのではなく)削除する必要がない限り、すべてのフィールドを二重引用符で囲むだけでも害はありません。

于 2008-09-04T17:33:56.423 に答える
1

DataTable から CSV ファイルを作成するときは、次の方法を使用します。ControllerContext は、ファイルが書き込まれる応答ストリーム オブジェクトです。あなたにとっては、単に Response オブジェクトになります。

public override void ExecuteResult(ControllerContext context)
        {
            StringBuilder csv = new StringBuilder(10 * Table.Rows.Count * Table.Columns.Count);

            for (int c = 0; c < Table.Columns.Count; c++)
            {
                if (c > 0)
                    csv.Append(",");
                DataColumn dc = Table.Columns[c];
                string columnTitleCleaned = CleanCSVString(dc.ColumnName);
                csv.Append(columnTitleCleaned);
            }
            csv.Append(Environment.NewLine);
            foreach (DataRow dr in Table.Rows)
            {
                StringBuilder csvRow = new StringBuilder();
                for(int c = 0; c < Table.Columns.Count; c++)
                {
                    if(c != 0)
                        csvRow.Append(",");

                    object columnValue = dr[c];
                    if (columnValue == null)
                        csvRow.Append("");
                    else
                    {
                        string columnStringValue = columnValue.ToString();


                        string cleanedColumnValue = CleanCSVString(columnStringValue);

                        if (columnValue.GetType() == typeof(string) && !columnStringValue.Contains(","))
                        {
                            cleanedColumnValue = "=" + cleanedColumnValue; // Prevents a number stored in a string from being shown as 8888E+24 in Excel. Example use is the AccountNum field in CI that looks like a number but is really a string.
                        }
                        csvRow.Append(cleanedColumnValue);
                    }
                }
                csv.AppendLine(csvRow.ToString());
            }

            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = "text/csv";
            response.AppendHeader("Content-Disposition", "attachment;filename=" + this.FileName);
            response.Write(csv.ToString());
        }

        protected string CleanCSVString(string input)
        {
            string output = "\"" + input.Replace("\"", "\"\"").Replace("\r\n", " ").Replace("\r", " ").Replace("\n", "") + "\"";
            return output;
        }
于 2010-10-28T19:23:52.243 に答える
1

関数「BookString()」を除いて、ほとんど見栄えがよくなります。最初に、これらすべての文字列を次のような小さな関数に渡す必要があります。

Private Function formatForCSV(stringToProcess As String) As String
    If stringToProcess.Contains("""") Or stringToProcess.Contains(",") Then
        stringToProcess = String.Format("""{0}""", stringToProcess.Replace("""", """"""))
    End If
    Return stringToProcess
End Function

'So, lines like this:
CsvLine.Append(b.Title.Replace(",", "") + ",")
'would be lines like this instead:
CsvLine.Append(formatForCSV(b.Title)) + ",")

この関数は、文字列を CSV 用に適切にフォーマットします。文字列に引用符またはコンマが含まれている場合は、引用符を二重引用符に置き換え、文字列を引用符で囲みます。

改行は考慮されませんが、改行がないことがわかっている文字列 (単純な 1 行のテキスト フォームなどからの入力) に対してのみ、適切な CSV 出力を安全に保証できることに注意してください。

于 2013-08-23T13:45:10.193 に答える