みなさん、こんにちは。
CSVファイルを扱う際、文字化けに悩まされた経験はありませんか?特に、日本語のデータを含むファイルをWindowsのExcelで開くと、文字がぐちゃぐちゃになってしまうことがありますよね。
この文字化け問題を解決する1つの方法が、BOM(バイトオーダーマーク)付きのUTF-8でCSVファイルを保存することです。以前のブログ記事でも、この方法を詳しく解説しました。
Pythonではencoding="utf-8-sig"
と指定するだけでBOM付きCSVを簡単に扱えます。しかし、他のプログラミング言語では少し事情が異なります。
今回は、BOM付きCSVを扱うための各言語ごとの違いと実装方法を、コード例を交えてまとめてみました。
BOMってそもそも何?
BOM(バイトオーダーマーク)とは、テキストファイルの先頭に付く、ファイルの種類やエンコーディングを示す特別なマークのことです。UTF-8ではEF BB BF
という3バイトのデータで表現されます。
多くのエディタやプログラムはBOMを気にせず処理しますが、Excelや一部の古いシステムではこのBOMを判別して、エンコーディングを正しく認識する仕組みになっています。
そのため、日本語を含むCSVをExcelユーザーと共有する際には、BOMを付けてあげるのが親切なのです。
言語別のBOM付きCSVの扱い方
Python
Pythonは、BOM付きUTF-8の扱いが最も簡単な言語の1つです。utf-8-sig
という専用のエンコーディングを指定するだけで、読み書きの両方を自動的に処理してくれます。
読み込み(input.csv)
import csv
# BOM付きUTF-8として自動的に認識して読み込む
with open("input.csv", "r", encoding="utf-8-sig") as f:
reader = csv.reader(f)
for row in reader:
print(row)
書き込み(output.csv)
import csv
data = [["名前", "年齢", "所属"], ["山田太郎", 30, "営業部"]]
# BOMを自動的に付与して書き込む
with open("output.csv", "w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerows(data)
utf-8-sig
を使うだけでOKという手軽さがいいですね!
JavaScript (Node.js)
JavaScriptでは、BOMは単なる「隠れた文字」として扱われます。そのため、読み込む際にBOMを自分で取り除く処理が必要ですし、書き込む際も自分でBOMを先頭に追加する必要があります。
読み込み(input.csv)
const fs = require('fs');
let data = fs.readFileSync("input.csv", "utf8");
// BOM(\uFEFF)をチェックして除去
if (data.charCodeAt(0) === 0xFEFF) {
data = data.slice(1);
}
console.log(data);
書き込み(output.csv)
const fs = require('fs');
const rows = [
["名前", "年齢", "所属"],
["山田太郎", "30", "営業部"]
];
let csv = rows.map(r => r.join(",")).join("\n");
// BOM(\uFEFF)を文字列の先頭に付与
csv = "\uFEFF" + csv;
fs.writeFileSync("output.csv", csv, "utf8");
BOMはUnicodeでは\uFEFF
という文字として表現されるため、これを文字列として扱います。手動での処理が必須になります。
Java
JavaもJavaScriptと同様に、BOMを自動で処理しません。読み込み・書き込みともに、自分でBOMの有無をチェックしたり、追加したりする必要があります。
読み込み(input.csv)
import java.io.*;
public class ReadCSV {
public static void main(String[] args) throws Exception {
try (BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream("input.csv"), "UTF-8"))) {
String firstLine = br.readLine();
// 最初の行の先頭にBOMがあるか確認し、あれば除去
if (firstLine != null && firstLine.startsWith("\uFEFF")) {
firstLine = firstLine.substring(1);
}
System.out.println(firstLine);
}
}
}
InputStreamReader
は指定されたエンコーディングでファイルを読み込みますが、BOMは無視しません。そのため、読み込んだ文字列からBOMを取り除く必要があります。
書き込み(output.csv)
import java.io.*;
public class WriteCSV {
public static void main(String[] args) throws Exception {
try (Writer writer = new OutputStreamWriter(
new FileOutputStream("output.csv"), "UTF-8")) {
// BOMを明示的に書き込む
writer.write('\uFEFF');
writer.write("名前,年齢,所属\n");
writer.write("山田太郎,30,営業部\n");
}
}
}
Writer
を使ってファイルに書き込む際も、BOMを表す\uFEFF
を先頭に自分で書き込む必要があります。
C# (.NET)
C#は、Pythonほどではないにせよ、比較的簡単にBOMを扱うことができます。Encoding
クラスを使うことで、BOM付きかそうでないかを意識して読み書きできます。
読み込み(input.csv)
using System;
using System.IO;
using System.Text;
class Program {
static void Main() {
// UTF-8を指定すると、BOMの有無を自動で判別してくれる
string text = File.ReadAllText("input.csv", Encoding.UTF8);
Console.WriteLine(text);
}
}
.NET Framework
や.NET Core
のEncoding.UTF8
は、賢くBOMの有無を自動的に認識してくれます。
書き込み(output.csv)
using System;
using System.IO;
using System.Text;
class Program {
static void Main() {
string[] lines = {
"名前,年齢,所属",
"山田太郎,30,営業部",
"鈴木花子,25,開発部"
};
// BOMを付与したUTF-8で保存
File.WriteAllLines("output.csv", lines, new UTF8Encoding(true));
}
}
UTF8Encoding(true)
の引数をtrue
にすることで、BOM付きでファイルを保存できます。false
にすればBOMなしになります。
実務での使い分け – BOM付き? BOMなし?
これまでBOM付きの扱いに焦点を当ててきましたが、実際の開発現場では、BOMがない純粋なUTF-8を使う場面の方が多いかもしれません。
BOM付き(UTF-8-SIG) | BOMなし(UTF-8) | |
得意なこと | Windows版Excelで開いても文字化けしない | 多くのシステムやAPIとの互換性が高い |
主な用途 | ExcelユーザーとCSVを共有する、手動で開く | Webシステム間のデータ連携、UNIX/Linux環境での処理、コマンドラインツール |
もし、「作ったCSVファイルを誰かが手作業でExcelで開く」という想定ならBOM付きがおすすめです。逆に、「別のシステムが自動で読み込む」という場合は、BOMなしの方が無用なトラブルを防げるでしょう。
まとめ
言語 | 読み込み時 | 書き込み時 |
Python | utf-8-sig | utf-8-sig |
JavaScript | BOMを除去 (.slice(1) ) | BOMを追加 ("\uFEFF" + ... ) |
Java | BOMを除去 (.substring(1) ) | BOMを追加 (writer.write('\uFEFF') ) |
C# | Encoding.UTF8 | new UTF8Encoding(true) |
PythonとC#はライブラリの機能としてBOMを意識した処理が用意されており、比較的扱いやすいですね。一方、JavaScriptやJavaでは、BOMを1文字として扱うため、手動で処理を実装する必要があります。
普段使っている言語の特性を理解して、状況に合わせてBOMを使い分けられると、文字化けで困ることもグッと減るはずです。
本日も最後までお読みいただき、ありがとうございました。
それでは、よいCSVライフを!