using System; using System.IO; using System.Text; namespace SabreTools.Library.IO { public class SeparatedValueWriter : IDisposable { /// /// Internal stream writer for outputting /// private StreamWriter sw; /// /// Internal value if we've written a header before /// private bool header = false; /// /// Internal value if we've written our first line before /// private bool firstRow = false; /// /// Internal value to say how many fields should be written /// private int fields = -1; /// /// Set if values should be wrapped in quotes /// public bool Quotes { get; set; } = true; /// /// Set what character should be used as a separator /// public char Separator { get; set; } = ','; /// /// Set if field count should be verified from the first row /// public bool VerifyFieldCount { get; set; } = true; /// /// Constructor for writing to a file /// public SeparatedValueWriter(string filename) { sw = new StreamWriter(filename); } /// /// Consturctor for writing to a stream /// public SeparatedValueWriter(Stream stream, Encoding encoding) { sw = new StreamWriter(stream, encoding); } /// /// Write a header row /// public void WriteHeader(string[] headers) { // If we haven't written anything out, we can write headers if (!header && !firstRow) WriteValues(headers); header = true; } /// /// Write a value row /// public void WriteValues(object[] values, bool newline = true) { // If the writer can't be used, we error if (sw == null || !sw.BaseStream.CanWrite) throw new ArgumentException(nameof(sw)); // If the separator character is invalid, we error if (Separator == default(char)) throw new ArgumentException(nameof(Separator)); // If we have the first row, set the bool and the field count if (!firstRow) { firstRow = true; if (VerifyFieldCount && fields == -1) fields = values.Length; } // Get the number of fields to write out int fieldCount = values.Length; if (VerifyFieldCount) fieldCount = Math.Min(fieldCount, fields); // Iterate over the fields, writing out each bool firstField = true; for (int i = 0; i < fieldCount; i++) { var value = values[i]; if (!firstField) sw.Write(Separator); if (Quotes) sw.Write("\""); sw.Write(value?.ToString() ?? string.Empty); if (Quotes) sw.Write("\""); firstField = false; } // If we need to pad out the number of fields, add empties if (VerifyFieldCount && values.Length < fields) { for (int i = 0; i < fields - values.Length; i++) { sw.Write(Separator); if (Quotes) sw.Write("\"\""); } } // Add a newline, if needed if (newline) sw.WriteLine(); } /// /// Write a generic string /// public void WriteString(string value) { if (string.IsNullOrEmpty(value)) return; sw.Write(value); } /// /// Write a newline /// public void WriteLine() { sw.WriteLine(); } /// /// Flush the underlying writer /// public void Flush() { sw.Flush(); } /// /// Dispose of the underlying writer /// public void Dispose() { sw.Dispose(); } } }