PageRenderTime 38ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/Sources/DataAccess/CsvWriter.cs

https://github.com/tpwalke2/DataTable
C# | 143 lines | 103 code | 19 blank | 21 comment | 13 complexity | b62ea0f21c2444858043e81b2f00f292 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. using System.Diagnostics;
  6. using System.Text.RegularExpressions;
  7. using System.Linq;
  8. using System.Diagnostics.CodeAnalysis;
  9. namespace DataAccess
  10. {
  11. // Make this private. We don't need to expose a CSV writer since users can easily just create a DataTable and save that.
  12. // Helper to write a CSV file.
  13. // Ensures normalized view.
  14. internal class CsvWriter : IDisposable {
  15. TextWriter _tw;
  16. readonly string[] _ColumnNames;
  17. bool _ownsStream = false;
  18. // Write out to the given stream.
  19. public CsvWriter(TextWriter writer, IEnumerable<string> columnNames)
  20. {
  21. this._ColumnNames = columnNames.ToArray();
  22. this._tw = writer;
  23. // Write header
  24. RawWriteLine(columnNames, _tw);
  25. }
  26. // Will overwrite
  27. [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "setting _ownsStream flag means caller will dispose")]
  28. public CsvWriter(string outputFilename, IEnumerable<string> columnNames)
  29. : this(CreateWriterForFile(outputFilename), columnNames)
  30. {
  31. _ownsStream = true;
  32. }
  33. static TextWriter CreateWriterForFile(string outputFilename)
  34. {
  35. Directory.CreateDirectory(Path.GetDirectoryName(outputFilename));
  36. return new StreamWriter(outputFilename);
  37. }
  38. // Write out specific values for the row.
  39. // - This still ensure's they're escaped
  40. // - places commas
  41. // - validates count matches header.
  42. public void WriteRow(string[] values)
  43. {
  44. Utility.Assert(values.Length == _ColumnNames.Length, "Number of items in row doesn't match header count");
  45. RawWriteLine(values, _tw);
  46. }
  47. // Write a row (which may be from an data-set) into this csv file.
  48. // Only take the columns specified by the ctor. If row doesn't have a column, output blank.
  49. // This ensures we maintain the right schema.
  50. public void WriteRow(Row r) {
  51. RawWriteLine(r.Values, _tw);
  52. //RawWriteLine(r.GetValuesOrEmpty(this._ColumnNames), _tw); // $$$ This is very slow, but it matches column names.
  53. }
  54. public void WriteRow(Row r, IDictionary<string, string> extra) {
  55. RawWriteLine(ValueHelper(r, extra), _tw);
  56. }
  57. IEnumerable<string> ValueHelper(Row r, IDictionary<string, string> extra) {
  58. foreach (var name in _ColumnNames) {
  59. //if (Utility.GetColumnIndexFromName(r.ColumnNames, name) // throws
  60. //if (r.m_parent.HasColumnName(name))
  61. if (true) // $$$ fix
  62. {
  63. yield return r[name];
  64. continue;
  65. }
  66. string value = null;
  67. if (extra.TryGetValue(name, out value)) {
  68. // It's in the extra dictionary
  69. yield return value;
  70. } else {
  71. yield return string.Empty;
  72. }
  73. }
  74. }
  75. // Write a single line to a CSV
  76. public static void RawWriteLine(IEnumerable<string> values, TextWriter tw)
  77. {
  78. bool first = true;
  79. foreach (var c in values)
  80. {
  81. if (!first)
  82. {
  83. tw.Write(',');
  84. }
  85. first = false;
  86. tw.Write(Escape(c));
  87. }
  88. tw.WriteLine();
  89. }
  90. // Escape a value for writing to CSVs
  91. // - Enclose it in quotes if the value has a comma
  92. private static string Escape(string s)
  93. {
  94. if (s == null)
  95. return string.Empty;
  96. if (s.IndexOf(',') >= 0)
  97. {
  98. return "\"" + s + "\"";
  99. }
  100. return s;
  101. }
  102. // Don't close the underlying stream, we don't own it. But we can flush it.
  103. public void Flush() {
  104. if (_tw != null)
  105. {
  106. _tw.Flush();
  107. }
  108. }
  109. #region IDisposable Members
  110. public void Dispose()
  111. {
  112. this.Flush();
  113. if (_ownsStream)
  114. {
  115. if (_tw != null)
  116. {
  117. _tw.Close();
  118. _tw = null;
  119. }
  120. }
  121. }
  122. #endregion
  123. } // end class
  124. } // end namespace