using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace FastDBF
{
public class DbfHelper
{
private static readonly string basePath = Directory.GetCurrentDirectory();
public static (bool, string) WriteDdf<T>(T model, string dbfName) where T : class
{
List<T> ts = new List<T>();
ts.Add(model);
return WriteDdf<T>(model, dbfName);
}
/// <summary>
/// 写入dbf
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list">列表数据</param>
/// <param name="dbfPath">dbf保存路径</param>
/// <returns></returns>
public static (bool, string) WriteDdf<T>(List<T> list, string dbfName) where T : class
{
if (list == null) return (false, "传入数据为空");
DbfFile dbfFile = new DbfFile(Encoding.UTF8);
try
{
//创建dbf文件
string writeDirectory = Path.Combine(basePath, "DbfFile");
string writePath = Path.Combine(writeDirectory, dbfName);
if (!Directory.Exists(writeDirectory)) Directory.CreateDirectory(writeDirectory);
bool fileIsExists = File.Exists(writePath);
dbfFile.Open(writePath, FileMode.Append, FileAccess.Write);
dbfFile._headerWritten = fileIsExists;
var dicProperty = Mapping<T>();
//create a header
foreach (var it in dicProperty)
{
dbfFile.Header.AddColumn(new DbfColumn(it.Key, DbfColumn.DbfColumnType.Character, 255, 0));
}
foreach (var it in list)
{
var orec = new DbfRecord(dbfFile.Header) { AllowDecimalTruncate = true };
foreach (var col in dicProperty)
{
var pro = col.Value;
object value = pro.GetValue(it);
if (value == null || value == DBNull.Value)
{
value = "";
}
orec[col.Key] = value.ToString();
}
dbfFile.Write(orec, true);
}
dbfFile.Dispose();
return (true, "写入成功");
}
catch (Exception ex)
{
dbfFile.Dispose();
return (false, $"写入失败:{ex.ToString()}");
}
}
/// <summary>
/// 读取dbf文件
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dbfPath">dbf文件路径</param>
/// <returns></returns>
public static (bool, List<T>, string) ReadDdf<T>(string dbfName) where T : class
{
List<T> list = new List<T>();
DbfFile dbfFile = new DbfFile(Encoding.UTF8);
try
{
//获取一个DBF文件对象
string readPath = Path.Combine(basePath, "DbfFile", dbfName);
if (!File.Exists(readPath)) return (false, null, "文件不存在");
dbfFile.Open(readPath, FileMode.Open, FileAccess.Read);
var dicProperty = Mapping<T>();
//读取dbf的字段名
DbfHeader dh = dbfFile.Header;
List<string> dbfColumns = new List<string>();
for (int index = 0; index < dh.ColumnCount; index++)
{
dbfColumns.Add(dh[index].Name);
}
//读取数据
int i = 0;
while (dbfFile.Read(i) != null)
{
//读取一行
DbfRecord record = dbfFile.Read(i);
if (record == null)
{
continue;
}
T t = Activator.CreateInstance<T>();
foreach (var col in dbfColumns)
{
var data = dicProperty.FirstOrDefault(r => r.Key == col);
if (data.Key == null)
{
continue;
}
var pro = data.Value;
if (pro == null || !pro.CanWrite)
{
continue;
}
string value = record[col];
if (value == null)
{
continue;
}
pro.SetValue(t, Convert.ChangeType(value.Trim(), pro.PropertyType));
}
list.Add(t);
i++;
}
dbfFile.Close();
return (true, list, "");
}
catch (Exception ex)
{
dbfFile.Dispose();
return (false, null, $"读取失败:{ex.ToString()}");
}
}
/// <summary>
/// 映射
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private static List<KeyValuePair<string, PropertyInfo>> Mapping<T>() where T : class
{
Type type = typeof(T);
var properties = type.GetProperties();
List<KeyValuePair<string, PropertyInfo>> result = new List<KeyValuePair<string, PropertyInfo>>();
//保存dbf字段和实体的映射关系
//实体没有ColumnAttribute,则认为dbf字段名称和实体名称一致
foreach (var pro in properties)
{
var attrs = pro.GetCustomAttributes(true).SingleOrDefault(attr => attr.GetType().Name == typeof(ColumnAttribute).Name) as dynamic;
if (attrs == null)
result.Add(new KeyValuePair<string, PropertyInfo>(pro.Name, pro));
else
result.Add(new KeyValuePair<string, PropertyInfo>(attrs.Name, pro));
}
return result;
}
}
}