2014-09-19 91 views
4

這裏的目標是在輸入csv文件後,一個神奇的工具將輸出csv和csv中的字段。我們來看看例子。從csv文件結構生成c#模型類

輸入myFile.csv:

Year,Make,Model 
1997,Ford,E350 
2000,Mercury,Cougar 

輸出myFile.cs

public class myFile 
{ 
    public string Year; 
    public string Make; 
    public string Model; 
} 

所以,我需要解決的唯一的事情就是類型的屬性。之後,我會用FileHelpers這個類讀取csv文件。稍後它將映射到EntityFramework類(使用AutoMapper)並保存到數據庫。

實際上,https://csv2entity.codeplex.com/看起來像是在做我所需要的,但它不起作用 - 我安裝了它並沒有在我的Visual Studio中改變,沒有新的模板出現。該項目完全死亡。打開的源代碼和...決定也許我會問這個問題在計算器:)

FileHelpers只有一個簡單的嚮導,它允許您手動添加字段。但我有50個領域,這不是我最後一次需要這樣做的地方,所以自動化解決方案在這裏是首選。

我相信這個問題以前解決過很多次了,有什麼幫助嗎?

+0

我認爲這將是realtively easdy創建一個鏈接來自該文件的XML文件;然後,XML到類是標準的。 – 2014-09-19 12:23:25

+0

這裏是一個MS建議,可以做得更一般:http://msdn.microsoft.com/en-us/library/bb387090.aspx – 2014-09-19 12:35:44

+0

這個類是在運行時生成的,還是隻是在尋找一個方式來生成代碼文件,以供後續編譯? – stovroz 2014-09-19 12:53:00

回答

3

謝謝貝德福德,我把你的代碼,增加了三件事情:

  • 它刪除屬性名稱無效符號。例如「訂單號」將成爲「OrderNo」財產。
  • 能夠添加屬性和類屬性。在我的情況下,我需要[DelimitedRecord(「,」)]和[FieldOptional()],因爲我使用FileHelpers。
  • 某些列沒有名稱,因此它自己生成名稱。命名約定是Column10,Column11等。

最終代碼:

public class CsvToClass 
{ 
    public static string CSharpClassCodeFromCsvFile(string filePath, string delimiter = ",", 
     string classAttribute = "", string propertyAttribute = "") 
    { 
     if (string.IsNullOrWhiteSpace(propertyAttribute) == false) 
      propertyAttribute += "\n\t"; 
     if (string.IsNullOrWhiteSpace(propertyAttribute) == false) 
      classAttribute += "\n"; 

     string[] lines = File.ReadAllLines(filePath); 
     string[] columnNames = lines.First().Split(',').Select(str => str.Trim()).ToArray(); 
     string[] data = lines.Skip(1).ToArray(); 

     string className = Path.GetFileNameWithoutExtension(filePath); 
     // use StringBuilder for better performance 
     string code = String.Format("{0}public class {1} {{ \n", classAttribute, className); 

     for (int columnIndex = 0; columnIndex < columnNames.Length; columnIndex++) 
     { 
      var columnName = Regex.Replace(columnNames[columnIndex], @"[\s\.]", string.Empty, RegexOptions.IgnoreCase); 
      if (string.IsNullOrEmpty(columnName)) 
       columnName = "Column" + (columnIndex + 1); 
      code += "\t" + GetVariableDeclaration(data, columnIndex, columnName, propertyAttribute) + "\n\n"; 
     } 

     code += "}\n"; 
     return code; 
    } 

    public static string GetVariableDeclaration(string[] data, int columnIndex, string columnName, string attribute = null) 
    { 
     string[] columnValues = data.Select(line => line.Split(',')[columnIndex].Trim()).ToArray(); 
     string typeAsString; 

     if (AllDateTimeValues(columnValues)) 
     { 
      typeAsString = "DateTime"; 
     } 
     else if (AllIntValues(columnValues)) 
     { 
      typeAsString = "int"; 
     } 
     else if (AllDoubleValues(columnValues)) 
     { 
      typeAsString = "double"; 
     } 
     else 
     { 
      typeAsString = "string"; 
     } 

     string declaration = String.Format("{0}public {1} {2} {{ get; set; }}", attribute, typeAsString, columnName); 
     return declaration; 
    } 

    public static bool AllDoubleValues(string[] values) 
    { 
     double d; 
     return values.All(val => double.TryParse(val, out d)); 
    } 

    public static bool AllIntValues(string[] values) 
    { 
     int d; 
     return values.All(val => int.TryParse(val, out d)); 
    } 

    public static bool AllDateTimeValues(string[] values) 
    { 
     DateTime d; 
     return values.All(val => DateTime.TryParse(val, out d)); 
    } 

    // add other types if you need... 
} 

用例:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var cSharpClass = CsvToClass.CSharpClassCodeFromCsvFile(@"YourFilePath.csv", ",", "[DelimitedRecord(\",\")]", "[FieldOptional()]"); 
     File.WriteAllText(@"OutPutPath.cs", cSharpClass); 
    } 
} 

還有就是完整的代碼和工作示例https://github.com/povilaspanavas/CsvToCSharpClass

2

您可以使用一些C#應用程序生成類代碼,該代碼將檢查每列的所有值。可以確定哪些是每一個適合的最窄類型:

public static string CSharpClassCodeFromCsvFile(string filePath) 
{ 
    string[] lines = File.ReadAllLines(filePath); 
    string[] columnNames = lines.First().Split(',').Select(str => str.Trim()).ToArray(); 
    string[] data = lines.Skip(1).ToArray(); 

    string className = Path.GetFileNameWithoutExtension(filePath); 
    // use StringBuilder for better performance 
    string code = String.Format("public class {0} {{ \n", className); 

    for (int columnIndex = 0; columnIndex < columnNames.Length; columnIndex++) 
    { 
     code += "\t" + GetVariableDeclaration(data, columnIndex, columnNames[columnIndex]) + "\n"; 
    } 

    code += "}\n"; 
    return code; 
} 

public static string GetVariableDeclaration(string[] data, int columnIndex, string columnName) 
{ 
    string[] columnValues = data.Select(line => line.Split(',')[columnIndex].Trim()).ToArray(); 
    string typeAsString; 

    if (AllDateTimeValues(columnValues)) 
    { 
     typeAsString = "DateTime"; 
    } 
    else if (AllIntValues(columnValues)) 
    { 
     typeAsString = "int"; 
    } 
    else if (AllDoubleValues(columnValues)) 
    { 
     typeAsString = "double"; 
    } 
    else 
    { 
     typeAsString = "string"; 
    } 

    string declaration = String.Format("public {0} {1} {{ get; set; }}", typeAsString, columnName); 
    return declaration; 
} 

public static bool AllDoubleValues(string[] values) 
{ 
    double d; 
    return values.All(val => double.TryParse(val, out d)); 
} 

public static bool AllIntValues(string[] values) 
{ 
    int d; 
    return values.All(val => int.TryParse(val, out d)); 
} 

public static bool AllDateTimeValues(string[] values) 
{ 
    DateTime d; 
    return values.All(val => DateTime.TryParse(val, out d)); 
} 

// add other types if you need... 

可以創建從該可以在自動化解決方案中使用的命令行應用程序。

+0

感謝您的代碼。採取了它,添加了一些修改,它的工作。在我的回答中,我的修改如下所述。 – 2014-09-22 12:55:36

+0

當然。你應該定製它以適應你自己的應用程序,這只是一個基本的解決方案。您可以使用相同的技術來生成實體框架類。 – Bedford 2014-09-22 13:16:23