private void WriteData <T>( IEnumerable <T> values, string fileName, TextWriter stream, CsvMetaData metaData) { FieldMapper <T> fm = new FieldMapper <T>(metaData, fileName, true); CsvStream cs = new CsvStream(null, stream, metaData.SeparatorChar, metaData.IgnoreTrailingSeparatorChar); List <string> row = new List <string>(); // If first line has to carry the field names, write the field names now. if (metaData.FirstLineHasColumnNames) { fm.WriteNames(row); cs.WriteRow(row, metaData.QuoteAllFields); } // ----- foreach (T obj in values) { // Convert obj to row fm.WriteObject(obj, row); cs.WriteRow(row, metaData.QuoteAllFields); } }
public void Write <T>( IEnumerable <T> values, TextWriter stream, CsvMetaData metaData) { WriteData(values, null, stream, metaData); }
/// /////////////////////////////////////////////////////////////////////// /// FieldMapper /// /// <summary> /// Constructor /// </summary> /// <param name="metaData"></param> public FieldMapper_Reading( CsvMetaData metaData, string fileName, bool writingFile) : base(metaData, fileName, writingFile) { }
/// /////////////////////////////////////////////////////////////////////// /// Read /// /// <summary> /// Reads the comma separated values from a stream or file. /// Returns the data into an IEnumerable<T> that can be used for LINQ queries. /// /// The stream or file will be closed after the last line has been processed. /// Because the library implements deferred reading (using Yield Return), this may not happen /// for a while. /// </summary> /// <typeparam name="T"> /// The records in the returned IEnumerable<T> will be of this type. /// </typeparam> /// <param name="stream"> /// The data will be read from this stream. /// </param> /// <param name="metaData"> /// Additional information how the input file is to be interpreted, such as the culture of the input dates. /// </param> /// <returns> /// Values read from the stream or file. /// </returns> public IEnumerable <T> Read <T>(string fileName, CsvMetaData metaData) where T : class, new() { // Note that ReadData will not be called right away, but when the returned // IEnumerable<T> actually gets accessed. IEnumerable <T> ie = ReadData <T>(fileName, null, metaData); return(ie); }
/// /////////////////////////////////////////////////////////////////////// /// Write /// public void Write <T>( IEnumerable <T> values, string fileName, CsvMetaData metaData) { using (StreamWriter sw = new StreamWriter( fileName, false, metaData.TextEncoding)) { WriteData(values, fileName, sw, metaData); } }
/// /////////////////////////////////////////////////////////////////////// /// FieldMapper /// /// <summary> /// Constructor /// </summary> /// <param name="metaData"></param> public FieldMapper(CsvMetaData metaData, string fileName, bool writingFile) { if ((!metaData.FirstLineHasColumnNames) && (!metaData.EnforceCsvColumnAttribute)) { throw new CsvColumnAttributeRequiredException(); } // --------- MMetaData = metaData; m_fileName = fileName; m_NameToInfo = new Dictionary <string, TypeFieldInfo>(); AnalyzeType( typeof(T), !metaData.FirstLineHasColumnNames, writingFile && !metaData.FirstLineHasColumnNames); }
/// /////////////////////////////////////////////////////////////////////// /// ReadData /// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="fileName"> /// Name of the file associated with the stream. /// /// If this is not null, a file is opened with this name. /// If this is null, the method attempts to read from the passed in stream. /// </param> /// <param name="stream"> /// All data is read from this stream, unless fileName is not null. /// /// This is a StreamReader rather then a TextReader, /// because we need to be able to seek back to the start of the /// stream, and you can't do that with a TextReader (or StringReader). /// </param> /// <param name="metaData"></param> /// <returns></returns> private IEnumerable <T> ReadData <T>( string fileName, StreamReader stream, CsvMetaData metaData) where T : class, new() { // If T implements IDataRow, then we're reading raw data rows bool readingRawDataRows = typeof(IDataRow).IsAssignableFrom(typeof(T)); // The constructor for FieldMapper_Reading will throw an exception if there is something // wrong with type T. So invoke that constructor before you open the file, because if there // is an exception, the file will not be closed. // // If T implements IDataRow, there is no need for a FieldMapper, because in that case we're returning // raw data rows. FieldMapper_Reading <T> fm = null; if (!readingRawDataRows) { fm = new FieldMapper_Reading <T>(metaData, fileName, false); } // ------- // Each time the IEnumerable<T> that is returned from this method is // accessed in a foreach, ReadData is called again (not the original Read overload!) // // So, open the file here, or rewind the stream. bool readingFile = !string.IsNullOrEmpty(fileName); if (readingFile) { stream = new StreamReader( fileName, metaData.TextEncoding, metaData.DetectEncodingFromByteOrderMarks); } else { // Rewind the stream if ((stream == null) || (!stream.BaseStream.CanSeek)) { throw new BadStreamException(); } stream.BaseStream.Seek(0, SeekOrigin.Begin); } // ---------- CsvStream cs = new CsvStream(stream, null, metaData.SeparatorChar, metaData.IgnoreTrailingSeparatorChar); // If we're reading raw data rows, instantiate a T so we return objects // of the type specified by the caller. // Otherwise, instantiate a DataRow, which also implements IDataRow. IDataRow row = null; if (readingRawDataRows) { row = new T() as IDataRow; } else { row = new DataRow(); } AggregatedException ae = new AggregatedException(typeof(T).ToString(), fileName, metaData.MaximumExceptions); try { List <int> charLengths = null; if (!readingRawDataRows) { charLengths = fm.GetCharLengths(); } bool firstRow = true; while (cs.ReadRow(row, charLengths)) { // Skip empty lines. // Important. If there is a newline at the end of the last data line, the code // thinks there is an empty line after that last data line. if ((row.Count == 1) && ((row[0].Value == null) || (string.IsNullOrEmpty(row[0].Value.Trim())))) { continue; } if (firstRow && metaData.FirstLineHasColumnNames) { if (!readingRawDataRows) { fm.ReadNames(row); } } else { T obj = default; try { if (readingRawDataRows) { obj = row as T; } else { obj = fm.ReadObject(row, ae); } } catch (AggregatedException ae2) { // Seeing that the AggregatedException was thrown, maximum number of exceptions // must have been reached, so rethrow. // Catch here, so you don't add an AggregatedException to an AggregatedException throw ae2; } catch (Exception e) { // Store the exception in the AggregatedException ae. // That way, if a file has many errors leading to exceptions, // you get them all in one go, packaged in a single aggregated exception. ae.AddException(e); } yield return(obj); } firstRow = false; } } finally { if (readingFile) { stream.Close(); } // If any exceptions were raised while reading the data from the file, // they will have been stored in the AggregatedException ae. // In that case, time to throw ae. ae.ThrowIfExceptionsStored(); } }
public IEnumerable <T> Read <T>(StreamReader stream, CsvMetaData metaData) where T : class, new() { return(ReadData <T>(null, stream, metaData)); }