using System;
|
using System.Collections.Generic;
|
using System.Data;
|
using System.IO;
|
using System.Linq;
|
using System.Text;
|
using System.Text.RegularExpressions;
|
using System.Threading.Tasks;
|
|
namespace DPumpHydr.WinFrmUI.WenSkin
|
{
|
public class Csv
|
{
|
public Csv()
|
{
|
}
|
public Csv(string path)
|
{
|
LoadFile(path);
|
}
|
public Csv(DataTable dt)
|
{
|
Load(dt);
|
}
|
|
#region 私有属性
|
|
public RowList rows;
|
|
#endregion
|
|
|
#region 公有属性
|
public Encoding Encoding { get; set; } = Encoding.UTF8;
|
public int HeaderLine { get; set; } = 1;
|
public List<string> Columns { get; } = new List<string>();
|
public RowList Rows => rows ??= new RowList(this);
|
public string RemData { get; set; }
|
public string Path { get; set; }
|
public string Text { get => GetText(); set => Load(value); }
|
public Row this[int index] => Rows[index];
|
#endregion
|
|
|
public void LoadFile(string path)
|
{
|
if (!File.Exists(path))
|
throw new FileNotFoundException("访问文件不存在 : " + path);
|
|
Path = path;
|
Load(File.ReadAllText(path, Encoding));
|
}
|
|
public void Load(string text)
|
{
|
Rows.Clear();
|
Columns.Clear();
|
int index = 0;
|
|
string rowStr = "";
|
bool special = false;
|
bool isFirst = true;
|
|
|
foreach (var t in text.Replace("\r\n", "\n").Split('\n'))
|
{
|
string line = t;
|
|
rowStr += line;
|
//获取该行双引号的个数,如果是双数或为0,则为完整一行
|
//如果该行双引号个数为单数,则是非完整行,需要下次出现单数才是完整行
|
int remainder = (line.Split(new char[] { '"' }, StringSplitOptions.None).Length - 1) % 2;
|
if (remainder != 0)
|
{
|
if (special)
|
{
|
special = false;
|
}
|
else
|
{
|
rowStr += Environment.NewLine;
|
special = true;
|
continue;
|
}
|
}
|
else
|
{
|
if (special)
|
{
|
rowStr += Environment.NewLine;
|
continue;
|
}
|
}
|
|
//解析完整行的csv数据
|
string[] rowData = SplitCsvRow(rowStr);
|
rowStr = null;
|
if (isFirst && HeaderLine > 0)
|
{
|
if (++index == HeaderLine)
|
{
|
isFirst = false;
|
foreach (string colName in rowData)
|
{
|
Columns.Add(colName);
|
}
|
}
|
else
|
{
|
RemData += rowData + "\n";
|
}
|
}
|
else
|
{
|
Rows.Add(rowData);
|
}
|
}
|
if (special)
|
{
|
throw new Exception("csv文件格式错误");
|
}
|
}
|
|
public void Load(DataTable dt)
|
{
|
Rows.Clear();
|
Columns.Clear();
|
HeaderLine = 1;
|
foreach (DataColumn col in dt.Columns)
|
{
|
Columns.Add(col.ColumnName);
|
}
|
foreach (DataRow row in dt.Rows)
|
{
|
|
Rows.Add(row.ItemArray);
|
}
|
}
|
|
|
// 解析完整行的csv数据
|
private static string[] SplitCsvRow(string rowText)
|
{
|
List<string> temp = new List<string>();
|
if (rowText.IndexOf('"') < 0)
|
{
|
//无特殊字符,直接按逗号拆分
|
temp.AddRange(rowText.Split(new char[] { ',' }));
|
}
|
else
|
{
|
var spArr = rowText.Split(new char[] { ',' });
|
string cellValue = null;
|
bool special = false;
|
//有特殊字符
|
foreach (var spItem in spArr)
|
{
|
cellValue += spItem;
|
int remainder = (spItem.Split(new char[] { '"' }, StringSplitOptions.None).Length - 1) % 2;
|
if (remainder != 0)
|
{
|
if (special)
|
{
|
special = false;
|
}
|
else
|
{
|
cellValue += ',';
|
special = true;
|
continue;
|
}
|
}
|
else
|
{
|
if (special)
|
{
|
cellValue += ',';
|
continue;
|
}
|
}
|
if (special)
|
{
|
throw new Exception("csv文件行格式错误");
|
}
|
if (cellValue.Length > 2 && cellValue.Last() == '\"' && cellValue.First() == '\"')
|
temp.Add(cellValue.Remove(cellValue.Length - 1).Remove(0, 1).Replace("\"\"", "\""));
|
else
|
temp.Add(cellValue);
|
cellValue = null;
|
}
|
}
|
return temp.ToArray();
|
}
|
|
public DataTable GetDataTable()
|
{
|
DataTable dt = new DataTable();
|
|
if (Columns.Count > 0)
|
{
|
foreach (var item in Columns)
|
{
|
dt.Columns.Add(item);
|
}
|
|
int cMax = Rows.Max(q => q.Count);
|
|
while (cMax > dt.Columns.Count)
|
{
|
dt.Columns.Add(dt.Columns.Count.ToString());
|
}
|
}
|
else
|
{
|
int cMax = Rows.Max(q => q.Count);
|
if (cMax > 0)
|
{
|
for (int i = 0; i < cMax; i++)
|
{
|
dt.Columns.Add(i.ToString());
|
}
|
}
|
}
|
|
|
foreach (var row in Rows)
|
{
|
dt.Rows.Add(row.ToArray());
|
}
|
return dt;
|
}
|
|
public string GetText()
|
{
|
StringBuilder sb = new StringBuilder();
|
if (HeaderLine > 0)
|
{
|
if (string.IsNullOrWhiteSpace(RemData))
|
sb.Append(RemData);
|
foreach (var item in Columns)
|
{
|
if (item.Contains("\"") || item.Contains(","))
|
sb.Append($"\"{item.Replace("\"", "\"\"")}\",");
|
else
|
sb.Append(item + ",");
|
}
|
sb.Remove(sb.Length - 1, 1);
|
sb.Append("\r\n");
|
}
|
foreach (var row in Rows)
|
{
|
foreach (var item in row)
|
{
|
if (item.Contains("\"") || item.Contains(","))
|
sb.Append($"\"{item.Replace("\"", "\"\"")}\",");
|
else
|
sb.Append(item + ",");
|
}
|
sb.Remove(sb.Length - 1, 1);
|
sb.Append("\r\n");
|
}
|
sb.Remove(sb.Length - 2, 2);
|
return sb.ToString();
|
}
|
|
public void Save()
|
{
|
Save(Path);
|
}
|
|
public void Save(string path)
|
{
|
File.WriteAllText(path, GetText(), Encoding);
|
}
|
|
public class RowList : List<Row>
|
{
|
private readonly Csv owner;
|
|
public RowList(Csv owner)
|
{
|
this.owner = owner;
|
}
|
public Csv Csv => owner;
|
public Row Add(string[] s)
|
{
|
Row row = new Row(this);
|
row.AddRange(s.ToList());
|
Add(row);
|
return row;
|
}
|
|
public Row Add(object[] s)
|
{
|
Row row = new Row(this);
|
foreach (var item in s)
|
{
|
row.Add(item?.ToString() ?? "");
|
}
|
Add(row);
|
return row;
|
}
|
|
public Row Add(string str)
|
{
|
if (string.IsNullOrEmpty(str))
|
{
|
return null;
|
}
|
Row row = new Row(this);
|
row.AddRange(SplitCsvRow(str));
|
Add(row);
|
return row;
|
}
|
|
public Row Add()
|
{
|
Row row = new Row(this);
|
for (int i = 0; i < owner.Columns.Count; i++)
|
{
|
row.Add("");
|
}
|
Add(row);
|
return row;
|
}
|
}
|
|
public class Row : List<string>
|
{
|
public string this[string key]
|
{
|
get
|
{
|
int index = owner.Csv.Columns.IndexOf(key);
|
if (index == -1 || index > Count - 1)
|
{
|
return null;
|
}
|
else
|
{
|
return this[index];
|
}
|
}
|
set
|
{
|
int index = owner.Csv.Columns.IndexOf(key);
|
if (index == -1 || index > Count - 1)
|
{
|
return;
|
}
|
else
|
{
|
this[index] = value;
|
}
|
}
|
}
|
|
public RowList owner;
|
public Row(RowList owner)
|
{
|
this.owner = owner;
|
}
|
}
|
|
}
|
}
|