www.pudn.com > VWAP.zip > CVSReader.cs


using System; 
using System.Collections; 
using System.IO; 
using System.Text; 
 
 
	///  
	/// A data-reader style interface for reading CSV files. 
	///  
	public class CSVReader : IDisposable  
	{ 
 
		#region Private variables 
 
		private Stream stream; 
		private StreamReader reader; 
 
		#endregion 
 
		///  
		/// Create a new reader for the given stream. 
		///  
		/// The stream to read the CSV from. 
		public CSVReader(Stream s) : this(s, null) { } 
 
		///  
		/// Create a new reader for the given stream and encoding. 
		///  
		/// The stream to read the CSV from. 
		/// The encoding used. 
		public CSVReader(Stream s, Encoding enc)  
		{ 
 
			this.stream = s; 
			if (!s.CanRead)  
			{ 
				throw new CSVReaderException("Could not read the given CSV stream!"); 
			} 
			reader = (enc != null) ? new StreamReader(s, enc) : new StreamReader(s); 
		} 
 
		///  
		/// Creates a new reader for the given text file path. 
		///  
		/// The name of the file to be read. 
		public CSVReader(string filename) : this(filename, null) { } 
 
		///  
		/// Creates a new reader for the given text file path and encoding. 
		///  
		/// The name of the file to be read. 
		/// The encoding used. 
		public CSVReader(string filename, Encoding enc)  
			: this(new FileStream(filename, FileMode.Open), enc) { } 
 
		///  
		/// Returns the fields for the next row of CSV data (or null if at eof) 
		///  
		/// A string array of fields or null if at the end of file. 
		public string[] GetCSVLine()  
		{ 
 
			string data = reader.ReadLine(); 
			if (data == null) return null; 
			if (data.Length == 0) return new string[0]; 
       
			ArrayList result = new ArrayList(); 
 
			ParseCSVFields(result, data); 
       
			return (string[])result.ToArray(typeof(string)); 
		} 
 
		// Parses the CSV fields and pushes the fields into the result arraylist 
		private void ParseCSVFields(ArrayList result, string data)  
		{ 
 
			int pos = -1; 
			while (pos < data.Length) 
				result.Add(ParseCSVField(data, ref pos)); 
		} 
 
		// Parses the field at the given position of the data, modified pos to match 
		// the first unparsed position and returns the parsed field 
		private string ParseCSVField(string data, ref int startSeparatorPosition)  
		{ 
 
			if (startSeparatorPosition == data.Length-1)  
			{ 
				startSeparatorPosition++; 
				// The last field is empty 
				return ""; 
			} 
 
			int fromPos = startSeparatorPosition + 1; 
 
			// Determine if this is a quoted field 
			if (data[fromPos] == '"')  
			{ 
				// If we're at the end of the string, let's consider this a field that 
				// only contains the quote 
				if (fromPos == data.Length-1)  
				{ 
					fromPos++; 
					return "\""; 
				} 
 
				// Otherwise, return a string of appropriate length with double quotes collapsed 
				// Note that FSQ returns data.Length if no single quote was found 
				int nextSingleQuote = FindSingleQuote(data, fromPos+1); 
				startSeparatorPosition = nextSingleQuote+1; 
				return data.Substring(fromPos+1, nextSingleQuote-fromPos-1).Replace("\"\"", "\""); 
			} 
 
			// The field ends in the next comma or EOL 
			int nextComma = data.IndexOf(',', fromPos); 
			if (nextComma == -1)  
			{ 
				startSeparatorPosition = data.Length; 
				return data.Substring(fromPos); 
			} 
			else  
			{ 
				startSeparatorPosition = nextComma; 
				return data.Substring(fromPos, nextComma-fromPos); 
			} 
		} 
 
		// Returns the index of the next single quote mark in the string  
		// (starting from startFrom) 
		private int FindSingleQuote(string data, int startFrom)  
		{ 
 
			int i = startFrom-1; 
			while (++i < data.Length) 
				if (data[i] == '"')  
				{ 
					// If this is a double quote, bypass the chars 
					if (i < data.Length-1 && data[i+1] == '"')  
					{ 
						i++; 
						continue; 
					} 
					else 
						return i; 
				} 
			// If no quote found, return the end value of i (data.Length) 
			return i; 
		} 
 
		///  
		/// Disposes the CSVReader. The underlying stream is closed. 
		///  
		public void Dispose()  
		{ 
			// Closing the reader closes the underlying stream, too 
			if (reader != null) reader.Close(); 
			else if (stream != null) 
				stream.Close(); // In case we failed before the reader was constructed 
			GC.SuppressFinalize(this); 
		} 
	} 
 
 
	///  
	/// Exception class for CSVReader exceptions. 
	///  
	public class CSVReaderException : ApplicationException  
	{  
   
		///  
		/// Constructs a new exception object with the given message. 
		///  
		/// The exception message. 
		public CSVReaderException(string message) : base(message) { } 
	}