Visual StudioなしでC#【コンソールアプリでStream編】

# 概要

[前回](http://qiita.com/tak458/items/5f58d079641182796dc7)に引き続き、Visual StudioなしでC#アプリを作ります。
今回はコンソールアプリでStreamを扱うことをゴールにします。

何万行にも及ぶテキストデータ（固定長だったりCSVだったり）に列を追加するなどは業務システムではありがちかと思います。
cmd.exeでも出来なくはないですが、列数を認識してやろうとすると限界がすぐに来るんですよね。

## 縛り条件

* Windows環境
* グローバルな環境は汚しちゃダメ（インストール不可、システム・ユーザ環境変数設定不可）
* Visual Studioはもちろんない

# 

まずはビルド準備としてビルドバッチを作ります。
前回に比べて.Net Frameworkはバージョンをあげました。

```bat:build.bat
@echo off
setlocal

set PATH="C:\Windows\Microsoft.NET\Framework\v4.0.30319";%PATH%

csc.exe %*

endlocal
```

ビルドする際はこのバッチにスクリプトをD&DすればOK。
早速、ソースコードです。

```CSharp:stream.cs
using System;
using System.IO;
using System.Text;

namespace StreamSample
{
	public static class Program
	{
		public static void Main(params string[] args)
		{
			if (args.Length < 2)
				throw new ArgumentException("引数に指定したファイル数が足りない");
			
			using (var reader = new StreamReader(args[0]))
			using (var writer = new StreamWriter(args[1]))
			{
				while (!reader.EndOfStream)
				{
					var line = reader.ReadLine();
					writer.WriteLine(line);
				}
			}
		}
	}
}
```

・・・単純にコピーするだけです。

ではビルドして実行してみます。

```input.txt(入力ファイル)
hogehoge
fugafuga
fizzbuzz
```

```
>dir /B
build.bat
program.cs

>build.bat program.cs
Microsoft (R) Visual C# Compiler version 4.6.1586.0
for C# 5
Copyright (C) Microsoft Corporation. All rights reserved.

This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to C# 5, which is no longer the latest version. For compilers that support newer versions of the C# programming language, see http://go.microsoft.com/fwlink/?LinkID=533240


>dir /B
build.bat
program.cs
program.exe

>program.exe input.txt output.txt

>type output.txt
hogehoge
fugafuga
fizzbuzz

>dir /B
build.bat
input.txt
output.txt
program.cs
program.exe
```

入力ファイルが無事にコピーされました。
これで入力から出力までの流れができましたね。

# レコードを編集

では早速入力されたファイルを編集して出力してみます。
お題となる入力ファイルとソースコードはこちら。
2列目と3列目を入れ替えています。

```input.txt（入力ファイル）
"00001","hoge","fuga","memo1"
"00002","mike","neko","memo2"
"00003","fizz","buzz","memo3"
"00004","foo ","bar ","memo4"
"00005","follow","me","memo5"
```

```csharp:program.cs
using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Collections.Generic;

namespace StreamSample
{
	public static class Program
	{
		public static void Main(params string[] args)
		{
			if (args.Length < 2)
				throw new ArgumentException("引数に指定したファイル数が足りない");
			
			using (var reader = new StreamReader(args[0]))
			using (var writer = new StreamWriter(args[1]))
			{
				while (!reader.EndOfStream)
				{
					// CSVを分解（囲み文字の二重引用符も除去）
					var record = reader.ReadLine().Split(',').Select(a => a.Trim('"')).ToArray();
					
					// 入れ替え
					var output = new string[]{ record[0], record[2], record[1], record[3] };
					
					// CSV形式で出力
					writer.WriteLine(string.Join(",", output.Select(a => "\"" + a + "\"")));
				}
			}
		}
	}
}
```

ワンライナーでこれだけ書けるのはやっぱりC#楽だなぁ・・・。と思ってしまうのは私だけでしょうか。笑

実行結果を見てみます。

```
>program.exe input.txt output.txt

>type output.txt
"00001","fuga","hoge","memo1"
"00002","neko","mike","memo2"
"00003","buzz","fizz","memo3"
"00004","bar ","foo ","memo4"
"00005","me","follow","memo5"

```

きれいに入れ替わっていますね。

# おわりに

同じようなことはバッチやPowerShellでももちろん実行可能です。
ただ、バッチだと列数に制限があったり、PowerShellだと実用に耐えない速度だったりしました。
なのでC#を使ってみた次第です。