这里的目标是在输入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中没有任何改变,没有出现新的模板。该项目已完全死亡。打开的源代码和......决定我可以在stackoverflow中问这个问题:)
FileHelpers只有一个简单的向导,允许您手动添加字段。但我有50个字段,这不是我最后一次需要这样做,所以这里首选自动解决方案。
我相信这个问题以前解决了很多次,有什么帮助吗?
答案 0 :(得分:5)
谢谢贝德福德,我拿了你的代码并添加了三件事:
最终代码:
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
的链接答案 1 :(得分: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...
您可以从中创建一个命令行应用程序,可以在自动解决方案中使用。
答案 2 :(得分:1)
您可以使用C#中的dynamic从CSV创建动态模型类。覆盖自定义DynamicObject类的TryGetMember并使用Indexers。
答案 3 :(得分:0)