[英]How to use a dynamic CSV delimiter with FileHelpers?
問題:我需要讀取一個 CSV 文件。 我使用 FileHelpers 庫來實現這一點。
問題是我需要一個動態定界符(用戶定義),這意味着任何東西都可以是定界符(逗號、分號、制表符、換行符,但也可以是其他任何東西)。
問題是,FileHelpers 在屬性中定義分隔符,這意味着在編譯時。 這使得不可能動態地進行。
我能做的是聲明一個新的 class,它繼承自一個基數 class,並在這個新的 class 上設置分隔符。
[FileHelpers.DelimitedRecord(",")]
public class CommaCustomer : BaseCustomer
{
}
這樣我只需要為每個新的定界符在基礎 class 中進行更改。 問題是,這是我不能(也不想)為每個可能的分隔符創建一個子 class。
這是我到目前為止的代碼:
using System;
using System.Data;
using System.IO;
//using FileHelpers;
//using FileHelpers.RunTime;
namespace Examples
{
class MainClass
{
[STAThread]
static void Main()
{
FileHelpers.FileHelperEngine engine = new FileHelpers.FileHelperEngine(typeof(SemicolonCustomer));
// To read use:
string str = @"D:\Username\Desktop\FileHelpers_Examples_CSharp_VbNet\Data\SemicolonCustomers.txt";
//str = @"D:\Username\Desktop\FileHelpers_Examples_CSharp_VbNet\Data\CustomersDelimited.txt";
SemicolonCustomer[] custs = (SemicolonCustomer[])engine.ReadFile(str);
//Customer[] custs = (Customer[]) engine.ReadFile("yourfile.txt");
foreach (SemicolonCustomer cli in custs)
{
Console.WriteLine();
Console.WriteLine("Customer: " + cli.CustId.ToString() + " - " + cli.Name);
Console.WriteLine("Added Date: " + cli.AddedDate.ToString("d-M-yyyy"));
Console.WriteLine("Balance: " + cli.Balance.ToString());
Console.WriteLine();
Console.WriteLine("-----------------------------");
} // Next cli
Console.ReadKey();
Console.WriteLine("Writing data to a delimited file...");
Console.WriteLine();
// To write use:
//engine.WriteFile("myyourfile.txt", custs);
//If you are using .NET 2.0 or greater is
//better if you use the Generics version:
// FileHelperEngine engine = new FileHelperEngine<Customer>();
// To read use (no casts =)
// Customer[] custs = engine.ReadFile("yourfile.txt");
// To write use:
// engine.WriteFile("yourfile.txt", custs);
} // End Sub Main
} // End Class MainClass
//------------------------
// RECORD CLASS (Example, change at your will)
// TIP: Remember to use the wizard to generate this class
public class BaseCustomer
{
public int CustId;
public string Name;
public decimal Balance;
[FileHelpers.FieldConverter(FileHelpers.ConverterKind.Date, "ddMMyyyy")]
public DateTime AddedDate;
}
[FileHelpers.DelimitedRecord(";")]
public class SemicolonCustomer : BaseCustomer
{
}
[FileHelpers.DelimitedRecord(",")]
public class CommaCustomer : BaseCustomer
{
}
}
是否有可能在運行時編譯子 class
[FileHelpers.DelimitedRecord(\"" + delimiter + "\")]
public class AnyDelimiterCustomer : BaseCustomer
{
}
然后在代碼中引用這個運行時編譯的 class?
我剛剛意識到有一個DelimitedFileEngine
以另一種方式解決了你的問題。
你可以去
var engine = new DelimitedFileEngine(typeof(BaseCustomer));
engine.Options.Delimiter = ",";
似乎BaseCustomer
需要使用[DelimitedRecord]
屬性進行修飾,否則會引發異常,但是提供給engine.Options.Delimiter
任何內容都會覆蓋分隔符。
以下示例使用標記為bar分隔的格式導入逗號分隔的記錄。
[DelimitedRecord("|")]
public class Format1
{
public string Field1;
public string Field2;
public string Field3;
public string Field4;
}
static void Main(string[] args)
{
var engine = new DelimitedFileEngine(typeof(Format1));
// change the delimiter
engine.Options.Delimiter = ",";
// import a comma separated record
object[] importedObjects = engine.ReadString(@"a,b,c,d");
foreach (object importedObject in importedObjects)
{
if (importedObject is Format1)
{
Format1 format1 = (Format1)importedObject;
// process it (for example, check the values)
Assert.AreEqual("a", format1.Field1);
Assert.AreEqual("b", format1.Field2);
Assert.AreEqual("c", format1.Field3);
Assert.AreEqual("d", format1.Field4);
}
}
}
不,那是不可能的。
但是您可以使用FileHelper DelimitedClassBuilder
來構建動態文件解析器,您可以在運行時設置分隔符:
DelimitedClassBuilder dcb = new DelimitedClassBuilder("Name",
"Here goes your col separator");
// You have to build your field definitions by hand now
dcb.AddField("FieldName", typeof(decimal));
...
// build the engine
DelimitedFileEngine fileEngine = new DelimitedFileEngine(dcb.CreateRecordClass());
// read the file
dynamic[] data = fileEngine.ReadFile(filePath);
例如
// The class definition
public string mClass =
@"
[DelimitedRecord(""" + delimiter + @""")]
public class BaseCustomer
{
public int CustId;
public string Name;
public decimal Balance;
[FileHelpers.FieldConverter(FileHelpers.ConverterKind.Date, ""ddMMyyyy"")]
public DateTime AddedDate;
}
";
Type t = ClassBuilder.ClassFromString(mClass);
FileHelperEngine engine = new FileHelperEngine(t);
DataTable = engine.ReadFileAsDT("test.txt");
或者,您可以使用DelimitedClassBuilder類。
DelimitedClassBuilder cb = new DelimitedClassBuilder("BaseCustomer", delimiter);
cb.AddField("CustId", typeof(int));
cb.LastField.TrimMode = TrimMode.Both;
cb.LastField.FieldNullValue = 0;
cb.AddField("Balance", typeof(Decimal));
cb.AddField("AddedDate", typeof(DateTime));
engine = new FileHelperEngine(cb.CreateRecordClass());
DataTable dt = engine.ReadFileAsDT("test.txt");
有可能的。 但只能將序列化類型移動到單獨的程序集中。
像這樣:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace FlaechenupdateScript
{
static class Program
{
// http://www.codeproject.com/KB/cs/runtimecompiling.aspx
private static System.Reflection.Assembly BuildAssembly(string code)
{
Microsoft.CSharp.CSharpCodeProvider provider =
new Microsoft.CSharp.CSharpCodeProvider();
System.CodeDom.Compiler.ICodeCompiler compiler = provider.CreateCompiler();
System.CodeDom.Compiler.CompilerParameters compilerparams = new System.CodeDom.Compiler.CompilerParameters();
string strLocation = System.Reflection.Assembly.GetExecutingAssembly().Location;
string strBasePath = System.IO.Path.GetDirectoryName(strLocation);
string strSerializationTypes = System.IO.Path.Combine(strBasePath, "SerializationTypes.dll");
string strFileHelpersLocation = System.IO.Path.Combine(strBasePath, "FileHelpers.dll");
compilerparams.ReferencedAssemblies.Add(strSerializationTypes);
compilerparams.ReferencedAssemblies.Add(strFileHelpersLocation);
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
System.CodeDom.Compiler.CompilerResults results =
compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
System.Text.StringBuilder errors = new System.Text.StringBuilder("Compiler Errors :\r\n");
foreach (System.CodeDom.Compiler.CompilerError error in results.Errors)
{
errors.AppendFormat("Line {0},{1}\t: {2}\n",
error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
return results.CompiledAssembly;
}
} // End Function BuildAssembly
public static Type GetClassType(Type tt, string strDelimiter)
{
string strFullTypeName = tt.FullName;
string strTypeUniqueName = System.Guid.NewGuid().ToString() + System.Guid.NewGuid().ToString() + System.Guid.NewGuid().ToString() + System.Guid.NewGuid().ToString();
strTypeUniqueName = "_" + strTypeUniqueName.Replace("-", "_");
string xx = @"
namespace CrapLord
{
[FileHelpers.IgnoreFirst]
[FileHelpers.IgnoreEmptyLines]
[FileHelpers.DelimitedRecord(""" + strDelimiter + @""")]
public class " + strTypeUniqueName + @" : " + strFullTypeName + @"
{
}
}
";
System.Reflection.Assembly a = BuildAssembly(xx);
var o = a.CreateInstance("CrapLord." + strTypeUniqueName);
Type t = o.GetType();
//System.Reflection.MethodInfo mi = t.GetMethod("EvalCode");
//var s = mi.Invoke(o, null);
return t;
}
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
Type t = GetClassType(typeof(Tools.Serialization.CSV.Customer), ",");
//FileHelpers.FileHelperEngine engine = new FileHelpers.FileHelperEngine(typeof(SemicolonCustomer));
FileHelpers.FileHelperEngine engine = new FileHelpers.FileHelperEngine(t);
string str = "path/to/datafile";
Tools.Serialization.CSV.Customer[] custs = (Tools.Serialization.CSV.Customer[])engine.ReadFile(str);
//Customer[] custs = (Customer[]) engine.ReadFile("yourfile.txt");
foreach (Tools.Serialization.CSV.Customer cli in custs)
{
Console.WriteLine();
Console.WriteLine("Customer: " + cli.CustId.ToString() + " - " + cli.Name);
Console.WriteLine("Added Date: " + cli.AddedDate.ToString("d-M-yyyy"));
Console.WriteLine("Balance: " + cli.Balance.ToString());
Console.WriteLine();
Console.WriteLine("-----------------------------");
} // Next cli
Console.WriteLine(Environment.NewLine);
Console.WriteLine(" --- Press any key to continue --- ");
Console.ReadKey();
}
}
}
SerializationTypes程序集:
using System;
using System.Collections.Generic;
using System.Text;
namespace Tools.Serialization.CSV
{
//------------------------
// RECORD CLASS (Example, change at your will)
// TIP: Remember to use the wizard to generate this class
public class Customer
{
public int CustId;
public string Name;
public decimal Balance;
[FileHelpers.FieldConverter(FileHelpers.ConverterKind.Date, "ddMMyyyy")]
public DateTime AddedDate;
}
}
也許你想使用來自Microsoft.VisualBasic.FileIO命名空間的TextFieldParser :
string[] fields;
string[] delimiter = new string[] { "|" };
using (Microsoft.VisualBasic.FileIO.TextFieldParser parser =
new Microsoft.VisualBasic.FileIO.TextFieldParser(filename))
{
parser.Delimiters = delimiter;
parser.HasFieldsEnclosedInQuotes = false;
while (!parser.EndOfData)
{
fields = parser.ReadFields();
//Do what you need
}
}
添加演員表為我解決了問題(FileHelpers V3.5.1)
var engine = new DelimitedFileEngine(typeof(BaseCustomer)); ((FileHelpers.Options.DelimitedRecordOptions)engine.Options).Delimiter=",";
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.