2016-04-06 14 views
-1

こんにちは、私はcreate multiple CSV filesからDataTablesmaller chunks based on sizeapp.configのキーと値のペアを通過する関数を持っています。以下のコードで特定のサイズのCSVファイルの分割

問題:

  1. 私は20の値を渡すだろうと、それは20kbのCSVファイルを作成する必要があり、1キロバイトのファイルサイズをハードコーディングしました。現在、同じ値のファイルサイズは5kbです。
  2. 最後の左のレコードはファイルを作成していません。

この問題を解決するために助けてください。ありがとう!

コード:

public static void CreateCSVFile(DataTable dt, string CSVFileName) 
    { 

     int size = Int32.Parse(ConfigurationManager.AppSettings["FileSize"]); 
     size *= 1024; //1 KB size 
     string CSVPath = ConfigurationManager.AppSettings["CSVPath"]; 

     StringBuilder FirstLine = new StringBuilder(); 
     StringBuilder records = new StringBuilder(); 

     int num = 0; 
     int length = 0; 

     IEnumerable<string> columnNames = dt.Columns.Cast<DataColumn>().Select(column => column.ColumnName); 
     FirstLine.AppendLine(string.Join(",", columnNames)); 
     records.AppendLine(FirstLine.ToString()); 

     length += records.ToString().Length; 

     foreach (DataRow row in dt.Rows) 
     { 
      //Putting field values in double quotes 
      IEnumerable<string> fields = row.ItemArray.Select(field => 
       string.Concat("\"", field.ToString().Replace("\"", "\"\""), "\"")); 

      records.AppendLine(string.Join(",", fields)); 
      length += records.ToString().Length; 

      if (length > size) 
      { 
       //Create a new file 
       num++; 
       File.WriteAllText(CSVPath + CSVFileName + DateTime.Now.ToString("yyyyMMddHHmmss") + num.ToString("_000") + ".csv", records.ToString()); 
       records.Clear(); 
       length = 0; 
       records.AppendLine(FirstLine.ToString()); 
      } 

     }    
    } 
+0

私はむしろ、 'DataTable'から直接指定されたファイルサイズの小さなチャンクに' CSV Files'を直接書きます。私はすべてのレコードを書くことができません。 'If​​'条件は' length> size'だけを探しているので、最後の左のレコードを残し、それらのレコードのファイルを作成しません。 – sarfarazit08

答えて

2

File.ReadLines,Linqdeferred executionを使用します。 ReadLinesReadAllLines

MSDN

から

foreach(var line in File.ReadLines(FilePath)) 
{ 
    // logic here. 
} 

方法次のように異なります。あなたは ReadLinesを使用する場合、あなたは全体のコレクションが返され 前に、文字列のコレクションを列挙開始することができます。 ReadAllLinesを使用する場合、配列 にアクセスする前に、文字列の配列全体が返されるまで待つことが、 である必要があります。したがって、非常に大きなファイルで作業している場合は、 ReadLinesがより効率的になります。を使用すると、となります。

これで、以下のようにメソッドを書き直すことができました。

public static void SplitCSV(string FilePath, string FileName) 
    { 
     //Read Specified file size 
     int size = Int32.Parse(ConfigurationManager.AppSettings["FileSize"]); 

     size *= 1024 * 1024; //1 MB size 

     int total = 0; 
     int num = 0; 
     string FirstLine = null; // header to new file     
     var writer = new StreamWriter(GetFileName(FileName, num)); 

     // Loop through all source lines 
     foreach (var line in File.ReadLines(FilePath)) 
     { 
      if (string.IsNullOrEmpty(FirstLine)) FirstLine = line; 
      // Length of current line 
      int length = line.Length; 

      // See if adding this line would exceed the size threshold 
      if (total + length >= size) 
      { 
       // Create a new file 
       num++; 
       total = 0; 
       writer.Dispose(); 
       writer = new StreamWriter(GetFileName(FileName, num)); 
       writer.WriteLine(FirstLine); 
       length += FirstLine.Length; 
      } 

      // Write the line to the current file     
      writer.WriteLine(line); 

      // Add length of line in bytes to running size 
      total += length; 

      // Add size of newlines 
      total += Environment.NewLine.Length; 
     } 
    } 
+0

私が投稿した質問でわかるように、各ファイルの作成にヘッダーを含めることもできます - 文字列FirstLine = arr [0]; 'writer.WriteLine(FirstLine);' * 'foreach loop' **? – sarfarazit08

1

ソリューションは非常に簡単です(あなたがstring[] arr = File.ReadAllLines(FilePath);にそうであるように)...あなたは、メモリ内のすべてのあなたのラインを配置する必要はありません。

代わりに、入力ファイルにStreamReaderを作成し、行単位で行バッファーに読み込みます。バッファが "スレッショルドサイズ"を超えている場合は、そのディスクを単一のcsvファイルに書き込みます。 (あなたのコードが行ったように、全体ではなく、CSVのinpuntファイルの)あなたは、メモリをより良く制御することが

using (var sr = new System.IO.StreamReader(filePath)) 
{ 
    var linesBuffer = new List<string>(); 
    while (sr.Peek() >= 0) 
    { 
     linesBuffer.Add(sr.ReadLine()); 
     if (linesBuffer.Count > yourThreshold) 
     { 
      // TODO: implement function WriteLinesToPartialCsv 
      WriteLinesToPartialCsv(linesBuffer); 
      // Clear the buffer: 
      linesBuffer.Clear(); 
      // Try forcing c# to clear the memory: 
      GC.Collect(); 
     } 
    } 
} 

は、あなたが見ることができるように、ラインによって、ストリームラインを読んだ:コードは次のようなものでなければなりません。

関連する問題