CSV文件本质是一种用逗号和(回车)换行符分割的文本文件,可以直接用Excel打开
* CSV (逗号分隔值文件格式)Comma-Separated Values 【每一行的分割符必须是英文的逗号,不能是中文的逗号】
* 逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。
* 纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。
* CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。
* 通常,所有记录都有完全相同的字段序列。通常都是纯文本文件.
* 建议使用WORDPAD或是记事本来开启,再则先另存新档后用EXCEL开启,也是方法之一。
*
* CSV格式是分隔的数据格式,有字段/列分隔的逗号字符和记录/行分隔换行符。
* 字段包含特殊字符(逗号,换行符,或双引号),必须以双引号括住。行内包含一个项目是空字符串,可以以双引号括住。
* 字段的值包含双引号时,要双写这个双引号(就像把一个双引号当做转义符一样)。
* CSV文件格式并不需要特定的字符编码,字节顺序,或行终止格式。
* 每个记录是一个行终止换行符(ASCII码/LF = 0x0A) 或 回车换行符(ASCII码/CRLF = 0x0D0A)。
* 0x0A【换行符】 在C#中代表字符 '\n'
* 0x0D0A【回车换行】 在C#中代表字符串 "\r\n"
*
* 转义(Escaped)要求:
* 包含逗号, 双引号, 或是换行符的字段必须放在引号内.【使用引号来进行特殊符号 Escaped转义】
* 字段内部的引号必须在其前面增加一个引号来实现文字引号的转码.
*
* 规则:
* 1 开头是不留空,以行为单位。
* 2 可含或不含列名,含列名则居文件第一行。
* 3 一行数据不跨行,无空行。
* 4 以半角英文逗号(即,)作分隔符,列为空也要表达其存在。
* 5 列内容如存在半角引号(即"),替换成半角双引号("")转义,即用半角引号(即"")将该字段值包含起来。
* 6 文件读写时引号,逗号操作规则互逆。
* 7 内码格式不限,可为 ASCII、Unicode 或者其他。
* 8 不支持数字
* 9 不支持特殊字符
我们使用时,如果不对引号 或者 逗号 进行特殊处理,使用Excel打开就会排列不美观,如图:
如果进行转义(Escaped)处理,如图:
对CSV文件的每一项都进行转义处理,关键函数如下:
///
/// 处理csv文件中的双引号和逗号,使其在Excel中完美显示为一个单元格
/// 斯内科 20210321
///
///
///
private static string ProcessPunctuationForCsv(string srcStr)
{
if (srcStr == null)
{
return string.Empty;
}
bool quoteFlag = false;//是否添加过双引号
//如果存在双引号,需要将字符串的一个双引号 替换为 两个双引号。并且需要在字符串的前后加上双引号
if (srcStr.Contains("\""))
{
srcStr = srcStr.Replace("\"", "\"\"");
srcStr = "\"" + srcStr + "\"";
quoteFlag = true;
}
//如果只存在逗号(不存在引号),将前后加引号即可
if (srcStr.Contains(",") && !quoteFlag)
{
srcStr = "\"" + srcStr + "\"";
}
return srcStr;
}
新建窗体应用程序CsvFileEscapedDemo,将默认的Form1重命名为 FormCsvFileEscaped
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CsvFileEscapedDemo
{
///
/// 员工信息
///
public class Employee
{
public Employee()
{
this.ListSkills = new List();
}
///
/// 编号
///
public int CoreId { get; set; }
///
/// 姓名
///
public string EmployeeName { get; set; }
///
/// 地址
///
public string Address { get; set; }
///
/// 技能列表
///
public List ListSkills { get; set; }
}
}
相关程序如下:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CsvFileEscapedDemo
{
///
/// 对CSV文件进行读写
///
public class CsvUtil
{
/*
* 1:csv与Excel本质区别是文本文件
* 2:每个单元格的数据用,分割
* 3:每行的数据用\r\n分割
*/
private static Object thisLock = new Object();
///
/// 创建Csv
///
/// 路径
/// 名称
///
public static bool CreateCsv(string _path, string _name)
{
lock (thisLock)
{
try
{
using (File.Create(_path + _name + ".csv"))
{
}
return true;
}
catch (Exception)
{
return false;
}
}
}
///
/// 删除Csv
///
/// 路径
/// 名称
///
public static bool DeleteCsv(string _path, string _name)
{
string _tmPath = _path + _name + ".csv";
lock (thisLock)
{
try
{
if (File.Exists(_tmPath) == true)
{
File.Delete(_tmPath);
return true;
}
else
{
return false;
}
}
catch (Exception e)
{
MessageBox.Show("CSV文件删除失败:" + e.Message);
return false;
}
}
}
///
/// 读取csv
///
/// 路径,如 @"D:\MESLog\ABC\"
/// 名称,不带.csv
/// 读取到的数据
///
public static bool ReadCsv(string _path, string _name, ref List _recvData)
{
return ReadCsv(Path.Combine(_path, _name + ".csv"), ref _recvData);
}
///
/// 读取csv
///
/// 路径,如 @"D:\MESLog\ABC\"
/// 名称,不带.csv
/// 读取到的数据
/// 异常信息
///
public static bool ReadCsv(string _path, string _name, ref List _recvData, ref string errorMsg)
{
return ReadCsv(Path.Combine(_path, _name + ".csv"), ref _recvData, ref errorMsg);
}
///
/// 读取csv文件
///
/// 全路径
/// 返回的值
///
public static bool ReadCsv(string fullfilePath, ref List recvData)
{
string errorMsg = "";
return ReadCsv(fullfilePath, ref recvData, ref errorMsg);
}
///
/// 读取csv文件
///
/// 全路径
/// 返回的值
///
public static bool ReadCsv(string fullfilePath, ref List recvData, ref string errorMsg)
{
lock (thisLock)
{
try
{
if (!fullfilePath.Contains(".csv"))
{
errorMsg = "路径中没有.csv后缀";
return false;
}
string _tmPath = fullfilePath;
using (StreamReader reader = new StreamReader(_tmPath, Encoding.Default))
{
string _lin = reader.ReadToEnd().Trim();
string[] _str = _lin.Split('\n');
recvData.Clear();
for (int i = 0; i < _str.Length; i++)
{
_str[i] = _str[i].TrimEnd('\r');
recvData.Add(_str[i].Split(','));
}
}
return true;
}
catch (Exception e)
{
errorMsg = e.Message;
MessageBox.Show("CSV文件读取失败:" + e.Message);
return false;
}
}
}
///
/// 写入csv文件
///
/// 路径,如 @"D:\MESLog\ABC\"
/// 名称,不带.csv
/// 需要写入的数据
/// 是否拼接
///
public static bool WriteCsv(string _path, string _name, List _writeData, bool _append)
{
return WriteCsv(Path.Combine(_path, _name + ".csv"), _writeData, _append);
}
///
/// 写入csv文件
///
/// 路径,如 @"D:\MESLog\ABC\"
/// 名称,不带.csv
/// 需要写入的数据
/// 是否拼接
///
public static bool WriteCsv(string _path, string _name, List _writeData, bool _append, ref string errorMsg)
{
return WriteCsv(Path.Combine(_path, _name + ".csv"), _writeData, _append, ref errorMsg);
}
///
/// 写入csv文件
///
/// 文件全路径
/// 需要写入的数据
/// 是否拼接
///
public static bool WriteCsv(string fullfilePath, List writeData, bool append)
{
string errorMsg = "";
return WriteCsv(fullfilePath, writeData, append, ref errorMsg);
}
///
/// 写入csv文件【不使用Escaped转义】
///
/// 文件全路径
/// 需要写入的数据
/// 是否拼接
///
public static bool WriteCsv(string fullfilePath, List _writeData, bool _append, ref string errorMsg)
{
lock (thisLock)
{
try
{
if (fullfilePath.Length < 1)
{
return false;
}
string directoryName = System.IO.Path.GetDirectoryName(fullfilePath);
//================判断文件夹是否存在,不存在就创建=====================================//
DirectoryInfo directoryInfo = new DirectoryInfo(directoryName);
if (!directoryInfo.Exists)
{
directoryInfo.Create();
}
//=====================================================//
if (!fullfilePath.Contains(".csv"))
{
errorMsg = "路径中没有.csv后缀";
return false;
}
string _tmPath = fullfilePath;
using (StreamWriter write = new StreamWriter(_tmPath, _append, Encoding.Default))
{
foreach (string[] strArr in _writeData)
{
write.WriteLine(string.Join(",", strArr));
}
}
return true;
}
catch (Exception e)
{
errorMsg = e.Message;
MessageBox.Show("CSV文件写入失败:" + e.Message);
return false;
}
}
}
///
/// 写入csv文件【使用双引号进行Escaped转义】
///
///
///
///
///
///
public static bool WriteCsvWithEscaped(string fullfilePath, List _writeData, bool _append, ref string errorMsg)
{
errorMsg = "";
if (_writeData == null)
{
errorMsg = "没有要写入的csv数据";
return false;
}
//修正所有元素
for (int i = 0; i < _writeData.Count; i++)
{
string[] dataArray = _writeData[i];
for (int j = 0; dataArray != null && j < dataArray.Length; j++)
{
dataArray[j] = ProcessPunctuationForCsv(dataArray[j]);
}
_writeData[i] = dataArray;
}
return WriteCsv(fullfilePath, _writeData, _append, ref errorMsg);
}
///
/// 处理csv文件中的双引号和逗号,使其在Excel中完美显示为一个单元格
/// 斯内科 20210321
///
///
///
private static string ProcessPunctuationForCsv(string srcStr)
{
if (srcStr == null)
{
return string.Empty;
}
bool quoteFlag = false;//是否添加过双引号
//如果存在双引号,需要将字符串的一个双引号 替换为 两个双引号。并且需要在字符串的前后加上双引号
if (srcStr.Contains("\""))
{
srcStr = srcStr.Replace("\"", "\"\"");
srcStr = "\"" + srcStr + "\"";
quoteFlag = true;
}
//如果只存在逗号(不存在引号),将前后加引号即可
if (srcStr.Contains(",") && !quoteFlag)
{
srcStr = "\"" + srcStr + "\"";
}
return srcStr;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CsvFileEscapedDemo
{
public partial class FormCsvFileEscaped : Form
{
public FormCsvFileEscaped()
{
InitializeComponent();
}
private void btnCsvWithoutEscaped_Click(object sender, EventArgs e)
{
//添加对 System.Web.Extensions的引用
System.Web.Script.Serialization.JavaScriptSerializer javaScriptSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
Employee employee = new Employee()
{
CoreId = 1,
EmployeeName = "徐暮云",
Address = "洛阳",
ListSkills = new List() { "疾风怒涛", "混沌千秋", "寒溟化蛟" }
};
string jsonString = javaScriptSerializer.Serialize(employee);
string errorMsg = "";
List writeData = new List();
writeData.Add(new string[] { "编号", employee.CoreId.ToString() });
writeData.Add(new string[] { "姓名", employee.EmployeeName });
writeData.Add(new string[] { "地址", employee.Address });
writeData.Add(new string[] { "技能列表", string.Join(",", employee.ListSkills) });
writeData.Add(new string[] { "Json对象", jsonString });
string fileName = AppDomain.CurrentDomain.BaseDirectory + "sword5\\xumuyun.csv";
bool result = CsvUtil.WriteCsv(fileName, writeData, true, ref errorMsg);
MessageBox.Show($"写入CSV文件的结果:{result}\n路径:{fileName}");
}
private void btnCsvWithEscaped_Click(object sender, EventArgs e)
{
//添加对 System.Web.Extensions的引用
System.Web.Script.Serialization.JavaScriptSerializer javaScriptSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
Employee employee = new Employee()
{
CoreId = 3,
EmployeeName = "皇甫朝云",
Address = "成都",
ListSkills = new List() { "轩辕服太虚", "持国护天" }
};
string jsonString = javaScriptSerializer.Serialize(employee);
string errorMsg = "";
List writeData = new List();
writeData.Add(new string[] { "编号", employee.CoreId.ToString() });
writeData.Add(new string[] { "姓名", employee.EmployeeName });
writeData.Add(new string[] { "地址", employee.Address });
writeData.Add(new string[] { "技能列表", string.Join(",", employee.ListSkills) });
writeData.Add(new string[] { "Json对象", jsonString });
string fileName = AppDomain.CurrentDomain.BaseDirectory + "sword5\\huangfuzhaoyun.csv";
bool result = CsvUtil.WriteCsvWithEscaped(fileName, writeData, true, ref errorMsg);
MessageBox.Show($"写入CSV文件的结果:{result}\n路径:{fileName}");
}
}
}