2014-09-19 65 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