CSVファイルを出力するファイルを作成したので、掲載しておきます。基本的にある程度仕様どおりのような気がしますが、間違っていたらご指摘ください。

CSVファイルの仕様(原文)
- http://www.ietf.org/rfc/rfc4180.txt 
  CSVファイルの一般的書式 (RFC4180 日本語訳) 
- http://www.kasai.fm/wiki/rfc4180jp

動作環境

  • 確認環境 Windows Vista
  • 開発環境 Visual Studio 2008 Professional
  • .NET 2.0以上

1.CSVWriterクラスの定義

CSVWriterを定義します。ソースは次の通り。今のクラスでは、ダブルクオーテーションで囲む場合、フィールド内のダブルクオーテーションをエスケープする処理が抜けていたりするので、足りない部分は適当に修正して使います。

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data;

namespace CSVReaderWriter
{
    /// <summary>
    /// CSVライター
    /// </summary>
    class CSVWriter : IDisposable
    {
        /// <summary>出力ストリーム</summary>
        StreamWriter _writer = null;
        #region コンストラクタ
        /// <summary>
        /// 指定されたストリームにデフォルトのエンコーディングで
        /// 出力を行います。
        /// </summary>
        /// <param name="stream"></param>
        public CSVWriter(Stream stream)
        {
            _writer = new StreamWriter(stream, Encoding.Default);
        }
        /// <summary>
        /// 指定されたストリームに指定されたエンコーディングで
        /// 出力を行います。
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="encoding"></param>
        public CSVWriter(Stream stream, Encoding encoding)
        {
            _writer = new StreamWriter(stream, encoding);
        }
        /// <summary>
        /// 指定されたパスにデフォルトエンコーディングで
        /// 出力を行います。
        /// </summary>
        /// <param name="path"></param>
        public CSVWriter(String path)
        {
            _writer = new StreamWriter(path, false, Encoding.Default);
        }
        /// <summary>
        /// 指定されたパスに指定されたエンコーディングで
        /// 出力を行います。
        /// </summary>
        /// <param name="path"></param>
        /// <param name="encoding"></param>
        public CSVWriter(String path, Encoding encoding)
        {
            _writer = new StreamWriter(path, false, encoding);
        }
        #endregion

        #region プロパティ
        private bool _isTokenEnclosedWithDQuotas = false;
        /// <summary>
        /// フィールドがダブルクオーテーションで囲まれるかのプロパティ
        /// trueの場合ダブルクオーテーションで囲まれる
        /// </summary>
        public bool IsTokenEnclosedWithDQuotas
        {
            get { return _isTokenEnclosedWithDQuotas; }
            set { _isTokenEnclosedWithDQuotas = value; }
        }

        private string _separator = "\t";
        /// <summary>
        /// 項目間の区切り文字
        /// </summary>
        public string Separator
        {
            get { return _separator; }
            set { _separator = value; }
        }

        #endregion

        #region メソッド
        /// <summary>
        /// CSV出力ストリームに1行分出力する
        /// </summary>
        /// <param name="tokens"></param>
        protected void WriteLine(string[] tokens)
        {
            for (int i = 0; i < tokens.Length; ++i)
            {
                _writer.Write(DQuote(tokens[i]));
                if (i != tokens.Length - 1)
                {
                    _writer.Write(Separator);
                }
            }
            _writer.Write("\n");
        }
        /// <summary>
        /// トークンを必要に応じてダブルクオーテーションで加工する。
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        protected virtual string DQuote(string token)
        {
            bool needDQuote = IsTokenEnclosedWithDQuotas;
            if (token.Contains(Separator) || token.Contains("\r") || token.Contains("\n"))
            {
                needDQuote = true;
            }
            if (needDQuote)
            {
                token = token.Replace("\"", "\"\""); 
                token = "\"" + token + "\"";
            }
            return token;
        }
        public void Flush()
        {
            _writer.Flush();
        }
        public void Close()
        {
            if (_writer != null) _writer.Close();
        }
        /// <summary>
        /// sourceに指定されている内容でCSVファイルを
        /// 出力します。列はsourceの列順に出されます。
        /// </summary>
        /// <param name="source"></param>
        public virtual void WriteOnce(DataTable source)
        {
            List<int> list = new List<int>();
            for (int i = 0; i < source.Columns.Count; ++i)
            {
                list.Add(i);
            }

            WriteOnce(source, list);
        }
        /// <summary>
        /// sourceに指定されている内容でCSVファイルを出力します。
        /// 出力する列はcolumnOrderの順に出力されます。
        /// </summary>
        /// <param name="source"></param>
        /// <param name="columnOrder"></param>
        public virtual void WriteOnce(DataTable source, IList<int> columnOrder)
        {
            foreach (DataRow row in source.Rows)
            {
                List<string> list = new List<string>();
                foreach (int colIdx in columnOrder)
                {
                    list.Add(row[colIdx].ToString());
                }
                WriteLine(list.ToArray());
            }
        }
        #endregion

        #region IDisposable Members
        public virtual void Dispose()
        {
            Close();
            if (_writer != null) _writer.Dispose();
        }
        void IDisposable.Dispose()
        {
            this.Dispose();
        }

        #endregion
    }
}

 説明は以上です。次回の俺式CSVReaderのサンプルに動作例を掲載します。

指摘点とうがあればご連絡ください。