用C#写的读写CSV文件

用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 + "/"";

  }

 }

}

你可能感兴趣的:(csv)