/// <summary> /// Appends a single object to a StringBuilder in CSV format as a single line /// </summary> /// <param name="sb">The stringbuilder to append data</param> /// <param name="obj">The single object to append in CSV-line format</param> /// <param name="settings">The CSV settings to use when exporting this array (Default: CSV)</param> /// <typeparam name="T">The 1st type parameter.</typeparam> public static void AppendAsCSV <T>(this StringBuilder sb, T obj, CSVSettings settings = null) where T : class, new() { // Skip any null objects if (obj == null) { return; } // Use CSV as default. if (settings == null) { settings = CSVSettings.CSV; } // Retrieve reflection information var type = typeof(T); var filist = type.GetFields(); var pilist = type.GetProperties(); // Retrieve all the fields and properties List <object> values = new List <object>(); foreach (var fi in filist) { values.Add(fi.GetValue(obj)); } foreach (var pi in pilist) { values.Add(pi.GetValue(obj, null)); } // Output one line of CSV AppendCSVRow(sb, values, settings); }
/// <summary> /// Add a CSV Header line to a StringBuilder /// </summary> /// <param name="sb">The stringbuilder to append data</param> /// <param name="type">The type of data to emit a header</param> /// <param name="settings">The CSV settings to use when exporting this array (Default: CSV)</param> public static void AppendCSVHeader(this StringBuilder sb, Type type, CSVSettings settings = null) { // Use CSV as default. if (settings == null) { settings = CSVSettings.CSV; } // Retrieve reflection information var filist = type.GetFields(); var pilist = type.GetProperties(); // Gather information about headers var headers = new List <object>(); foreach (var fi in filist) { headers.Add(fi.Name); } foreach (var pi in pilist) { headers.Add(pi.Name); } AppendCSVRow(sb, headers, settings); }
/// <summary> /// Serialize an array of objects to CSV format /// </summary> /// <typeparam name="T">The type of objects to serialize from this CSV</typeparam> /// <param name="list">The array of objects to serialize</param> /// <param name="settings">The CSV settings to use when exporting this array (Default: CSV)</param> /// <returns>The completed CSV string representing one line per element in list</returns> public static string Serialize <T>(IEnumerable <T> list, CSVSettings settings = null) where T : class, new() { // Use CSV as default. if (settings == null) { settings = CSVSettings.CSV; } // Okay, let's begin StringBuilder sb = new StringBuilder(); // Did the caller want the header row? if (settings.HeaderRowIncluded) { sb.AppendCSVHeader(typeof(T), settings); sb.Append(settings.LineSeparator); } // Let's go through the array of objects // Iterate through all the objects var values = new List <object>(); foreach (T obj in list) { sb.AppendAsCSV <T>(obj, settings); sb.Append(settings.LineSeparator); } // Here's your data serialized in CSV format return(sb.ToString()); }
/// <summary> /// Serialize a sequence of objects into a CSV string /// </summary> /// <returns>A single line of CSV encoded data containing these values</returns> /// <param name="row">A list or array of objects to serialize</param> /// <param name="settings">The field delimiter character (Default: comma)</param> public static string ToCSVString(this IEnumerable <object> row, CSVSettings settings = null) { StringBuilder sb = new StringBuilder(); AppendCSVRow(sb, row, settings); return(sb.ToString()); }
/// <summary> /// Parse a single row of data from a CSV line into an array of objects, while permitting embedded newlines /// </summary> /// <param name="inStream">The stream to read</param> /// <param name="settings">The CSV settings to use for this parsing operation (Default: CSV)</param> /// <returns>An array containing all fields in the next row of data, or null if it could not be parsed.</returns> public static string[] ParseMultiLine(StreamReader inStream, CSVSettings settings = null) { StringBuilder sb = new StringBuilder(); string[] array = null; while (!inStream.EndOfStream) { // Read in a line sb.Append(inStream.ReadLine()); // Does it parse? string s = sb.ToString(); if (TryParseLine(s, out array, settings)) { return(array); } // We didn't succeed on the first try - our text must have an embedded newline in it. // Let's assume that we were in the middle of parsing a field when we encountered a newline, // and continue parsing. sb.Append(settings.LineSeparator); } // Fails to parse - return the best array we were able to get return(array); }
/// <summary> /// Serialize an array of objects to CSV format /// </summary> /// <typeparam name="T">The type of objects to serialize from this CSV</typeparam> /// <param name="list">The array of objects to serialize</param> /// <param name="stream">The stream to which we will send this CSV text</param> /// <param name="settings">The CSV settings to use when exporting this array (Default: CSV)</param> /// <returns>The completed CSV string representing one line per element in list</returns> public static Task SerializeAsync <T>(IEnumerable <T> list, Stream stream, CSVSettings settings = null) where T : class, new() { using (var cw = new CSVWriter(stream, settings)) { return(cw.SerializeAsync(list)); } }
/// <summary> /// Read in a single CSV file as an array of objects /// </summary> /// <typeparam name="T">The type of objects to deserialize from this CSV.</typeparam> /// <param name="stream">The stream to read.</param> /// <param name="settings">The CSV settings to use when loading this array (Default: CSV)</param> /// <returns>An array of objects that were retrieved from the CSV file.</returns> public static List <T> LoadArray <T>(StreamReader stream, CSVSettings settings) where T : class, new() { using (CSVReader cr = new CSVReader(stream, settings)) { return(cr.Deserialize <T>()); } }
/// <summary> /// Write a data table to disk at the designated file name in CSV format /// </summary> /// <param name="dt"></param> /// <param name="filename"></param> /// <param name="settings">The CSV settings to use when exporting this DataTable (Default: CSV)</param> public static void WriteToFile(this DataTable dt, string filename, CSVSettings settings = null) { using (StreamWriter sw = new StreamWriter(filename)) { WriteToStream(dt, sw, settings); } }
/// <summary> /// Write the data table to a stream in CSV format /// </summary> /// <param name="dt">The data table to write</param> /// <param name="sw">The stream where the CSV text will be written</param> /// <param name="settings">The CSV settings to use when exporting this DataTable (Default: CSV)</param> public static void WriteToStream(this DataTable dt, StreamWriter sw, CSVSettings settings = null) { using (CSVWriter cw = new CSVWriter(sw, settings)) { cw.Write(dt); } }
/// <summary> /// Read in a single CSV file into a datatable in memory /// </summary> /// <param name="stream">The stream source from which to load the datatable.</param> /// <param name="settings">The CSV settings to use when exporting this array (Default: CSV)</param> /// <returns>An data table of strings that were retrieved from the CSV file.</returns> public static DataTable FromStream(StreamReader stream, CSVSettings settings = null) { using (CSVReader cr = new CSVReader(stream, settings)) { return(cr.ReadAsDataTable()); } }
/// <summary> /// Constructs a serialization helper object separate from I/O /// </summary> /// <param name="settings"></param> /// <param name="riskyChars"></param> /// <param name="forceQualifierTypes"></param> public SerializationHelper(CSVSettings settings, char[] riskyChars, Dictionary <Type, int> forceQualifierTypes) { _settings = settings; if (_settings == null) { _settings = CSVSettings.CSV; } // Extract properties and fields that are not excluded var excluded = new ExcludedColumnHelper(_settings); var props = new List <PropertyInfo>(); foreach (var prop in typeof(T).GetProperties()) { if (!excluded.IsExcluded(prop.Name)) { props.Add(prop); } } var fields = new List <FieldInfo>(); foreach (var field in typeof(T).GetFields()) { if (!excluded.IsExcluded(field.Name)) { fields.Add(field); } } _properties = props.ToArray(); _fields = fields.ToArray(); _riskyChars = riskyChars; _forceQualifierTypes = forceQualifierTypes; }
public static void AppendCSVHeader <T>(this StringBuilder sb, CSVSettings settings = null) where T : class, new() #endif { var header = Serialize(new T[] { }, settings); sb.Append(header); }
/// <summary> /// Serialize an array of objects to CSV format /// </summary> /// <typeparam name="T">The type of objects to serialize from this CSV</typeparam> /// <param name="list">The array of objects to serialize</param> /// <param name="stream">The stream to which we will send this CSV text</param> /// <param name="settings">The CSV settings to use when exporting this array (Default: CSV)</param> /// <returns>The completed CSV string representing one line per element in list</returns> public static void Serialize <T>(IEnumerable <T> list, Stream stream, CSVSettings settings = null) where T : class, new() { using (var cw = new CSVWriter(stream, settings)) { cw.Serialize(list); } }
/// <summary> /// Construct a new CSV reader off a streamed source /// </summary> /// <param name="source">The stream source. Note that when disposed, the CSV Reader will dispose the stream reader.</param> /// <param name="settings">The CSV settings to use for this reader (Default: CSV)</param> public CSVReader(Stream source, CSVSettings settings = null) { _settings = settings; if (_settings == null) { _settings = CSVSettings.CSV; } _stream = new StreamReader(source, _settings.Encoding); // Do we need to parse headers? if (_settings.HeaderRowIncluded) { var line = _stream.ReadLine(); if (_settings.AllowSepLine) { var newDelimiter = CSV.ParseSepLine(line); if (newDelimiter != null) { // We don't want to change the original settings, since they may be a singleton _settings = _settings.CloneWithNewDelimiter(newDelimiter.Value); line = _stream.ReadLine(); } } Headers = CSV.ParseLine(line, _settings); } else { Headers = _settings.AssumedHeaders; } }
/// <summary> /// Read in a single CSV file into a datatable in memory /// </summary> /// <param name="filename"></param> /// <param name="settings">The CSV settings to use when exporting this array (Default: CSV)</param> /// <returns>An data table of strings that were retrieved from the CSV file.</returns> public static DataTable FromFile(string filename, CSVSettings settings = null) { using (var sr = new StreamReader(filename)) { return(FromStream(sr, settings)); } }
/// <summary> /// Deserialize a single row using precomputed converters /// </summary> /// <param name="line"></param> /// <param name="row_num"></param> /// <param name="settings"></param> /// <returns></returns> /// <exception cref="Exception"></exception> public T Deserialize(string[] line, int row_num, CSVSettings settings) { // If this line is completely empty, do our settings permit us to ignore the empty line? if (line.Length == 0 || (line.Length == 1 && line[0] == string.Empty) && settings.IgnoreEmptyLineForDeserialization) { return(null); } // Does this line match the length of the first line? Does the caller want us to complain? if (line.Length != _numColumns && !settings.IgnoreHeaderErrors) { throw new Exception($"Line #{row_num} contains {line.Length} columns; expected {_numColumns}"); } // Construct a new object and execute each column on it var obj = new T(); for (var i = 0; i < Math.Min(line.Length, _numColumns); i++) { if (_converters[i] == null) { continue; } // Attempt to convert this to the specified type object value = null; if (settings.AllowNull && (line[i] == null || line[i] == settings.NullToken)) { value = null; } else if (_converters[i].IsValid(line[i])) { value = _converters[i].ConvertFromString(line[i]); } else if (!settings.IgnoreHeaderErrors) { throw new Exception( $"The value '{line[i]}' cannot be converted to the type {_columnTypes[i]}."); } // Can we set this value to the object as a property? if (_properties[i] != null) { _properties[i].SetValue(obj, value, null); } else if (_fields[i] != null) { _fields[i].SetValue(obj, value); } else if (_methods[i] != null) { _methods[i].Invoke(obj, new object[] { value }); } } return(obj); }
/// <summary> /// Construct a new CSV writer to produce output on the enclosed StreamWriter /// </summary> /// <param name="dest">The stream where this CSV will be outputted</param> /// <param name="settings">The CSV settings to use when writing to the stream (Default: CSV)</param> public CSVWriter(StreamWriter dest, CSVSettings settings = null) { _outstream = dest; _settings = settings; if (_settings == null) { _settings = CSVSettings.CSV; } }
/// <summary> /// Convenience function to read from a file on disk /// </summary> /// <param name="filename">The file to read</param> /// <param name="settings">The CSV settings to use for this reader (Default: CSV)</param> /// <param name="encoding">The string encoding to use for the reader (Default: UTF8)</param> /// <returns></returns> public static CSVReader FromFile(string filename, CSVSettings settings = null, Encoding encoding = null) { if (encoding == null) { encoding = Encoding.UTF8; } var sr = new StreamReader(filename, encoding); return(new CSVReader(sr, settings)); }
/// <summary> /// Construct a new CSV writer to produce output on the enclosed stream /// </summary> /// <param name="dest">The stream where this CSV will be outputted</param> /// <param name="settings">The CSV settings to use when writing to the stream (Default: CSV)</param> public CSVWriter(Stream dest, CSVSettings settings = null) { _settings = settings; if (_settings == null) { _settings = CSVSettings.CSV; } _writer = new StreamWriter(dest, _settings.Encoding); _riskyChars = _settings.GetRiskyChars(); _forceQualifierTypes = _settings.GetForceQualifierTypes(); }
/// <summary> /// Deserialize a CSV string into a list of typed objects /// </summary> /// <typeparam name="T">The type of objects to deserialize</typeparam> /// <param name="settings">The CSV settings to use when parsing the source (Default: CSV)</param> /// <param name="source">The source CSV to deserialize</param> /// <returns></returns> public static List <T> Deserialize <T>(string source, CSVSettings settings = null) where T : class, new() { byte[] byteArray = Encoding.UTF8.GetBytes(source); using (var stream = new MemoryStream(byteArray)) { using (CSVReader cr = new CSVReader(new StreamReader(stream), settings)) { return(cr.Deserialize <T>()); } } }
/// <summary> /// Convenience function to read from a string /// </summary> /// <param name="source">The string to read</param> /// <param name="settings">The CSV settings to use for this reader (Default: CSV)</param> /// <returns></returns> public static CSVReader FromString(string source, CSVSettings settings = null) { if (settings == null) { settings = CSVSettings.CSV; } var byteArray = settings.Encoding.GetBytes(source); var stream = new MemoryStream(byteArray); return(new CSVReader(stream, settings)); }
/// <summary> /// Construct a new CSV writer to produce output on the enclosed StreamWriter /// </summary> /// <param name="dest">The stream where this CSV will be outputted</param> /// <param name="settings">The CSV settings to use when writing to the stream (Default: CSV)</param> public CSVWriter(StreamWriter dest, CSVSettings settings = null) { _writer = dest; _settings = settings; if (_settings == null) { _settings = CSVSettings.CSV; } _riskyChars = _settings.GetRiskyChars(); _forceQualifierTypes = _settings.GetForceQualifierTypes(); }
/// <summary> /// Convert a CSV file (in string form) into a data table /// </summary> /// <param name="source"></param> /// <param name="settings">The CSV settings to use when exporting this array (Default: CSV)</param> /// <returns></returns> public static DataTable FromString(string source, CSVSettings settings = null) { byte[] byteArray = Encoding.UTF8.GetBytes(source); using (MemoryStream stream = new MemoryStream(byteArray)) { using (CSVReader cr = new CSVReader(new StreamReader(stream), settings)) { return(cr.ReadAsDataTable()); } } }
public static string ToCSVString(this IEnumerable <object> row, CSVSettings settings = null) #endif { if (settings == null) { settings = CSVSettings.CSV; } var riskyChars = settings.GetRiskyChars(); var forceQualifierTypes = settings.GetForceQualifierTypes(); return(ItemsToCsv(row, settings, riskyChars, forceQualifierTypes)); }
/// <summary> /// Try to parse a line of CSV data. Can only return false if an unterminated text qualifier is encountered. /// /// This function cannot recognize 'sep=' lines because it does not know whether it is parsing the first line /// in the overall CSV stream. /// </summary> /// <returns>False if there was an unterminated text qualifier in the <paramref name="line"/></returns> /// <param name="line">The line of text to parse</param> /// <param name="settings">The CSV settings to use for this parsing operation (Default: CSV)</param> /// <param name="row">The array of fields found in the line</param> public static bool TryParseLine(string line, out string[] row, CSVSettings settings = null) { row = null; var machine = new CSVStateMachine(settings); while (machine.State == CSVState.CanKeepGoing) { row = machine.ParseChunk(line, true); line = string.Empty; } return(machine.State == CSVState.Done); }
/// <summary> /// Convert a CSV file (in string form) into a list of string arrays /// </summary> /// <param name="source_string"></param> /// <param name="settings">The CSV settings to use when loading this array (Default: CSV)</param> /// <returns></returns> public static List <string[]> LoadString(string source_string, CSVSettings settings = null) { byte[] byteArray = Encoding.UTF8.GetBytes(source_string); MemoryStream stream = new MemoryStream(byteArray); var results = new List <string[]>(); using (CSVReader cr = new CSVReader(new StreamReader(stream))) { foreach (var line in cr) { results.Add(line); } } return(results); }
/// <summary> /// Add a single token to the list /// </summary> /// <param name="list">List.</param> /// <param name="work">Work.</param> /// <param name="settings">Settings.</param> private static void AddToken(List <string> list, StringBuilder work, CSVSettings settings) { var s = work.ToString(); if (settings.AllowNull && String.Equals(s, settings.NullToken, StringComparison.Ordinal)) { list.Add(null); } else { list.Add(s); } work.Length = 0; }
/// <summary> /// Constructs a new state machine to begin processing CSV text /// </summary> public CSVStateMachine(CSVSettings settings) { _line = ""; _list = new List <string>(); _work = new StringBuilder(); _settings = settings ?? CSVSettings.CSV; _position = -1; // The presence of a "sep=" line may affect these values _delimiter = _settings.FieldDelimiter; _allowSepLine = _settings.AllowSepLine; // We are ready for work State = CSVState.CanKeepGoing; }
public static void AppendCSVLine <T>(this StringBuilder sb, T obj, CSVSettings settings = null) where T : class, new() #endif { if (settings == null) { settings = CSVSettings.CSV; } // Duplicate settings, but flag ourselves to ignore the header settings = settings.CloneWithNewDelimiter(settings.FieldDelimiter); settings.HeaderRowIncluded = false; var line = Serialize(new T[] { obj }, settings); sb.Append(line); }
/// <summary> /// Write a DataTable to a string in CSV format /// </summary> /// <param name="dt">The datatable to write</param> /// <param name="settings">The CSV settings to use when exporting this DataTable (Default: CSV)</param> /// <returns>The CSV string representing the object array.</returns> public static string WriteToString(this DataTable dt, CSVSettings settings = null) { using (var ms = new MemoryStream()) { var sw = new StreamWriter(ms); var cw = new CSVWriter(sw, settings); cw.Write(dt); sw.Flush(); ms.Position = 0; using (var sr = new StreamReader(ms)) { return(sr.ReadToEnd()); } } }