2017-05-07 115 views
2

嘗試使用CSVhelper將多個.csv文件從目錄合併到一個.csv文件時。在目錄中有50個.csv文件,在這50個文件中,有兩組文件結構,一個包含7列,另一個包含6.每個文件具有完全相同的前5個文件頭,但根據文件最後兩列更改。 CSVfile格式1的使用CSVhelper合併具有不同標題的CSV文件C#

實施例:enter image description here

CSVfile格式2的實施例:enter image description here

在目錄中的每個文件將持有任一這些結構的與在列中不同的數據。新文件的輸出將具有來自所有列的數據行Action,Code和Error Message。如果我只用示例1的結構使用文件,則文件完美地結合在一起。不過,如果我包括與這兩個結構的文件,並嘗試在我的新文件中使用「ErrorIPAddress」自實施例2我得到以下錯誤:

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

在這一行:`IEnumerable的dataRecord = reader.GetRecords()。 ToList();

我的問題是:如何使用不在另一個文件中的列?我試圖將它與以下映射:Map(m => m.ErrorIPAddress).Index(5);,我相信這是導致我的問題,如果我註釋它的錯誤不會持續,但顯然我不會將我需要的數據到新的.csv。如果我嘗試按以下名稱映射:Map(m => m.ErrorIPAddress).Name("ErrorIPAddress");我收到ErrorIPAddress不在.csv文件中的錯誤消息,因爲不是所有文件都有該列。

輸出.csv格式:enter image description here

的最後一列將由ErrorIPAddress列格式2.

+0

我建議你將閱讀不同CSV格式的問題與如何合併不同數據集的問題區分開來。要閱讀CSV文件,請創建2個方法。每種方法都只負責讀取一種類型的CSV。 (CSV的合併不應該是這兩種方法的一部分)。對於每個CSV文件,請嘗試使用一種方法讀取它。如果此方法失敗,請嘗試使用第二種方法讀取它。如果您已閱讀相關的CSV文件,請使用另一種方法(您將必須執行),以根據您的要求合併數據集。 – elgonzo

+0

生成的合併CSV應具有哪種列格式? – robaudas

+0

@robaudas我已經添加到問題。該列將通過示例2中對ErrorIP地址的簡單計數生成。 – johnfish92

回答

2

代碼我假設你正在使用一個類定義的所有字段看起來是這樣的:

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使用的是CsvClassMap但沒有正確匹配屬性和字段名稱。它應該看起來像這樣:

public class CsvFile2Map : CsvClassMap<StudentWebAccess> 
{ 
    public CsvFile2Map() 
    {    
     Map(m => m.IPAddress).Name("ErrorIPAddress"); 
     Map(m => m.Code).Name("ErrorMessage"); 
    } 
} 

如果您的類文件使用ErrorIPAddress而不是IPAddress,則必須反轉映射。

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

這是更多我正在尋找的答案。但是,我可以問一些問題並提出一些意見。首先,文件格式1中的代碼與錯誤消息不同。我有我的類dataRecord包含在格式1中的標題 - 非常類似於您提供的內容。我也有一個自定義的地圖,從.csv文件中獲取我想要的值。這是否意味着我需要創建類似於格式2的內容?通過一個包含格式2中包含的所有字段的新類以及一個類似於上述的新地圖? – johnfish92

+0

需要注意的是,我需要保持兩個文件的IP地址不同,因爲它們被用來計算新文件中的2個差異列。格式1的IP地址將用於請求,格式2的IP地址將出現錯誤 – johnfish92

+0

我覺得我回答了您的問題。但爲了解決您的整體解決方案,我只需要2個單獨的類定義(每個文件一個),然後將這些文件讀取到2個單獨的集合中,然後執行邏輯以使用2個集合而不是一個集合來創建報告。這完全避免了映射,但假定您的應用程序的範圍僅用於生成報告。 – robaudas

1

產生不需要外部庫。使用下面

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

相關問題