用C#写的读写CSV文件

坚强是说给别人听的谎言 提交于 2020-02-17 07:04:21

用C#写的读取CSV文件的源代码

CSV文件的格子中包含逗号,引号,换行等,都能轻松读取,而且可以把数据转化成DATATABLE格式

using System;
using System.Text;
using System.Collections;
using System.IO;
using System.Data;
using System.Text.RegularExpressions;
using System.Diagnostics;
 
namespace CsvLib
{
 #region 类说明信息
 
 /// <summary>
 ///  <DL>
 ///  <DT><b>读CSV文件类,读取指定的CSV文件,可以导出DataTable</b></DT>
 ///   <DD>
 ///    <UL> 
 ///    </UL>
 ///   </DD>
 ///  </DL>
 ///  <Author>yangzhihong</Author>   
 ///  <CreateDate>2006/01/16</CreateDate>
 ///  <Company></Company>
 ///  <Version>1.0</Version>
 /// </summary>
 #endregion
 public class CsvStreamReader
 {
  private  ArrayList  rowAL;        //行链表,CSV文件的每一行就是一个链
  private  string  fileName;       //文件名
 
  private  Encoding encoding;       //编码
 
  public CsvStreamReader()
  {
   this.rowAL = new ArrayList();   
   this.fileName = "";
   this.encoding = Encoding.Default;
  }
 
  /// <summary>
  ///
  /// </summary>
  /// <param name="fileName">文件名,包括文件路径</param>
  public CsvStreamReader(string fileName)
  {
   this.rowAL = new ArrayList();    
   this.fileName = fileName;
   this.encoding = Encoding.Default;
   LoadCsvFile();
  }
 
  /// <summary>
  ///
  /// </summary>
  /// <param name="fileName">文件名,包括文件路径</param>
  /// <param name="encoding">文件编码</param>
  public CsvStreamReader(string fileName,Encoding encoding)
  {
   this.rowAL = new ArrayList();  
   this.fileName = fileName;
   this.encoding = encoding;
   LoadCsvFile();
  }
 
  /// <summary>
  /// 文件名,包括文件路径
  /// </summary>
  public string FileName
  {
   set
   {
    this.fileName = value;
    LoadCsvFile();
   }
  }
 
  /// <summary>
  /// 文件编码
  /// </summary>
 
  public Encoding FileEncoding
  {
   set
   {
    this.encoding = value;
   }
  }
 
  /// <summary>
  /// 获取行数
  /// </summary>
  public int RowCount
  {
   get
   {
    return this.rowAL.Count;
   }
  }
 
  /// <summary>
  /// 获取列数
  /// </summary>
  public int ColCount
  {
   get
   {
    int maxCol;
 
    maxCol = 0;
    for (int i = 0;i<this.rowAL.Count;i++)
    {
     ArrayList colAL = (ArrayList) this.rowAL[i];
 
     maxCol = (maxCol > colAL.Count)?maxCol:colAL.Count;
    }
 
    return maxCol;
   }
  }
 
 
  /// <summary>
  /// 获取某行某列的数据
 
  /// row:行,row = 1代表第一行
 
  /// col:列,col = 1代表第一列  
  /// </summary>
  public string this[int row,int col]
  {
   get
   {   
    //数据有效性验证
 
    CheckRowValid(row);
    CheckColValid(col);
    ArrayList colAL = (ArrayList) this.rowAL[row-1];
 
    //如果请求列数据大于当前行的列时,返回空值
 
    if (colAL.Count < col)
    {
     return "";
    }
     
                return colAL[col-1].ToString();    
   }
  }
 
 
  /// <summary>
  /// 根据最小行,最大行,最小列,最大列,来生成一个DataTable类型的数据
 
  /// 行等于1代表第一行
 
  /// 列等于1代表第一列
 
  /// maxrow: -1代表最大行
  /// maxcol: -1代表最大列
  /// </summary>
  public DataTable this[int minRow,int maxRow,int minCol,int maxCol]
  {
   get
   {
    //数据有效性验证
 
    CheckRowValid(minRow);
    CheckMaxRowValid(maxRow);
    CheckColValid(minCol);
    CheckMaxColValid(maxCol);
    if (maxRow == -1)
    {
     maxRow = RowCount;
    }
    if (maxCol == -1)
    {
     maxCol = ColCount;
    }
    if (maxRow < minRow)
    {
     throw new Exception("最大行数不能小于最小行数");
    }
    if (maxCol < minCol)
    {
     throw new Exception("最大列数不能小于最小列数");
    }
    DataTable csvDT = new DataTable();
    int   i;
    int   col;
    int   row;
 
    //增加列
 
    for (i = minCol;i <= maxCol;i++)
    {
     csvDT.Columns.Add(i.ToString());
    }
    for (row = minRow;row <= maxRow;row++)
    {
     DataRow csvDR = csvDT.NewRow();
 
     i = 0;
     for (col = minCol;col <=maxCol;col++)
     {
      csvDR[i] = this[row,col];
      i++;
     }
     csvDT.Rows.Add(csvDR);
    }
 
    return csvDT;
   }
  }
 
 
  /// <summary>
  /// 检查行数是否是有效的
 
  /// </summary>
  /// <param name="col"></param>  
  private void CheckRowValid(int row)
  {
   if (row <= 0)
   {
    throw new Exception("行数不能小于0");    
   } 
   if (row > RowCount)
   {
    throw new Exception("没有当前行的数据");   
   }  
  }
 
  /// <summary>
  /// 检查最大行数是否是有效的
 
  /// </summary>
  /// <param name="col"></param>  
  private void CheckMaxRowValid(int maxRow)
  {
   if (maxRow <= 0 && maxRow != -1)
   {
    throw new Exception("行数不能等于0或小于-1");    
   } 
   if (maxRow > RowCount)
   {
    throw new Exception("没有当前行的数据");   
   }  
  }
 
  /// <summary>
  /// 检查列数是否是有效的
 
  /// </summary>
  /// <param name="col"></param>  
  private void CheckColValid(int col)
  {
   if (col <= 0)
   {
    throw new Exception("列数不能小于0");    
   } 
   if (col > ColCount)
   {
    throw new Exception("没有当前列的数据");   
   }
  }
 
  /// <summary>
  /// 检查检查最大列数是否是有效的
 
  /// </summary>
  /// <param name="col"></param>  
  private void CheckMaxColValid(int maxCol)
  {
   if (maxCol <= 0 && maxCol != -1)
   {
    throw new Exception("列数不能等于0或小于-1");    
   } 
   if (maxCol > ColCount)
   {
    throw new Exception("没有当前列的数据");   
   }
  }
 
  /// <summary>
  /// 载入CSV文件
  /// </summary>
  private void LoadCsvFile()
  {
   //对数据的有效性进行验证
 
   if (this.fileName == null)
   {
    throw new Exception("请指定要载入的CSV文件名");
   }
   else if (!File.Exists(this.fileName))
   {
    throw new Exception("指定的CSV文件不存在");
   }
   else
   {
   }
   if (this.encoding == null)
   {
    this.encoding = Encoding.Default;
   }
 
   StreamReader sr = new StreamReader(this.fileName,this.encoding); 
   string   csvDataLine;
    
   csvDataLine = "";
   while (true)
   {
    string fileDataLine;
 
    fileDataLine = sr.ReadLine();
    if (fileDataLine == null)
    {
     break;
    }
    if (csvDataLine == "")
    {
     csvDataLine = fileDataLine;//GetDeleteQuotaDataLine(fileDataLine);
    }
    else
    {
     csvDataLine += "/r/n" + fileDataLine;//GetDeleteQuotaDataLine(fileDataLine);
    }
    //如果包含偶数个引号,说明该行数据中出现回车符或包含逗号
    if (!IfOddQuota(csvDataLine))
    {
     AddNewDataLine(csvDataLine);
     csvDataLine = "";
    }
   }           
   sr.Close();
   //数据行出现奇数个引号
   if (csvDataLine.Length > 0)
   {
    throw new Exception("CSV文件的格式有错误");
   }
  }
 
  /// <summary>
  /// 获取两个连续引号变成单个引号的数据行
  /// </summary>
  /// <param name="fileDataLine">文件数据行</param>
  /// <returns></returns>
  private string GetDeleteQuotaDataLine(string fileDataLine)
  {
   return fileDataLine.Replace("/"/"","/"");
  }
 
  /// <summary>
  /// 判断字符串是否包含奇数个引号
  /// </summary>
  /// <param name="dataLine">数据行</param>
  /// <returns>为奇数时,返回为真;否则返回为假</returns>
  private bool IfOddQuota(string dataLine)
  {
   int  quotaCount;
   bool oddQuota;
 
   quotaCount = 0;
   for (int i = 0;i < dataLine.Length;i++)
   {
    if (dataLine[i] == '/"')
    {
     quotaCount++;
    }
   }
 
   oddQuota = false;
   if (quotaCount % 2 == 1)
   {
    oddQuota = true;
   }   
 
   return oddQuota;
  }
 
  /// <summary>
  /// 判断是否以奇数个引号开始
 
  /// </summary>
  /// <param name="dataCell"></param>
  /// <returns></returns>
  private bool IfOddStartQuota(string dataCell)
  {
   int  quotaCount;
   bool oddQuota;
 
   quotaCount = 0;
   for (int i = 0;i < dataCell.Length;i++)
   {
    if (dataCell[i] == '/"')
    {
     quotaCount++;
    }
    else
    {
     break;
    }
   }
 
   oddQuota = false;
   if (quotaCount % 2 == 1)
   {
    oddQuota = true;
   }   
 
   return oddQuota;
  }
 
  /// <summary>
  /// 判断是否以奇数个引号结尾
  /// </summary>
  /// <param name="dataCell"></param>
  /// <returns></returns>
  private bool IfOddEndQuota(string dataCell)
  {
   int  quotaCount;
   bool oddQuota;
 
   quotaCount = 0;
   for (int i = dataCell.Length -1;i >= 0;i--)
   {
    if (dataCell[i] == '/"')
    {
     quotaCount++;
    }
    else
    {
     break;
    }
   }
 
   oddQuota = false;
   if (quotaCount % 2 == 1)
   {
    oddQuota = true;
   }   
 
   return oddQuota;
  }
 
  /// <summary>
  /// 加入新的数据行
 
  /// </summary>
  /// <param name="newDataLine">新的数据行</param>
  private void AddNewDataLine(string newDataLine)
  {
   Debug.WriteLine("NewLine:" + newDataLine);
 
   //return;
 
   ArrayList colAL = new ArrayList();
   string[] dataArray = newDataLine.Split(',');
   bool  oddStartQuota;       //是否以奇数个引号开始
 
   string      cellData;
 
   oddStartQuota = false;
   cellData = "";
   for (int i = 0 ;i < dataArray.Length;i++)
   {
    if (oddStartQuota)
    {
     //因为前面用逗号分割,所以要加上逗号
     cellData += "," + dataArray[i];
     //是否以奇数个引号结尾
     if (IfOddEndQuota(dataArray[i]))
     {
      colAL.Add(GetHandleData(cellData));
      oddStartQuota = false;
      continue;
     }
    }
    else
    {
     //是否以奇数个引号开始
 
     if (IfOddStartQuota(dataArray[i]))
     {
      //是否以奇数个引号结尾,不能是一个双引号,并且不是奇数个引号
 
      if (IfOddEndQuota(dataArray[i]) && dataArray[i].Length > 2 && !IfOddQuota(dataArray[i]))
      {
       colAL.Add(GetHandleData(dataArray[i]));
       oddStartQuota = false;
       continue;
      }
      else
      {
 
       oddStartQuota = true;  
       cellData = dataArray[i];
       continue;
      }
     } 
     else
     {
      colAL.Add(GetHandleData(dataArray[i])); 
     }
    }           
   }
   if (oddStartQuota)
   {
    throw new Exception("数据格式有问题");
   }
   this.rowAL.Add(colAL);
  }
 
 
  /// <summary>
  /// 去掉格子的首尾引号,把双引号变成单引号
 
  /// </summary>
  /// <param name="fileCellData"></param>
  /// <returns></returns>
  private string GetHandleData(string fileCellData)
  {
   if (fileCellData == "")
   {
    return "";
   }
   if (IfOddStartQuota(fileCellData))
   {
    if (IfOddEndQuota(fileCellData))
    {
     return fileCellData.Substring(1,fileCellData.Length-2).Replace("/"/"","/""); //去掉首尾引号,然后把双引号变成单引号
    }
    else
    {
     throw new Exception("数据引号无法匹配" + fileCellData);
    }    
   }
   else
   {
    //考虑形如""    """"      """"""   
    if (fileCellData.Length >2 && fileCellData[0] == '/"')
    {
     fileCellData = fileCellData.Substring(1,fileCellData.Length-2).Replace("/"/"","/""); //去掉首尾引号,然后把双引号变成单引号
    }
   }
 
   return fileCellData;
  }
 }
}
 
  
 
using System;
using System.Text;
using System.Collections;
using System.IO;
using System.Data;
 
namespace CsvLib
{
 #region 类说明信息
 /// <summary>
 ///  <DL>
 ///  <DT><b>写CSV文件类,首先给CSV文件赋值,最后通过Save方法进行保存操作</b></DT>
 ///   <DD>
 ///    <UL> 
 ///    </UL>
 ///   </DD>
 ///  </DL>
 ///  <Author>yangzhihong</Author>   
 ///  <CreateDate>2006/01/16</CreateDate>
 ///  <Company></Company>
 ///  <Version>1.0</Version>
 /// </summary>
 #endregion
 public class CsvStreamWriter
 {  
  private  ArrayList  rowAL;        //行链表,CSV文件的每一行就是一个链
  private  string  fileName;       //文件名
  private  Encoding encoding;       //编码
 
  public CsvStreamWriter()
  {
   this.rowAL = new ArrayList();   
   this.fileName = "";
   this.encoding = Encoding.Default;
  }
 
  /// <summary>
  ///
  /// </summary>
  /// <param name="fileName">文件名,包括文件路径</param>
  public CsvStreamWriter(string fileName)
  {
   this.rowAL = new ArrayList();    
   this.fileName = fileName;
   this.encoding = Encoding.Default;
  }
 
  /// <summary>
  ///
  /// </summary>
  /// <param name="fileName">文件名,包括文件路径</param>
  /// <param name="encoding">文件编码</param>
  public CsvStreamWriter(string fileName,Encoding encoding)
  {
   this.rowAL = new ArrayList();  
   this.fileName = fileName;
   this.encoding = encoding;
  }
 
  /// <summary>
  /// row:行,row = 1代表第一行
  /// col:列,col = 1代表第一列
  /// </summary>
  public string this[int row,int col]
  {
   set
   {
    //对行进行判断
    if (row <= 0)
    {
     throw new Exception("行数不能小于0");
    }    
    else if (row > this.rowAL.Count) //如果当前列链的行数不够,要补齐
    {
     for (int i = this.rowAL.Count + 1;i <= row;i++)
     {
      this.rowAL.Add(new ArrayList());
     }
    }
    else
    {
    }
    //对列进行判断
    if (col <= 0)
    {
     throw new Exception("列数不能小于0");
    }
    else
    {
     ArrayList colTempAL = (ArrayList) this.rowAL[row-1];
 
     //扩大长度
     if (col > colTempAL.Count)
     {
      for (int i = colTempAL.Count;i <= col;i++)
      {
       colTempAL.Add("");
      }
     }
     this.rowAL[row-1] = colTempAL;
    }
    //赋值
    ArrayList colAL = (ArrayList) this.rowAL[row-1];
 
    colAL[col-1] = value;
    this.rowAL[row-1] = colAL;
   }
  }
 
 
  /// <summary>
  /// 文件名,包括文件路径
  /// </summary>
  public string FileName
  {
   set
   {
    this.fileName = value;
   }
  }
 
  /// <summary>
  /// 文件编码
  /// </summary>
 
  public Encoding FileEncoding
  {
   set
   {
    this.encoding = value;
   }
  }
 
  /// <summary>
  /// 获取当前最大行
  /// </summary>
  public int CurMaxRow
  {
   get
   {
    return this.rowAL.Count;
   }
  }
 
  /// <summary>
  /// 获取最大列
  /// </summary>
  public int CurMaxCol
  {
   get
   {
    int maxCol;
 
    maxCol = 0;
    for (int i = 0;i<this.rowAL.Count;i++)
    {
     ArrayList colAL = (ArrayList) this.rowAL[i];
 
     maxCol = (maxCol > colAL.Count)?maxCol:colAL.Count;
    }
 
    return maxCol;
   }
  }
 
  /// <summary>
  /// 添加表数据到CSV文件中
  /// </summary>
  /// <param name="dataDT">表数据</param>
  /// <param name="beginCol">从第几列开始,beginCol = 1代表第一列</param>
  public void AddData(DataTable dataDT,int beginCol)
  {
   if (dataDT == null)
   {
    throw new Exception("需要添加的表数据为空");
   }
   int curMaxRow;
 
   curMaxRow = this.rowAL.Count;
   for (int i = 0;i < dataDT.Rows.Count;i++)
   {
    for (int j = 0;j <dataDT.Columns.Count;j++)
    {
     this[curMaxRow + i + 1,beginCol + j] = dataDT.Rows[i][j].ToString();     
    }
   }
  }
 
  /// <summary>
  /// 保存数据,如果当前硬盘中已经存在文件名一样的文件,将会覆盖
  /// </summary>
  public void Save()
  {
   //对数据的有效性进行判断
   if (this.fileName == null)
   {
    throw new Exception("缺少文件名");
   }
   else if (File.Exists(this.fileName))
   {
    File.Delete(this.fileName);
   }
   if (this.encoding == null)
   {
    this.encoding = Encoding.Default;
   }
   System.IO.StreamWriter sw = new StreamWriter(this.fileName,false,this.encoding);
 
   for (int i = 0 ;i < this.rowAL.Count;i++)
   {
    sw.WriteLine(ConvertToSaveLine((ArrayList) this.rowAL[i]));    
   }
 
   sw.Close();
  }
 
  /// <summary>
  /// 保存数据,如果当前硬盘中已经存在文件名一样的文件,将会覆盖
  /// </summary>
  /// <param name="fileName">文件名,包括文件路径</param>
  public void Save(string fileName)
  {
   this.fileName = fileName;
   Save();
  }
 
  /// <summary>
  /// 保存数据,如果当前硬盘中已经存在文件名一样的文件,将会覆盖
  /// </summary>
  /// <param name="fileName">文件名,包括文件路径</param>
  /// <param name="encoding">文件编码</param>
  public void Save(string fileName,Encoding encoding)
  {
   this.fileName = fileName;
   this.encoding = encoding;
   Save();
  }
 
 
  /// <summary>
  /// 转换成保存行
  /// </summary>
  /// <param name="colAL">一行</param>
  /// <returns></returns>
  private string ConvertToSaveLine(ArrayList colAL)
  {
   string saveLine;
 
   saveLine = "";
   for (int i = 0;i< colAL.Count;i++)
   {
    saveLine += ConvertToSaveCell(colAL[i].ToString());
    //格子间以逗号分割
    if (i < colAL.Count - 1)
    {
     saveLine += ",";
    }    
   }
 
   return saveLine;
  }
 
  /// <summary>
  /// 字符串转换成CSV中的格子
  /// 双引号转换成两个双引号,然后首尾各加一个双引号
  /// 这样就不需要考虑逗号及换行的问题
  /// </summary>
  /// <param name="cell">格子内容</param>
  /// <returns></returns>
  private string ConvertToSaveCell(string cell)
  {
   cell = cell.Replace("/"","/"/"");
   
   return "/"" + cell + "/"";
  }
 }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!