Advertisement
Guest User

Calanus

a guest
Dec 8th, 2009
2,728
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.03 KB | None | 0 0
  1. using System;
  2. using System.Collections;
  3. using System.IO;
  4. using System.Text;
  5. using System.Collections.Generic;
  6.  
  7. namespace IVS
  8. {
  9.     /// <summary>
  10.     /// A data-reader style interface for reading CSV files.
  11.     /// </summary>
  12.     public class CSVReader : IDisposable
  13.     {
  14.         private Stream stream;
  15.         private StreamReader reader;
  16.  
  17.         /// <summary>
  18.         /// Create a new reader for the given stream.
  19.         /// </summary>
  20.         /// <param name="s">The stream to read the CSV from.</param>
  21.         public CSVReader(Stream s) : this(s, null) { }
  22.  
  23.         /// <summary>
  24.         /// Create a new reader for the given stream and encoding.
  25.         /// </summary>
  26.         /// <param name="s">The stream to read the CSV from.</param>
  27.         /// <param name="enc">The encoding used.</param>
  28.         public CSVReader(Stream s, Encoding enc)
  29.         {
  30.             this.stream = s;
  31.             if (!s.CanRead)
  32.             {
  33.                 throw new CSVReaderException("Could not read the given CSV stream!");
  34.             }
  35.             reader = (enc != null) ? new StreamReader(s, enc) : new StreamReader(s);
  36.         }
  37.  
  38.         /// <summary>
  39.         /// Creates a new reader for the given text file path.
  40.         /// </summary>
  41.         /// <param name="filename">The name of the file to be read.</param>
  42.         public CSVReader(string filename) : this(filename, null) { }
  43.  
  44.         /// <summary>
  45.         /// Creates a new reader for the given text file path and encoding.
  46.         /// </summary>
  47.         /// <param name="filename">The name of the file to be read.</param>
  48.         /// <param name="enc">The encoding used.</param>
  49.         public CSVReader(string filename, Encoding enc)
  50.             : this(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), enc) { }
  51.  
  52.         /// <summary>
  53.         /// Returns the fields for the next row of CSV data (or null if at eof)
  54.         /// </summary>
  55.         /// <returns>A string array of fields or null if at the end of file.</returns>
  56.         public string[] GetCSVLine()
  57.         {
  58.             string data = reader.ReadLine();
  59.             if (data == null) return null;
  60.             if (data.Length == 0) return new string[0];
  61.  
  62.             List<String> result = new List<String>();
  63.  
  64.             ParseCSVFields(result, data);
  65.  
  66.             return (string[])result.ToArray();
  67.         }
  68.  
  69.         // Parses the CSV fields and pushes the fields into the result arraylist
  70.         private void ParseCSVFields(List<String> result, string data)
  71.         {
  72.             int pos = -1;
  73.             while (pos < data.Length)
  74.                 result.Add(ParseCSVField(data, ref pos));
  75.         }
  76.  
  77.         // Parses the field at the given position of the data, modified pos to match
  78.         // the first unparsed position and returns the parsed field
  79.         private string ParseCSVField(string data, ref int startSeparatorPosition)
  80.         {
  81.             if (startSeparatorPosition == data.Length - 1)
  82.             {
  83.                 startSeparatorPosition++;
  84.                 // The last field is empty
  85.                 return "";
  86.             }
  87.  
  88.             int fromPos = startSeparatorPosition + 1;
  89.  
  90.             // Determine if this is a quoted field
  91.             if (data[fromPos] == '"')
  92.             {
  93.                 // If we're at the end of the string, let's consider this a field that
  94.                 // only contains the quote
  95.                 if (fromPos == data.Length - 1)
  96.                 {
  97.                     fromPos++;
  98.                     return "\"";
  99.                 }
  100.  
  101.                 // Otherwise, return a string of appropriate length with double quotes collapsed
  102.                 // Note that FSQ returns data.Length if no single quote was found
  103.                 int nextSingleQuote = FindSingleQuote(data, fromPos + 1);
  104.                 startSeparatorPosition = nextSingleQuote + 1;
  105.                 return data.Substring(fromPos + 1, nextSingleQuote - fromPos - 1).Replace("\"\"", "\"");
  106.             }
  107.  
  108.             // The field ends in the next comma or EOL
  109.             int nextComma = data.IndexOf(',', fromPos);
  110.             if (nextComma == -1)
  111.             {
  112.                 startSeparatorPosition = data.Length;
  113.                 return data.Substring(fromPos);
  114.             }
  115.             else
  116.             {
  117.                 startSeparatorPosition = nextComma;
  118.                 return data.Substring(fromPos, nextComma - fromPos);
  119.             }
  120.         }
  121.  
  122.         // Returns the index of the next single quote mark in the string
  123.         // (starting from startFrom)
  124.         private int FindSingleQuote(string data, int startFrom)
  125.         {
  126.             int i = startFrom - 1;
  127.             while (++i < data.Length)
  128.                 if (data[i] == '"')
  129.                 {
  130.                     // If this is a double quote, bypass the chars
  131.                     if (i < data.Length - 1 && data[i + 1] == '"')
  132.                     {
  133.                         i++;
  134.                         continue;
  135.                     }
  136.                     else
  137.                         return i;
  138.                 }
  139.             // If no quote found, return the end value of i (data.Length)
  140.             return i;
  141.         }
  142.  
  143.         /// <summary>
  144.         /// Disposes the CSVReader. The underlying stream is closed.
  145.         /// </summary>
  146.         public void Dispose()
  147.         {
  148.             // Closing the reader closes the underlying stream, too
  149.             if (reader != null) reader.Close();
  150.             else if (stream != null)
  151.                 stream.Close(); // In case we failed before the reader was constructed
  152.             GC.SuppressFinalize(this);
  153.         }
  154.     }
  155.  
  156.     /// <summary>
  157.     /// Exception class for CSVReader exceptions.
  158.     /// </summary>
  159.     public class CSVReaderException : Exception
  160.     {
  161.  
  162.         /// <summary>
  163.         /// Constructs a new exception object with the given message.
  164.         /// </summary>
  165.         /// <param name="message">The exception message.</param>
  166.         public CSVReaderException(string message) : base(message) { }
  167.     }
  168. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement