Files
SabreTools/SabreTools.Library/IO/SeparatedValueWriter.cs
Matt Nadareski 41d3d0c848 IO namespace
2020-08-01 22:46:28 -07:00

169 lines
4.5 KiB
C#

using System;
using System.IO;
using System.Text;
namespace SabreTools.Library.IO
{
public class SeparatedValueWriter : IDisposable
{
/// <summary>
/// Internal stream writer for outputting
/// </summary>
private StreamWriter sw;
/// <summary>
/// Internal value if we've written a header before
/// </summary>
private bool header = false;
/// <summary>
/// Internal value if we've written our first line before
/// </summary>
private bool firstRow = false;
/// <summary>
/// Internal value to say how many fields should be written
/// </summary>
private int fields = -1;
/// <summary>
/// Set if values should be wrapped in quotes
/// </summary>
public bool Quotes { get; set; } = true;
/// <summary>
/// Set what character should be used as a separator
/// </summary>
public char Separator { get; set; } = ',';
/// <summary>
/// Set if field count should be verified from the first row
/// </summary>
public bool VerifyFieldCount { get; set; } = true;
/// <summary>
/// Constructor for writing to a file
/// </summary>
public SeparatedValueWriter(string filename)
{
sw = new StreamWriter(filename);
}
/// <summary>
/// Consturctor for writing to a stream
/// </summary>
public SeparatedValueWriter(Stream stream, Encoding encoding)
{
sw = new StreamWriter(stream, encoding);
}
/// <summary>
/// Write a header row
/// </summary>
public void WriteHeader(string[] headers)
{
// If we haven't written anything out, we can write headers
if (!header && !firstRow)
WriteValues(headers);
header = true;
}
/// <summary>
/// Write a value row
/// </summary>
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();
}
/// <summary>
/// Write a generic string
/// </summary>
public void WriteString(string value)
{
if (string.IsNullOrEmpty(value))
return;
sw.Write(value);
}
/// <summary>
/// Write a newline
/// </summary>
public void WriteLine()
{
sw.WriteLine();
}
/// <summary>
/// Flush the underlying writer
/// </summary>
public void Flush()
{
sw.Flush();
}
/// <summary>
/// Dispose of the underlying writer
/// </summary>
public void Dispose()
{
sw.Dispose();
}
}
}