WSLとiconvを使ってWindows上でSJISファイルをEBCDIC (IBM-930) に変換する方法

# はじめに
Windows 上で Shift_JIS のテキストファイルを EBCDIC（特に IBM-930）に変換するプログラムを C# で実装できないか調査した結果、**Windows 単体では変換が困難**であることが分かりました。

.NET の Encoding.GetEncoding() を使った変換や、iconv.dll を DLL として直接呼び出すアプローチは、特に日本語に対応した EBCDIC（IBM-930）ではうまくいきませんでした。

そこで本記事では、**WSL（Windows Subsystem for Linux）と iconv コマンドを組み合わせることで、C# アプリケーションから文字コード変換を実現する方法**をご紹介します。

### 補足情報
.NET 環境では、英数字のみの EBCDIC（IBM037）は使用可能ですが、日本語が含まれる IBM930 などは未対応です。

| `Encoding.GetEncoding("名前")` で指定 | コードページ | 内容                   |
| -------------------------------- | ------ | -------------------- |
| `"IBM037"`                       | 37     | アメリカ英語（英数字のみ）        |
| `"IBM290"`                       | 290    | 日本語カタカナ EBCDIC（限定）   |
| `"IBM930"`                       | 対応なし   | 日本語対応 EBCDIC（本記事の対象） |


### やりたいこと

* 日本語を含む Shift_JIS ファイルを EBCDIC（IBM-930）に変換したい
* できれば Windows 上で完結させたい
* WSL を介して C# アプリから iconv を呼び出す形でもOK **（結果、出来ずWSLに頼りました）**


# 最初に試した方法と課題
まずは gettext-iconv-windows を使って、Windows ネイティブで変換できないか試しましたが、IBM-930 の文字セットに対応していないため断念しました。

https://github.com/mlocati/gettext-iconv-windows


## 解決方法（WSL + iconv）
Linux 環境では iconv が IBM-930 に対応していることから、WSL 上の Ubuntu にて変換を実行する方式を採用しました。

手順は以下の通りです
1. WSL + Ubuntu を導入
1. iconv（libc-bin）をインストール
1. WSL 側で IBM-930 が対応しているか確認
1. Windows 側とのファイル共有
1. C# アプリから WSL の iconv を呼び出す

# 手順詳細

### 1. WSL のインストール

```powershell
wsl --install -d Ubuntu
```
※ すでに WSL を導入済みの場合はこのステップは不要です。

### 2. iconv のインストール（libc-bin）

```bash
sudo apt update
sudo apt install -y libc-bin
```

### 3. IBM-930 の対応確認

```bash
iconv -l | grep IBM930
```

出力例

```text
CSIBM930//
IBM930//
```

### 4. Windows と WSL 間のファイル共有
たとえば、Windows 側の以下のファイルで

```
C:\Users\<YourUser>\Documents\input.txt
```

は、WSL 側から以下のようにアクセスできます。

```
/mnt/c/Users/<YourUser>/Documents/input.txt
```

### 5. C# から WSL の iconv を呼び出す（WinForms 例）
ボタンイベントで iconv を WSL 経由で実行するサンプルコードです。

```c#
private void button1_Click(object sender, EventArgs e)
{
    string inputPath = "/mnt/c/Users/YourUser/Documents/input.txt";
    string outputPath = "/mnt/c/Users/YourUser/Documents/output.ebc";

    string wslCmd = $"wsl -d Ubuntu iconv -f CP932 -t IBM930 \"{inputPath}\" -o \"{outputPath}\"";

    var psi = new ProcessStartInfo
    {
        FileName = "cmd.exe",
        Arguments = $"/C {wslCmd}",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        CreateNoWindow = true
    };

    using (var proc = Process.Start(psi))
    {
        string stdout = proc.StandardOutput.ReadToEnd();
        string stderr = proc.StandardError.ReadToEnd();
        proc.WaitForExit();

        if (proc.ExitCode != 0)
            MessageBox.Show($"変換失敗:\n{stderr}", "iconv エラー");
        else
            MessageBox.Show("変換成功", "完了");
    }
}

```

:::note info
YourUser はご自身のユーザー名に置き換えてください。
:::

# まとめ

| 方法                        | 結果            |
| ------------------------- | ------------- |
| iconv.dll を C# から呼び出し     | ❌ 未対応／不安定     |
| gettext-iconv-windows を利用 | ❌ IBM-930 非対応 |
| WSL + iconv を使った実行        | ✅ 安定して成功      |


# おわりに
今回の方法では WSL を経由していますが、将来的には WSL を使わずに Windows 上のみで変換できる方法を模索していきたいと考えています。


# 参考にしたもの
* [iconv](https://man7.org/linux/man-pages/man1/iconv.1.html)
* [gettext-iconv-windows](https://github.com/mlocati/gettext-iconv-windows)
* [.NET Encoding.GetEncoding ドキュメント](https://learn.microsoft.com/ja-jp/dotnet/api/system.text.encoding.getencoding?view=net-9.0)