繁体   English   中英

将C#DataTable(ColumnName,ColumnType,ColumnValue)转换为csv并恢复

[英]Convert C# DataTable(ColumnName, ColumnType, ColumnValue) to csv and restore back

我正在寻找c#代码将ADO.NET数据表转换为csv文件,但是我想保存/恢复

  • 列名,
  • 列数据类型和
  • 栏值

在csv中。 我发现的大多数解决方案都以字符串列类型从CSV恢复数据表。 我还希望将可为空的值还原为DBNull.Value。 DateTime列应仅保存和恢复为DateTime类型。 该概念是使用Oracle / Sqlserver数据库中的DataAdapter填充数据表,然后将该表保存到CSV文件,然后再从CSV还原。

我已经使用下面的链接中的代码使用DataTableExtensions类c#datatable到csv将DataTable保存到CSV文件

为了将CSV文件读回到DataTable,我使用了以下链接http://www.codeproject.com/Articles/11698/A-Portable-and-Efficient-Generic-Parser-for-Flat-F

问题是当我将CSV文件还原到数据表时,我必须从数据表行创建实体。 但是他们在InvalidCast上抛出异常。

假设您要在第一行中存储列名,在第二行中存储类型,而数据则在第三行开始,则可以使用以下代码。 样本数据:

DataTable tblExport = new DataTable();
tblExport.Columns.Add("ID", typeof(int));
tblExport.Columns.Add("Name", typeof(string));
tblExport.Columns.Add("DateofBirth", typeof(DateTime)).AllowDBNull = false;
tblExport.Columns.Add("DateofDeath", typeof(DateTime)).AllowDBNull = true;

tblExport.Rows.Add(1, "Tim", new DateTime(1973, 7, 9), DBNull.Value);
tblExport.Rows.Add(2, "Jim", new DateTime(1953, 3, 19), new DateTime(2011, 1, 2));
tblExport.Rows.Add(3, "Toby", new DateTime(1983, 4, 23), DBNull.Value);

由于您需要将所有值都转换为具有value.ToString字符串, value.ToString我在开始时将区域性更改为InvariantCulture以强制使用特定的DateTime格式,因此请存储旧版本,以便您可以在末尾再次启用它。 我希望代码是不言自明的:

var oldCulture = CultureInfo.CurrentCulture;
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

将DataTable写入csv文件

string delimiter = "\t"; // tab separated
StringBuilder sb = new StringBuilder();
// first line column-names
IEnumerable<string> columnNames = tblExport.Columns.Cast<DataColumn>()
    .Select(column => column.ColumnName);
sb.AppendLine(string.Join(delimiter, columnNames));
// second line column-types
IEnumerable<string> columnTypes = tblExport.Columns.Cast<DataColumn>()
    .Select(column => column.DataType.ToString());
sb.AppendLine(string.Join(delimiter, columnTypes));
// rest: table data
foreach (DataRow row in tblExport.Rows)
{
    IEnumerable<string> fields = row.ItemArray.Select(field => field.ToString());
    sb.AppendLine(string.Join(delimiter, fields)); 
}
string path = @"C:\Temp\Testfile.csv";
File.WriteAllText(path, sb.ToString());

将csv文件读入DataTable

string[] lines = File.ReadAllLines(path);
string[] columns = lines[0].Split(new[] { delimiter }, StringSplitOptions.None);
string[] types   = lines[1].Split(new[] { delimiter }, StringSplitOptions.None);
DataTable tblImport = new DataTable();
for (int i = 0; i < columns.Length; i++)
{
    string colName  = columns[i];
    string typeName = types[i];
    tblImport.Columns.Add(colName, Type.GetType(typeName));
}

// import data
// use a typeValueConverter dictionary to convert values:
var typeValueConverter = new Dictionary<Type, Func<string, object>> {
    { typeof(DateTime), value =>  value.TryGetDateTime(null, null) },
    { typeof(Decimal),  value =>  value.TryGetDecimal(null) },
    { typeof(int),      value =>  value.TryGetInt32(null) },
};
foreach (string line in lines.Skip(2))
{ 
    string[] fields = line.Split(new[]{ delimiter }, StringSplitOptions.None);
    DataRow r = tblImport.Rows.Add(); // already added at this point
    for (int i = 0; i < tblImport.Columns.Count; i++)
    {
        DataColumn col = tblImport.Columns[i];
        string rawValue = fields[i];
        object val = rawValue;
        if (typeValueConverter.ContainsKey(col.DataType))
            val = typeValueConverter[col.DataType](rawValue);
        else if (col.DataType != typeof(string) && string.IsNullOrEmpty(rawValue))
            val = DBNull.Value;
        r.SetField(col, val);
    }
}
System.Threading.Thread.CurrentThread.CurrentCulture = oldCulture;

当然,您应将两种方法分开,一种用于导出,另一种用于导入。

我已经使用了扩展方法TryGetDateTimeTryGetDecimalTryGetInt32来将字符串解析为DateTime? Decimal? int? (如果无法解析,则为null)。 它们在LINQ查询中特别方便:

public static DateTime? TryGetDateTime(this string item, DateTimeFormatInfo dfi, params string[] allowedFormats)
{
    if (dfi == null) dfi = DateTimeFormatInfo.InvariantInfo;
    DateTime dt;
    bool success;
    if(allowedFormats == null)
        success = DateTime.TryParse(item, dfi, DateTimeStyles.None, out dt);
    else
        success = DateTime.TryParseExact(item, allowedFormats, dfi, DateTimeStyles.None, out dt);
    if (success) return dt;
    return null;
}

public static decimal? TryGetDecimal(this string item, IFormatProvider formatProvider = null, NumberStyles nStyles = NumberStyles.Any)
{
    if (formatProvider == null) formatProvider = NumberFormatInfo.InvariantInfo;
    decimal d = 0m;
    bool success = decimal.TryParse(item, nStyles, formatProvider, out d);
    if (success)
        return d;
    else
        return null;
}

public static int? TryGetInt32(this string item, IFormatProvider formatProvider = null, NumberStyles nStyles = NumberStyles.Any)
{
    if (formatProvider == null) formatProvider = NumberFormatInfo.InvariantInfo;
    int i = 0;
    bool success = int.TryParse(item, nStyles, formatProvider, out i);
    if (success)
        return i;
    else
        return null;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM