あなたのCSVが会社を潰す日 〜非エンジニアが知らずにやらかすWindowsの罠〜
CSV×改行コード(CRLF/LF)で二度と死なない:Excel/Windows産CSVをLinuxサーバへ安全に流し込む実戦手引き
結論
Windowsで作ったCSVをそのまま渡すと、相手(サーバやDB、エンジニアのスクリプト)側で行の区切りがズレて「カラム数が合わない」「文字化け」「取り込み失敗」などが起こります。対策は (1) 改行のそろえ(EOL統一) と (2) "CSVとして"正しく読み込むこと の二本柱。この記事の手順をコピペすれば回避できます。
これは"非エンジニアのあなた"に起きがちな事故です
- 「私がExcelで作ったデータで夜中にシステムが止まった」
- 「売上レポートが文字化けして、役員会議が延期になった」
- 「顧客リストの取り込みが失敗して、メール配信が止まった」
実はこれ、あなたの作業が悪いわけではありません。Windowsの改行のしかたとCSVのルールの"ちょっとしたズレ"が原因の環境差のせいです。でも、知らないとヤバいことになります。
実録:非エンジニアが引き起こした大事故(5選)
1. 「売上データが消えた」月末の地獄絵図
登場人物:営業企画のAさん(Excel大好き、IT知識ゼロ)
状況:毎月末、全国の売上データをExcelで整理してシステムに一括アップロード。今月は過去最高売上を記録し、役員も大注目。
事件発生:いつも通りCSVで書き出してアップロード→「処理中...」のまま3時間固まる→全データが中途半端に取り込まれて売上が半分以下に表示
大混乱:
- 役員「売上半減?!何があった?!」
- 営業部長「システム障害ですか?」
- 情シス緊急招集→夜中の3時まで復旧作業
- 翌朝の役員会議は「データ信頼性の問題」で大炎上
真犯人:Aさんが見やすさのために住所欄で**Alt+Enter(セル内改行)**を多用→CSV出力時に引用符が一部外れて行がバラバラに→取り込み処理が暴走
Aさんの心境:「私、何か悪いことした...?普通にExcelで整理しただけなのに...会社に迷惑かけちゃった...」
2. 「顧客に間違った人の個人情報を送信」プライバシー大事故
登場人物:マーケティング部のBさん(キャンペーン担当、几帳面)
状況:新商品キャンペーンで1万人にパーソナライズメールを送信予定。顧客データベースからExportしたCSVに、手作業で「特別オファー金額」を追加して一括処理。
事件発生:配信開始30分後、お客様相談室に電話が殺到
悲劇の内容:
- 田中さんに「佐藤様、あなたの年収1200万円に相応しい...」
- 佐藤さんに「山田様、シングルマザーのあなたを応援...」
- 山田さんに「鈴木様、ご主人の定年後の資産形成...」
原因:顧客名の一部に**会社名(改行付き)**が含まれていた→CSV処理でデータがズレて個人情報が完全に入れ替わり
その後:
- 謝罪対応に1週間、法務部も巻き込んで大騒動
- 個人情報保護委員会への報告書作成
- Bさん、責任を感じて体調不良で1ヶ月休職
Bさんの証言:「まさか自分がデータを作っただけで、お客様にご迷惑をかけるなんて...もうExcelが怖くて触れない」
3. 「給与計算が狂って全社員に間違った給与を支給」
登場人物:人事部のCさん(勤続15年のベテラン)
状況:働き方改革で在宅勤務手当や時差出勤手当が新設→給与システムが対応していないため、手当部分だけExcelで管理してCSVで給与システムに追加取り込み
大惨事:給与支給日の朝、全社員500人の銀行口座に給与振り込み完了→新入社員が部長より高給取りに、部長の給与が最低賃金以下に
阿鼻叫喚:
- 新入社員D君「えっ、僕の給料80万円?間違いですよね?」
- 部長「俺の給料8万円って...バイト以下じゃないか!」
- 経理「銀行への振り込み取り消しは不可能です」
- 社長「信用問題になる、すぐ何とかしろ!」
原因:手当CSV内のコメント欄に改行を含む「業務内容詳細」を記載→取り込み時にデータがずれて、社員番号と金額がバラバラに対応
後処理:
- 全員に謝罪と訂正振り込み(2日後)
- 労基署から「賃金支払いの不備」として指導
- Cさん「15年間ミスしたことなかったのに...」
4. 「株主総会資料の数字が全部デタラメ」
登場人物:IR担当のEさん(数字に強い、責任感強すぎ)
状況:上場企業の四半期決算発表前日、最終チェックのため会計データをExcelで整理→投資家向け資料に使う重要指標をCSV出力
絶望的展開:翌日の決算説明会で、売上成長率が-95%、営業利益率が400% などの異常数値を堂々と発表
会場の様子:
- 投資家A「売上がほぼゼロ?倒産するんですか?」
- 投資家B「利益率400%って...粉飾決算ですか?」
- アナリスト「こんなデタラメな数字、初めて見た」
- 株価、決算発表直後に30%暴落
真相:財務データの「前年同期比」列に改行付きコメント(「※為替影響考慮\n実質成長率は...」)が混入→CSV処理で数値列がコメント列とずれて、とんでもない計算結果に
Eさんのその後:「会社の株価を暴落させた女」として社内で有名に→転職を決意
5. 💀「薬事法違反で業務停止命令」製薬会社の悪夢
登場人物:品質管理部のFさん(薬学修士、超真面目)
状況:新薬の臨床試験データをExcelで管理→承認申請用にCSVで厚労省システムへ提出
致命的ミス:データ取り込み時に患者の症状記録が別の患者と入れ替わり→「重篤な副作用なし」の患者が「重篤な副作用あり」として申請
発覚と大惨事:
- 承認審査中に厚労省が異常を発見
- 「臨床データの信頼性に重大な疑義」として審査中止
- 業界紙一面「○○製薬、データ改ざん疑惑」
- 株価50%下落、業務停止命令3ヶ月
- 新薬開発費100億円が水の泡
Fさんの告白:「患者さんの命に関わるデータなのに...私の手でこんなことになるなんて。一生償いきれない」
原因:症状記録に改行付きの長文があったが、CSV出力時の引用処理が不完全→患者IDと症状データの対応が崩壊
あなたも明日やらかすかもしれない理由
これらの事故、**全て「普通にExcelを使っただけ」**で起きています。
- Windowsで普通にExcelを使う
- 見やすくするためにセル内で改行(Alt+Enter)
- CSV保存してシステムに渡す
この当たり前の流れで大事故が起きるのが現実です。
しかも**「昨日まで正常だったのに今日だけ異常」**というパターンが多く、原因究明まで時間がかかって被害が拡大します。
「私は単純なデータしか扱わないから大丈夫」 ←これが一番危険。気づかないうちに改行やコメントが紛れ込んで、いつか必ず事故ります。
なにが起きているの?(やさしい説明)
-
改行の記号がOSで違う:
- Windowsは行の終わりに CRLF(2文字)
- macOS/Linuxは LF(1文字)
-
CSVはルールがある:
- セルの中に改行があってもOK(ただし**"で囲む**必要あり)
- "(ダブルクォート)自体が入るときは "" と二重に
エンジニア側の取り込み(サーバ/DB/スクリプト)がこれらを**“文字通りCSVとして”扱っていない**と、行が途中で切れたり、見えない文字(
)が混ざって数値にできなかったりします。
macなら大丈夫? いいえ。Excel for Macが出すCSVでも、Windows式の改行やBOMが入ることがあり、同じ事故が起きます。
あなたができる安全対策(コピペでOK)
- 渡す前に“改行をそろえる”(CRLF→LF)
- 取り込み側は“CSVとして読む”(行分割ではなく、CSVモード/専用パーサを使ってもらう)
この記事には、
- 前処理のコピペ用コマンド(Windows/ Mac /Linux)
- DB取り込みの正しい設定例(PostgreSQL / MySQL)
-
壊れやすいパターンのチェック方法
をまとめました。仕組みはあと回しでも、手順だけ真似すれば事故は止まります。
想定読者
- Windowsで出力したCSVを Linux/macOSサーバ のDBに取り込む人
- Excel/業務システムが吐くCSVで取り込みが不安定な現場
- CSVパースを自作していて“行数/カラム数が合わない”系の不具合に悩む人
この記事のゴール
- 改行コードとCSV仕様の要点を 実務目線 で整理
- 再発防止テンプレ(前処理ワンライナー/DB取り込みレシピ/CIチェック)を配布
まず用語整理:EOL(改行コード)の違い
OS | 記号 | 実体 |
---|---|---|
Windows | CRLF | \r\n |
macOS / Linux / Unix | LF | \n |
- エディタや簡易スクリプトが
\n
だけでsplit すると、末尾に\r
が残って"\rOK"
のようなゴミ文字化→数値変換エラー、JOINミスなどに波及。 - ExcelのCSV は プラットフォームを問わずCRLF を出すケースが多い(Excel for Macでも)。
CSVの“正解”挙動(RFC 4180 要旨)
- 改行やカンマを含むフィールドは 二重引用符
"
で囲む - フィールド内の二重引用符は
""
と二重化 してエスケープ - 行の区切りは原則レコード境界(=EOL)。引用符で囲まれたフィールド内のEOLは1セル内の文字列として扱われる
つまり、フィールド内改行はOK。ダメなのは 引用なしで生改行が入っているCSV と EOLと引用の混在・不整合。
よくある症状
- 取り込みツールで カラム数が合わない(途中で行が切れてしまう)
- 数値列やフラグ列に
\r
が混入 してcast
エラー - 先頭カラム名に BOM(\uFEFF) が混入→カラム名不一致
まずは現物診断(安全な読み方)
# CR(\r) を含む行を検出(^M表示)
grep -n $'\r' file.csv | head
# 引用符の不整合(簡易チェック:行ごとの '"' 出現数が奇数なら怪しい)
awk -F '"' '{if ((NF-1)%2==1) print "unbalanced at line", NR}' file.csv | head
# 文字コード/BOMの確認
file -I file.csv # application/csv; charset=utf-8 など
xxd -g 1 -l 3 file.csv # 先頭が EF BB BF なら UTF-8 BOM
前処理テンプレ:EOL正規化(LF統一)
Linux/WSL/macOS 共通
# 破壊的にCR削除(CRLF→LF)
sed -i '' -e 's/\r$//' file.csv # macOS(BSD sed)
# Linuxなら: sed -i 's/\r$//' file.csv
# 非破壊で出力を分けたい場合
tr -d '\r' < file.csv > file_lf.csv
# 専用ツール(Homebrewで入る)
dos2unix file.csv
Windows PowerShell
(Get-Content file.csv -Raw) -replace "`r`n","`n" |
Set-Content file.csv -NoNewline -Encoding utf8
ポイント: 中身をCSVとして壊さない。EOL正規化はOKだが、カンマや引用の置換は厳禁。
DB取り込みの“正しい姿”
PostgreSQL
COPY mytable(col1, col2, ...)
FROM '/path/file.csv'
WITH (
FORMAT csv,
HEADER true,
DELIMITER ',',
QUOTE '"',
ESCAPE '"'
);
-
FORMAT csv
を使う限り、引用付きフィールド内改行も扱える。CRLF/LFはどちらも処理可。
MySQL / MariaDB
LOAD DATA INFILE '/path/file.csv'
INTO TABLE mytable
CHARACTER SET utf8mb4
FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '"'
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES;
- Windows由来なら
LINES TERMINATED BY '\r\n'
を明示。LFに正規化した場合は\n
を指定。
SQLite(補足)
.mode csv
.import file.csv mytable
- 混在EOLは不安定。事前にLFへ正規化が無難。
アプリ側の“壊れない読み方”
Python(標準csv)
import csv
with open('file.csv', newline='', encoding='utf-8') as f:
reader = csv.reader(f) # 引用・改行を仕様通りに処理
for row in reader:
...
pandas
import pandas as pd
df = pd.read_csv('file.csv', dtype=str, keep_default_na=False)
Node.js(例:csv-parse)
import { parse } from 'csv-parse'
import fs from 'node:fs'
fs.createReadStream('file.csv')
.pipe(parse({
columns: true,
relax_quotes: false,
relax_column_count: false
}))
.on('data', r => { /* ... */ })
Go
r := csv.NewReader(file)
r.LazyQuotes = false // 仕様に厳格
records, err := r.ReadAll()
重要:
readlines()
で行を split しない。必ず CSV パーサに任せる。
エディタ & Git の地雷回避
VS Code
- 右下の End of Line で
LF
に変更 - 設定例:
{
"files.eol": "\n",
"editor.renderControlCharacters": true
}
Git
git config --global core.autocrlf input # macOS/Linux
# WindowsでLF維持したい場合も 'input' を推奨
.gitattributes
でCSVだけLFを強制:
*.csv text eol=lf
BOM/文字コードの取り扱い
- 先頭に UTF-8 BOM があると、ヘッダ名に不可視文字が混入 → カラム不一致
- 事前に除去:
# 先頭3バイトのBOMを剥がす(非破壊)
tail -c +4 file.csv > file_nobom.csv
- もしくは
iconv
で再エンコード:
iconv -f utf-8 -t utf-8 file.csv -o file_nobom.csv
実戦レシピ:ワンショット取り込み
set -euo pipefail
in="file.csv"
out="/tmp/file.lf.csv"
# 1) EOLをLFに正規化
tr -d '\r' < "$in" > "$out"
# 2) 構造チェック
csvclean -n "$out" || { echo "CSV structure looks suspicious"; exit 1; }
# 3) PostgreSQLへ(例)
psql -v ON_ERROR_STOP=1 -c "\
COPY mytable(col1,col2,...) FROM '$out' \
WITH (FORMAT csv, HEADER true, DELIMITER ',', QUOTE '"', ESCAPE '"');"
CIでの再発防止(プリチェック)
pre-commitフック例
#!/usr/bin/env bash
set -euo pipefail
bad=$(grep -IlR $'\r' -- '*.csv' || true)
if [ -n "$bad" ]; then
echo "[EOL] CRLF detected in:"; echo "$bad"; exit 1
fi
# 引用不整合の簡易検査
echo "$@" | xargs -r -n1 awk -F '"' '{if ((NF-1)%2==1) {print FILENAME ": line" NR " has unbalanced quotes"; exit 1}}'
.gitattributes
も併用:
*.csv text eol=lf
FAQ
Q. macOSはUNIX系だから問題にならない?
A. No。特定条件下でだめ。macOS自体はLFだが、たとえばExcel for Mac や Windows生成のCSV を扱うと CRLFやBOM混入 で同様に破綻する。取り込み先がLinuxでもmacOSでも、前処理と正しいローダ が必要。
Q. フィールド内改行は全部排除すべき?
A. 仕様的にはOK。どうしても運用上NGなら、書き出し側で改行→\n
等に変換し、読み込み時に復元するポリシーを決める(要合意)。
Q. 自作パーサを直せばよい?
A. 原則おすすめしない。パーサは既存実装(DBのCSVモード、言語標準、実績ライブラリ)を使う。
2. 「ヘッダが見つからない」BOMの罠
状況:マーケがExcelで出したCSVをpandasで読み、PostgreSQLへCOPY
。なぜか列名id
が見つからない。
症状:KeyError: 'id'
/ DB側では column "id" does not exist
。
原因:CSV先頭にUTF-8 BOM() が付与。ヘッダが実際は id,name,...
になっており一致せず。
再現の断片:
EF BB BF 69 64 2C 6E 61 6D 65 ... # バイト列先頭がEF BB BF
対処:
- 事前に
tail -c +4
でBOM除去、またはiconv
再エンコード - pandas側は
encoding='utf-8-sig'
で読み込み、DB投入前に明示的にカラム名を正規化
学び:BOMは“見えない敵”。ヘッダ不一致やカラム名の取り違えはBOMを疑う。
3. 「OK
」で判定バグ—CRの居残り
状況:社内ツール(Python)が
区切りで行をsplitしてCSVを読んでいた。Windows発のCSVに切り替えた日から判定が不安定に。
症状:status == 'OK'
のはずがFalse
判定、数値カラムのint('100 ')
で例外。
原因:WindowsのCRLF行末を
だけで分割したため、末尾の
が値に残留。
再現の断片:
for line in open('w.csv').read().split('
'):
cols = line.split(',')
status = cols[-1]
# 'OK
' になっていて比較に失敗
対処:
- 入力前に CR除去(CRLF→LF)
- そもそも
csv
モジュール や DBのCSVモード を使う(行splitをやめる)
学び:「行で割る」は事故の元。CSVはCSVとして読む。EOLは最初に正規化。
まとめ(チェックリスト)
- EOL統一(CRLF→LF)
- UTF-8/BOM除去
- CSVローダ/パーサ利用(行split禁止)
-
引用とエスケープ(
"..."
&""
) -
DB側オプション適合(
FORMAT csv
/LINES TERMINATED BY
) - CI/フックで検知
付録:最小再現データ
id,name,comment
1,"Alice","Hello\nWorld"
2,Bob,"He said ""Yes"""
3,Carol,
- これを CRLF にして、素朴な
split('\n')
実装 に食わせると破綻する。DBのCSVモードや言語のCSVパーサなら正しく解釈できる。
ライセンス
- 本記事のコード片は MIT とします。業務ドキュメントやPlaybookへの転用可。
Discussion