首页 > 代码库 > C# - CSV(Comma-Separated Values)文件读取.

C# - CSV(Comma-Separated Values)文件读取.

  1 using System;  2 using System.Collections.Generic;  3 using System.Diagnostics;  4 using System.IO;  5 using System.Text;  6   7 namespace CsvFile  8 {  9     /// <summary> 10     /// Determines how empty lines are interpreted when reading CSV files. 11     /// These values do not affect empty lines that occur within quoted fields 12     /// or empty lines that appear at the end of the input file. 13     /// </summary> 14     public enum EmptyLineBehavior 15     { 16         /// <summary> 17         /// Empty lines are interpreted as a line with zero columns. 18         /// </summary> 19         NoColumns, 20         /// <summary> 21         /// Empty lines are interpreted as a line with a single empty column. 22         /// </summary> 23         EmptyColumn, 24         /// <summary> 25         /// Empty lines are skipped over as though they did not exist. 26         /// </summary> 27         Ignore, 28         /// <summary> 29         /// An empty line is interpreted as the end of the input file. 30         /// </summary> 31         EndOfFile, 32     } 33  34     /// <summary> 35     /// Common base class for CSV reader and writer classes. 36     /// </summary> 37     public abstract class CsvFileCommon 38     { 39         /// <summary> 40         /// These are special characters in CSV files. If a column contains any 41         /// of these characters, the entire column is wrapped in double quotes. 42         /// </summary> 43         protected char[] SpecialChars = new char[] { ,, ", \r, \n }; 44  45         // Indexes into SpecialChars for characters with specific meaning 46         private const int DelimiterIndex = 0; 47         private const int QuoteIndex = 1; 48  49         /// <summary> 50         /// Gets/sets the character used for column delimiters. 51         /// </summary> 52         public char Delimiter 53         { 54             get { return SpecialChars[DelimiterIndex]; } 55             set { SpecialChars[DelimiterIndex] = value; } 56         } 57  58         /// <summary> 59         /// Gets/sets the character used for column quotes. 60         /// </summary> 61         public char Quote 62         { 63             get { return SpecialChars[QuoteIndex]; } 64             set { SpecialChars[QuoteIndex] = value; } 65         } 66     } 67  68     /// <summary> 69     /// Class for reading from comma-separated-value (CSV) files 70     /// </summary> 71     public class CsvFileReader : CsvFileCommon, IDisposable 72     { 73         // Private members 74         private StreamReader Reader; 75         private string CurrLine; 76         private int CurrPos; 77         private EmptyLineBehavior EmptyLineBehavior; 78  79         /// <summary> 80         /// Initializes a new instance of the CsvFileReader class for the 81         /// specified stream. 82         /// </summary> 83         /// <param name="stream">The stream to read from</param> 84         /// <param name="emptyLineBehavior">Determines how empty lines are handled</param> 85         public CsvFileReader(Stream stream, 86             EmptyLineBehavior emptyLineBehavior = EmptyLineBehavior.NoColumns) 87         { 88             Reader = new StreamReader(stream); 89             EmptyLineBehavior = emptyLineBehavior; 90         } 91  92         /// <summary> 93         /// Initializes a new instance of the CsvFileReader class for the 94         /// specified file path. 95         /// </summary> 96         /// <param name="path">The name of the CSV file to read from</param> 97         /// <param name="emptyLineBehavior">Determines how empty lines are handled</param> 98         public CsvFileReader(string path, 99             EmptyLineBehavior emptyLineBehavior = EmptyLineBehavior.NoColumns)100         {101             Reader = new StreamReader(path);102             EmptyLineBehavior = emptyLineBehavior;103         }104 105         /// <summary>106         /// Reads a row of columns from the current CSV file. Returns false if no107         /// more data could be read because the end of the file was reached.108         /// </summary>109         /// <param name="columns">Collection to hold the columns read</param>110         public bool ReadRow(List<string> columns)111         {112             // Verify required argument113             if (columns == null)114                 throw new ArgumentNullException("columns");115 116         ReadNextLine:117             // Read next line from the file118             CurrLine = Reader.ReadLine();119             CurrPos = 0;120             // Test for end of file121             if (CurrLine == null)122                 return false;123             // Test for empty line124             if (CurrLine.Length == 0)125             {126                 switch (EmptyLineBehavior)127                 {128                     case EmptyLineBehavior.NoColumns:129                         columns.Clear();130                         return true;131                     case EmptyLineBehavior.Ignore:132                         goto ReadNextLine;133                     case EmptyLineBehavior.EndOfFile:134                         return false;135                 }136             }137 138             // Parse line139             string column;140             int numColumns = 0;141             while (true)142             {143                 // Read next column144                 if (CurrPos < CurrLine.Length && CurrLine[CurrPos] == Quote)145                     column = ReadQuotedColumn();146                 else147                     column = ReadUnquotedColumn();148                 // Add column to list149                 if (numColumns < columns.Count)150                     columns[numColumns] = column;151                 else152                     columns.Add(column);153                 numColumns++;154                 // Break if we reached the end of the line155                 if (CurrLine == null || CurrPos == CurrLine.Length)156                     break;157                 // Otherwise skip delimiter158                 Debug.Assert(CurrLine[CurrPos] == Delimiter);159                 CurrPos++;160             }161             // Remove any unused columns from collection162             if (numColumns < columns.Count)163                 columns.RemoveRange(numColumns, columns.Count - numColumns);164             // Indicate success165             return true;166         }167 168         /// <summary>169         /// Reads a quoted column by reading from the current line until a170         /// closing quote is found or the end of the file is reached. On return,171         /// the current position points to the delimiter or the end of the last172         /// line in the file. Note: CurrLine may be set to null on return.173         /// </summary>174         private string ReadQuotedColumn()175         {176             // Skip opening quote character177             Debug.Assert(CurrPos < CurrLine.Length && CurrLine[CurrPos] == Quote);178             CurrPos++;179 180             // Parse column181             StringBuilder builder = new StringBuilder();182             while (true)183             {184                 while (CurrPos == CurrLine.Length)185                 {186                     // End of line so attempt to read the next line187                     CurrLine = Reader.ReadLine();188                     CurrPos = 0;189                     // Done if we reached the end of the file190                     if (CurrLine == null)191                         return builder.ToString();192                     // Otherwise, treat as a multi-line field193                     builder.Append(Environment.NewLine);194                 }195 196                 // Test for quote character197                 if (CurrLine[CurrPos] == Quote)198                 {199                     // If two quotes, skip first and treat second as literal200                     int nextPos = (CurrPos + 1);201                     if (nextPos < CurrLine.Length && CurrLine[nextPos] == Quote)202                         CurrPos++;203                     else204                         break;  // Single quote ends quoted sequence205                 }206                 // Add current character to the column207                 builder.Append(CurrLine[CurrPos++]);208             }209 210             if (CurrPos < CurrLine.Length)211             {212                 // Consume closing quote213                 Debug.Assert(CurrLine[CurrPos] == Quote);214                 CurrPos++;215                 // Append any additional characters appearing before next delimiter216                 builder.Append(ReadUnquotedColumn());217             }218             // Return column value219             return builder.ToString();220         }221 222         /// <summary>223         /// Reads an unquoted column by reading from the current line until a224         /// delimiter is found or the end of the line is reached. On return, the225         /// current position points to the delimiter or the end of the current226         /// line.227         /// </summary>228         private string ReadUnquotedColumn()229         {230             int startPos = CurrPos;231             CurrPos = CurrLine.IndexOf(Delimiter, CurrPos);232             if (CurrPos == -1)233                 CurrPos = CurrLine.Length;234             if (CurrPos > startPos)235                 return CurrLine.Substring(startPos, CurrPos - startPos);236             return String.Empty;237         }238 239         // Propagate Dispose to StreamReader240         public void Dispose()241         {242             Reader.Dispose();243         }244     }245 246     /// <summary>247     /// Class for writing to comma-separated-value (CSV) files.248     /// </summary>249     public class CsvFileWriter : CsvFileCommon, IDisposable250     {251         // Private members252         private StreamWriter Writer;253         private string OneQuote = null;254         private string TwoQuotes = null;255         private string QuotedFormat = null;256 257         /// <summary>258         /// Initializes a new instance of the CsvFileWriter class for the259         /// specified stream.260         /// </summary>261         /// <param name="stream">The stream to write to</param>262         public CsvFileWriter(Stream stream)263         {264             Writer = new StreamWriter(stream);265         }266 267         /// <summary>268         /// Initializes a new instance of the CsvFileWriter class for the269         /// specified file path.270         /// </summary>271         /// <param name="path">The name of the CSV file to write to</param>272         public CsvFileWriter(string path)273         {274             Writer = new StreamWriter(path);275         }276 277         /// <summary>278         /// Writes a row of columns to the current CSV file.279         /// </summary>280         /// <param name="columns">The list of columns to write</param>281         public void WriteRow(List<string> columns)282         {283             // Verify required argument284             if (columns == null)285                 throw new ArgumentNullException("columns");286 287             // Ensure we‘re using current quote character288             if (OneQuote == null || OneQuote[0] != Quote)289             {290                 OneQuote = String.Format("{0}", Quote);291                 TwoQuotes = String.Format("{0}{0}", Quote);292                 QuotedFormat = String.Format("{0}{{0}}{0}", Quote);293             }294 295             // Write each column296             for (int i = 0; i < columns.Count; i++)297             {298                 // Add delimiter if this isn‘t the first column299                 if (i > 0)300                     Writer.Write(Delimiter);301                 // Write this column302                 if (columns[i].IndexOfAny(SpecialChars) == -1)303                     Writer.Write(columns[i]);304                 else305                     Writer.Write(QuotedFormat, columns[i].Replace(OneQuote, TwoQuotes));306             }307             Writer.WriteLine();308         }309 310         // Propagate Dispose to StreamWriter311         public void Dispose()312         {313             Writer.Dispose();314         }315     }316 }

 

C# - CSV(Comma-Separated Values)文件读取.