2017-05-07 43 views
2

CSVhelperを使用して複数の.csvファイルをディレクトリから1つの.csvファイルにマージしようとすると、ディレクトリには50個の.csvファイルがあり、50個のファイルの中にファイル構造の2つのセットがあります.1つは7つの列と1つのファイル構造です。すべてのファイルは全く同じ最初の5つのヘッダーを持っていますが、ファイルによっては最後の2つの列変化する。 csvfile内のフォーマット1のCSVhelperを使用して異なるヘッダーを持つCSVファイルをマージするC#

例:csvfile内のフォーマット2のenter image description here

例:enter image description here

ディレクトリ内のすべてのファイルは、列の異なるデータをこれらの構造のいずれかを保持します。新しいファイルの出力には、アクション、コード、およびエラーメッセージのすべての列バーのデータがあります。私が例1の構造だけでファイルを使用すると、ファイルは完全に一緒になります。 `IEnumerableをdataRecordは= reader.GetRecords():この行で

An unhandled exception of type 'CsvHelper.TypeConversion.CsvTypeConverterException' occurred in CsvHelper.dll

:私は両方の構造を持つファイルが含まれており、私の新しいファイルの例2から「ErrorIPAddress」を試してみて、使用している場合しかし、私は次のエラーを取得します。 ToList();

私の質問は、1つのファイルの列を他のファイルに使用する方法ですか?私はそれを次のようにマッピングしようとしました:Map(m => m.ErrorIPAddress).Index(5);と私はこれが問題を引き起こしていると私は考えていますが、明らかに私が新しい.csvに必要なデータを得ることはできません。私が試みて、名前でマップすると:Map(m => m.ErrorIPAddress).Name("ErrorIPAddress"); ErrorIPAddressが.csvファイルにないというエラーメッセージが表示されますが、すべてのファイルにその列があるわけではありません。

出力.csv形式:enter image description here

最後の列は、あなたが外部ライブラリを必要としない形式2.

+0

異なるCSV形式を読み込む問題と、異なるデータセットをマージする方法の問題を区別することをお勧めします。 CSVファイルを読み込むには、2つのメソッドを作成します。これらのメソッドのそれぞれは、1種類のCSVだけを読み込む責任があります。 (CSVのマージはこれらの2つの方法の一部ではありません)。各CSVファイルについて、1つの方法でそれを読んでみてください。この方法が失敗した場合は、2番目の方法でそれを読んでみてください。関連するCSVファイルを読んでいる場合は、要件に応じてデータセットをマージする別の方法(実装する必要があります)を使用してください。 – elgonzo

+0

結果のマージされたCSVにはどのような列形式が必要ですか? – robaudas

+0

@robaudas私は質問に追加しました。この列は、例2のErrorIPaddressの単純なカウントによって生成されます。 – johnfish92

答えて

2

以下のコードを使用しますCsvClassMapのプロパティとフィールド名が正しく一致していません。

クラスファイルでIPAddressの代わりにErrorIPAddressが使用されている場合は、マッピングを元に戻す必要があります。

Map(m => m.ErrorIPAddress).Name("IPAddress"); 
+0

これは私が探していたより多くの答えでした。しかし、私はいくつかの質問をし、いくつかのコメントをすることができます。まず、ファイル形式1のコードはエラーメッセージと同じではありません。私はフォーマット1に含まれているヘッダのクラスdataRecordを持っています。あなたが提供したものと非常に似ています。また、.csvファイルから必要な値を取得するカスタムマップがあります。これはフォーマット2に似た何かを作成する必要があるのですか?形式2に含まれるすべてのフィールドを持つ新しいクラスと、上に似た新しいマップがありますか? – johnfish92

+0

でも注意してください。私は、両方のファイルから別々のIPアドレスを保持する必要があります。これは、新しいファイルに2つのdiffカラムを計算するために使用されているためです。フォーマット1のIPアドレスはリクエスト用で、フォーマット2のIPアドレスはエラー用です – johnfish92

+0

私はあなたの質問に答えたようです。しかし、あなたの全体的なソリューションに対処するために、2つの別々のクラス定義(各ファイルに1つずつ)を用意して、2つの別々のコレクションにファイルを読み込み、2つのコレクションを使用してレポートを作成するロジックを実行します。これにより、マッピング全体が回避されますが、アプリケーションの範囲がレポートの生成のみを目的としていることが前提です。 – robaudas

1

にErrorIPAddress列によって生成されます。だから、

public class StudentWebAccess 
{ 
    public int StudentID { get; set; } 
    public string Gender { get; set; } 
    public int Grade { get; set; }   
    public int IPAddress { get; set; } // Also ErrorIPAddress? 
    public DateTime DateTime { get; set; } 
    public string Action { get; set; } 
    public string Code { get; set; } // Also ErrorMessage? 
} 

ファイルフォーマット2を読み取るために使用している:私はあなたがこのようになり、すべてのフィールドを持つ単一のクラス定義を使用していると仮定してい

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Globalization; 
using System.Data; 
using System.Data.OleDb; 
using System.IO; 


namespace ConsoleApplication1 
{ 
    class Program 
    { 
     const string FOLDER = @"c:\temp\test"; 
     static void Main(string[] args) 
     { 
      CSVReader reader = new CSVReader(); 

      //table containing merged csv files 
      DataTable dt = new DataTable(); 

      //get csv files one at a time 
      foreach (string file in Directory.GetFiles(FOLDER, "*.csv")) 
      { 
       //read csv file into a new dataset 
       DataSet ds = reader.ReadCSVFile(file, true); 
       //datatable containing new csv file 
       DataTable dt1 = ds.Tables[0]; 

       //add new columns to datatable dt if doesn't exist 
       foreach(DataColumn col in dt1.Columns.Cast<DataColumn>()) 
       { 
        //test if column exists and add if it doesn't 
        if (!dt.Columns.Contains(col.ColumnName)) 
        { 
         dt.Columns.Add(col.ColumnName, typeof(string)); 
        } 
       } 

       //array of column names in new table 
       string[] columnNames = dt1.Columns.Cast<DataColumn>().Select(x => x.ColumnName).ToArray(); 

       //copy row from dt1 into dt 
       foreach(DataRow row in dt1.AsEnumerable()) 
       { 
        //add new row to table dt 
        DataRow newRow = dt.Rows.Add(); 

        //add data from dt1 into dt 
        for(int i = 0; i < columnNames.Count(); i++) 
        { 
         newRow[columnNames[i]] = row[columnNames[i]]; 
        } 
       } 
      } 

     } 
    } 
    public class CSVReader 
    { 

     public DataSet ReadCSVFile(string fullPath, bool headerRow) 
     { 

      string path = fullPath.Substring(0, fullPath.LastIndexOf("\\") + 1); 
      string filename = fullPath.Substring(fullPath.LastIndexOf("\\") + 1); 
      DataSet ds = new DataSet(); 

      try 
      { 

       //read csv file using OLEDB Net Library 
       if (File.Exists(fullPath)) 
       { 
        string ConStr = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}" + ";Extended Properties=\"Text;HDR={1};FMT=Delimited\\\"", path, headerRow ? "Yes" : "No"); 
        string SQL = string.Format("SELECT * FROM {0}", filename); 
        OleDbDataAdapter adapter = new OleDbDataAdapter(SQL, ConStr); 
        adapter.Fill(ds, "TextFile"); 
        ds.Tables[0].TableName = "Table1"; 
       } 

       //replace spaces in column names with underscore 
       foreach (DataColumn col in ds.Tables["Table1"].Columns) 
       { 
        col.ColumnName = col.ColumnName.Replace(" ", "_"); 
       } 
      } 

      catch (Exception ex) 
      { 
       Console.WriteLine(ex.Message); 
      } 
      return ds; 
     } 
    } 
} 
+0

私はコードの本体を取るだけではなく、それが何を完全に理解するだろう。あなたは私に簡単な説明を教えてもらえますか? – johnfish92

+0

コードにコメントを追加しました。コードはOLEDB Net Libraryメソッドを使用してcsvを読み取ります。 – jdweng

関連する問題