2011-04-13 6 views
2

データテーブルをループしてCSVファイルの各行を書き込んでCSVファイルを作成します。私のデータソースは通常、それに約65,000行あります。このプロセスは、ブラウザからダウンロードするのに数分かかります。問題は、ローカルでは、devでそれはあまりにも時間がかかることはありませんが、クライアントでは通常タイムアウトです。CSVファイルをより速く作成する

このファイルを高速に生成する方法はありますか?

Function GenerateCSVFile() As String 
    Dim stuPro As New studentProvider.StudentProvider 
    Dim emailCenter As New EmailCenter 
    Dim strFileName As String = System.IO.Path.GetRandomFileName().Replace(".", "") 
    Dim strResult As String = "" 

    Dim dtStudent As Data.DataTable 
    Dim paymentYear As String = "" 
    dtStudent = stuPro.generateDataFile() 

    If dtStudent.Rows.Count > 0 Then 

     Using sw As New System.IO.StreamWriter(Server.MapPath("Temp/" + strFileName + ".csv")) 
      Try 
       Dim lineValue As String = "" 

       lineValue += "Academic Year, StudentID, SSN, First, Middle, Last" 

       sw.WriteLine(lineValue) 

       For i As Integer = 0 To dtStudent.Rows.Count - 1 

        lineValue = dtStudent.Rows(i)("fy").ToString 
        lineValue += "," & dtStudent.Rows(i)("uniq_stu_id").ToString 
        lineValue += "," & dtStudent.Rows(i)("ssn").ToString 
        lineValue += "," & dtStudent.Rows(i)("fname").ToString 
        lineValue += "," & dtStudent.Rows(i)("mname").ToString 
        lineValue += "," & dtStudent.Rows(i)("lname").ToString 
        sw.WriteLine(lineValue) 

       Next 
      Catch ex As Exception 
       strResult += ex.ToString 
      Finally 
       sw.Close() 
      End Try 

     End Using 

     Dim strFriendlyName As String = Date.Now.ToString("MM-dd-yyyy") & ".csv" 

     If String.IsNullOrEmpty(strResult) Then 

      Dim fs As System.IO.FileStream = Nothing 

      fs = System.IO.File.Open(Server.MapPath("Temp/" + strFileName + ".csv"), System.IO.FileMode.Open) 
      Dim btFile(fs.Length) As Byte 
      fs.Read(btFile, 0, fs.Length) 
      fs.Close() 

      With Response 
       .AddHeader("Content-disposition", "attachment;filename=" & strFriendlyName) 
       .ContentType = "application/octet-stream" 
       .BinaryWrite(btFile) 
       .End() 
      End With 
     End If 
    Else 
     strResult = "No records found for specified academic year" 
    End If 

    Return strResult 
End Function 

あなたは、一時ファイルへの書き込みでそのファイルを読み込み、そして、彼らは、応答の中に、そのファイルの内容を書いている

Function GenerateCSVFile() As String 
    Dim startDate As Date = Date.Now 
    Dim enddate As Date = Nothing 
    Dim stuPro As New studentProvider.StudentProvider 
    Dim emailCenter As New EmailCenter 
    Dim strFileName As String = System.IO.Path.GetRandomFileName().Replace(".", "") 
    Dim strResult As String = "" 

    Dim dtStudent As Data.DataTable 
    Dim paymentYear As String = "" 
    dtStudent = stuPro.generateDataFile(Session("VendorID"), txtAcademicYear.Text.Trim) 

    If dtStudent.Rows.Count > 0 Then 

     With Response 

      Dim strFriendlyName As String = Date.Now.ToString("MM-dd-yyyy") & ".csv" 
      .AddHeader("Content-disposition", "attachment;filename=" & strFriendlyName) 
      .ContentType = "application/octet-stream" 

      Dim lineValue As StringBuilder = New StringBuilder 

      lineValue.Append("Academic Year, StudentID, SSN, First, Middle, Last") 

      .Write(lineValue.ToString) 

      For i As Integer = 0 To dtStudent.Rows.Count - 1 

       lineValue = New StringBuilder 
       lineValue.Append(dtStudent.Rows(i)("fy").ToString) 
       lineValue.Append("," & dtStudent.Rows(i)("uniq_stu_id").ToString) 
       lineValue.Append("," & dtStudent.Rows(i)("ssn").ToString) 
       lineValue.Append("," & dtStudent.Rows(i)("fname").ToString) 
       lineValue.Append("," & dtStudent.Rows(i)("mname").ToString) 
       lineValue.Append("," & dtStudent.Rows(i)("lname").ToString) 

       .Write(lineValue.ToString) 

      Next 
      enddate = Date.Now 

      MsgBox(DateDiff(DateInterval.Second, startDate, enddate)) 

      .End() 
     End With 
    Else 
     strResult = "No records found for specified academic year" 
    End If 
    Return strResult 
End Function 

答えて

1

これをスピードアップするためにいくつかのオプションがあります。

  • をレスポンス直接ページに書き込む、レスポンスにファイルには、StreamWriterから書き込まないでくださいが。
  • データテーブルの代わりにデータテーブルを使用してデータをループするソリューションを探してください。このデータを使用すると、データが高速になる可能性があります。また、メモリ使用量を減らします(メモリ内のテーブル全体をロードしません)。
  • 多くの文字列を連結する場合、StringBuilderを使用するか、この場合String.Joinを使用して簡単に行全体を作成します。

String.Joinの例は:あなたは、文字列変数を使用する方法

For Each row in dtStudent.Rows 
    Dim line as new List(of String) 
    line.Add(row("fy").ToString) 
    line.Add(row("uniq_stu_id").ToString) 
    line.Add(-etc-) 

    Response.Write(String.Join(",", line.ToArray) & vbcrlf) 
Next 
+0

レスポンスへの書き込みにはどのような方法を使用しますか? Response.writeまたはResponse.WriteFile。 – guanome

+0

作成するすべての行にResponse.Write(string)を使用し、これを行う前にヘッダーを設定します。これにより、ブラウザーは、予期するデータの種類を知ることができます。 – Willem

+0

私は提案された変更を加えましたが、それはまだ同じように動作しています。ファイルの生成には1分かかります。これは私が65,000以上の行で得ることができる最高のものですか?生成されるファイルは28MBです。 – guanome

3

更新されたコード。一時ファイルをスキップし、一度に1行ずつ直接レスポンスに書き込みます。これにより、ブラウザーは、サーバーがタイムアウトしていると思ったり、処理を高速化したり、アプリが消費するメモリー量を減らしたりすることができなくなります。

その後、このWeb要求でキャッシュを有効にして、複数のユーザーが短期間に要求した場合にASP.NETでCSVを再作成する必要がないようにします。

+0

レスポンスへの書き込みにはどのような方法を使用しますか? Response.writeまたはResponse.WriteFile。 – guanome

+0

@guanome - .Write(更新されたコードで行ったように)。これでタイムアウトの問題が修正されましたか? –

2

連結の代わりにStringBuilderを使用する必要があります。

1

@Robertレヴィの提案に加えて、注意してください。これらの行には、ストリングビルダを使用する方がよいでしょう。

 dim sbTemp as new StringBuilder() 
     For i As Integer = 0 To dtStudent.Rows.Count - 1 

      sbTemp.Append(dtStudent.Rows(i)("fy").ToString) 
      sbTemp.Append(",") 
      sbTemp.Append(dtStudent.Rows(i)("uniq_stu_id").ToString) 

      'etc 
      sw.WriteLine(lineValue) 

     Next 
0

見ることのできるものは、プロデューサ/コンシューマデザインのパターンです。これにより、csvファイルに書き込まれる必要のあるデータと実際の書き込みを行うスレッド(または複数のスレッド)を含むキューが1つ(または複数)のスレッドに割り当てられます。

関連する問題