PythonでCSVを読み書きするには、標準ライブラリの csv モジュールを使い、open(ファイル名, newline="", encoding="utf-8") で開いたファイルを csv.reader / csv.writer に渡します。 インストールは不要です。

この記事では、読む・書く・追記・辞書で扱う(DictReader / DictWriter)のコピペ用テンプレートを最初にまとめ、そのあとで、つまずきやすい newline="" の意味、Excel向けの文字コード(utf-8-sig と cp932)、UnicodeDecodeError、クォート を、実際にファイルを書き出してバイト列で確認した結果つきで解説します。出力はすべて Python 3.14.7(pandasは3.0.6)で実行したものです。


Python CSV読み書きの早見表

やりたいこと 書き方 ポイント
1行ずつリストで読む for row in csv.reader(f): 値はすべて文字列
1行ずつ辞書で読む for row in csv.DictReader(f): 1行目がキーになる
リストで書く csv.writer(f).writerows(rows) 1行なら writerow
辞書で書く csv.DictWriter(f, fieldnames=[...]) writeheader() を忘れずに
追記する open(..., "a", newline="") ヘッダーは書かない
開き方(共通) open(p, newline="", encoding="utf-8") newline="" は必ず付ける
Excelで開くCSVを書く encoding="utf-8-sig" 先頭にBOMが付く
Excelで保存したCSVを読む encoding="cp932" または "utf-8-sig" 保存形式による
ヘッダーを飛ばす header = next(reader)
TSVを読む・書く delimiter="\t"
すべての値を " で囲む quoting=csv.QUOTE_ALL
大きいファイル for で1行ずつ処理 list() にしない
表として集計したい pd.read_csv(p) pandas

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PythonでCSVを読み書き|コピペ用テンプレートと文字化け対策」


コピペ用テンプレート:読む・書く・追記・辞書で扱う

どのテンプレートも import csv だけで動きます。newline="" と encoding= は毎回書くと、OSや環境による違いが出にくくなります。

CSVに書き込む(csv.writer)

import csv

rows = [
    ["id", "name", "qty"],
    [1, "ペン", 120],
    [2, "ノート", 45],
]
with open("items.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(rows)          # 1行ずつなら writer.writerow(row)

print(open("items.csv", "rb").read())

実行結果(Python 3.14.7、書き出したファイルのバイト列):

b'id,name,qty\r\n1,\xe3\x83\x9a\xe3\x83\xb3,120\r\n2,\xe3\x83\x8e\xe3\x83\xbc\xe3\x83\x88,45\r\n'

csvモジュールは行末に \r\n(CRLF)を書きます。 これはCSVの仕様(RFC 4180)に合わせた既定値で、lineterminator="\n" で変えられます。数値は自動で文字列になります。

CSVを読み込む(csv.reader)

import csv

with open("items.csv", newline="", encoding="utf-8") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)
['id', 'name', 'qty']
['1', 'ペン', '120']
['2', 'ノート', '45']

読み込んだ値はすべて文字列(str)です。 数値として計算するには変換が必要です(後述)。

CSVに追記する(モード "a")

import csv

with open("items.csv", "a", newline="", encoding="utf-8") as f:
    csv.writer(f).writerow([3, "クリップ", 300])

with open("items.csv", newline="", encoding="utf-8") as f:
    print(f.read())
id,name,qty
1,ペン,120
2,ノート,45
3,クリップ,300

"w" は上書き、"a" は末尾に追加です。追記は元のファイルと同じ encoding で開きます。 utf-8-sig で書いたファイルに utf-8-sig で追記しても、途中にBOMは入りませんでした(実行結果:b'\xef\xbb\xbfid\r\n1\r\n'。BOMは先頭の1つだけ)。

辞書として読む(csv.DictReader)

import csv

with open("items.csv", newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        print(row["name"], row["qty"], row)
ペン 120 {'id': '1', 'name': 'ペン', 'qty': '120'}
ノート 45 {'id': '2', 'name': 'ノート', 'qty': '45'}
クリップ 300 {'id': '3', 'name': 'クリップ', 'qty': '300'}

1行目(ヘッダー)がキーになるので、列の順番が変わっても row["name"] で取り出せます。 実務では reader より DictReader のほうが読みやすく、列の追加にも強いです。

辞書から書く(csv.DictWriter)

import csv

members = [
    {"id": 1, "name": "佐藤", "email": "sato@example.com"},
    {"id": 2, "name": "鈴木"},                          # emailがない
]
with open("members.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["id", "name", "email"], restval="")
    writer.writeheader()
    writer.writerows(members)

print(open("members.csv", encoding="utf-8").read())
id,name,email
1,佐藤,sato@example.com
2,鈴木,

fieldnames で列の順番を決め、writeheader() でヘッダー行を書きます。 足りないキーは restval の値(既定は空文字)で埋まります。

逆に fieldnames にないキーがあるとエラーになります。

w = csv.DictWriter(f, fieldnames=["id", "name"])
w.writerow({"id": 1, "name": "佐藤", "age": 31})
ValueError: dict contains fields not in fieldnames: 'age'

→ extrasaction="ignore" を付けると余分なキーは無視されます(実行結果:1,佐藤)。

DictReaderで列が足りない・多い行を読む

import csv, io
s = "id,name,qty\n1,ペン\n2,ノート,45,余分\n"
for r in csv.DictReader(io.StringIO(s), restval="(なし)", restkey="extra"):
    print(r)
{'id': '1', 'name': 'ペン', 'qty': '(なし)'}
{'id': '2', 'name': 'ノート', 'qty': '45', 'extra': ['余分']}

足りない列は restval(既定は None)、余った値は restkey(既定は None というキー)にリストで入ります。


newline=""を付けないと空行が入る理由

newline="" を付けないと、Windowsでは1行ごとに空行が入ったCSVになります。 公式ドキュメントでも、csvモジュールでファイルを開くときは newline="" を指定するよう書かれています。

仕組み:\r\n がさらに変換されて \r\r\n になる

  1. csvモジュールは行末に \r\n を書く
  2. Windowsのテキストモードは、書き込み時に \n を \r\n に変換する
  3. 結果、行末が \r\r\n になり、Excelなどで開くと空行が入って見える

newline="" は「Pythonによる改行の変換をしない」という指定です。Linux上で、Windowsと同じ変換(newline="\r\n")を指定して再現し、バイト列を比べました。

import csv
row = ["id", "name"]

with open("ok.csv", "w", newline="", encoding="utf-8") as f:       # 正しい書き方
    csv.writer(f).writerow(row)

with open("ng.csv", "w", newline="\r\n", encoding="utf-8") as f:   # Windowsで省略したときと同じ変換
    csv.writer(f).writerow(row)

with open("linux.csv", "w", encoding="utf-8") as f:                # Linuxで省略した場合
    csv.writer(f).writerow(row)

print("ok:", open("ok.csv", "rb").read())
print("ng:", open("ng.csv", "rb").read())
print("linux省略:", open("linux.csv", "rb").read())
ok: b'id,name\r\n'
ng: b'id,name\r\r\n'
linux省略: b'id,name\r\n'

Linux・macOSでは省略しても変換されないため、問題が表に出ません。 そのため「手元では動いたのに、Windowsで作ったCSVにだけ空行が入る」ということが起こります。\r\r\n のファイルを読み込むと、空のリストが混ざりました。

[['1', 'ペン'], [], ['2', 'ノート'], []]

(ng.csv と同じ方法で2行書いたファイルを csv.reader で読んだ結果)

読み込み時も newline="" が必要:値の中の改行

値の中に改行を含むCSVは、読み込み時にも newline="" がないと改行が変わります。

import csv
with open("memo.csv", "w", newline="", encoding="utf-8") as f:
    csv.writer(f).writerow([1, "1行目\r\n2行目"])

with open("memo.csv", newline="", encoding="utf-8") as f:
    print("newline=''  :", list(csv.reader(f)))
with open("memo.csv", encoding="utf-8") as f:
    print("newline省略 :", list(csv.reader(f)))
newline=''  : [['1', '1行目\r\n2行目']]
newline省略 : [['1', '1行目\n2行目']]

省略すると、値の中の \r\n が \n に変わりました。読むときも書くときも newline="" を付けると覚えておけば安心です。


文字コード:utf-8-sigとcp932の使い分け

Excelでそのまま開くCSVを作るなら utf-8-sig、Excelで「CSV(コンマ区切り)」として保存されたファイルを読むなら cp932 です。 3つの文字コードで同じ内容を書き出し、先頭のバイトを比べました。

import csv
row = [["id", "name"], [1, "佐藤"]]
for enc in ["utf-8", "utf-8-sig", "cp932"]:
    fn = f"out_{enc}.csv"
    with open(fn, "w", newline="", encoding=enc) as f:
        csv.writer(f).writerows(row)
    print(f"{enc:10}", open(fn, "rb").read())
utf-8      b'id,name\r\n1,\xe4\xbd\x90\xe8\x97\xa4\r\n'
utf-8-sig  b'\xef\xbb\xbfid,name\r\n1,\xe4\xbd\x90\xe8\x97\xa4\r\n'
cp932      b'id,name\r\n1,\x8d\xb2\x93\xa1\r\n'

utf-8-sig は先頭に EF BB BF(BOM)の3バイトが付きます。 ExcelはこのBOMを見てUTF-8と判断するため、日本語が正しく表示されます。cp932 は「佐藤」が4バイト(8D B2 93 A1)で、UTF-8(6バイト)とは別のバイト列です。

encoding BOM 主な用途 注意点
utf-8 なし システム間の連携、Web、DB取り込み Excelで直接開くと文字化けすることがある
utf-8-sig(書き込み) 付ける Excelで開くCSVを出力 BOMを想定しないシステムでは先頭に余分な文字が入る
utf-8-sig(読み込み) あれば除く BOM付き・なし両方のUTF-8を読む BOMがなくても普通に読める
cp932 なし Excelで保存された日本語CSV、古いシステム 絵文字など一部の文字は書けない

文字化けの仕組みやExcel側での開き方は、「文字化けの原因と直し方」の記事で詳しく扱っています。ここではPythonでの書き方に絞ります。

BOM付きをutf-8で読むとKeyErrorになる

import csv
with open("out_utf-8-sig.csv", newline="", encoding="utf-8") as f:
    r = next(csv.DictReader(f))
print(r)
print(r["id"])
{'id': '1', 'name': '佐藤'}
KeyError: 'id'

BOMが1列目のキー名にくっつき、'id' というキーになります。 画面上は id に見えるため気づきにくいエラーです。encoding="utf-8-sig" で開くとBOMが取り除かれ、r["id"] で 1 が取れました。utf-8-sig はBOMがないファイルもそのまま読めるので、UTF-8のCSVを読むときは utf-8-sig にしておくと安全です。


UnicodeDecodeErrorの原因と対処

UnicodeDecodeError は、ファイルの実際の文字コードと、encoding= で指定した文字コードが違うときに出ます。

import csv
with open("out_cp932.csv", newline="", encoding="utf-8") as f:   # cp932のファイルをutf-8で読む
    print(list(csv.reader(f)))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8d in position 11: invalid start byte

position 11 は先頭から11バイト目(id,name\r\n1, の直後、「佐」の1バイト目 0x8D)です。逆に、UTF-8のファイルを cp932 で読むと、エラーにならずに文字化けすることがあります。

with open("out_utf-8.csv", newline="", encoding="cp932") as f:
    print(list(csv.reader(f)))
[['id', 'name'], ['1', '菴占陸']]

エラーが出ないぶん気づきにくいので、読み込んだ直後に数行を表示して確認すると安心です。

対処1:正しい文字コードを指定する(基本)

エラーの 'utf-8' codec の部分が「今の指定」です。日本語のCSVなら、まず utf-8-sig と cp932 を試します。候補を順に試す関数にしておくと便利です。

import csv

def open_csv(path, encodings=("utf-8-sig", "cp932")):
    """候補の文字コードを順に試して開く"""
    for enc in encodings:
        try:
            with open(path, newline="", encoding=enc) as f:
                return enc, list(csv.reader(f))
        except UnicodeDecodeError:
            continue
    raise ValueError(f"{path}: 文字コードを判定できませんでした")

for p in ["out_utf-8.csv", "out_utf-8-sig.csv", "out_cp932.csv"]:
    print(p, open_csv(p))
out_utf-8.csv ('utf-8-sig', [['id', 'name'], ['1', '佐藤']])
out_utf-8-sig.csv ('utf-8-sig', [['id', 'name'], ['1', '佐藤']])
out_cp932.csv ('cp932', [['id', 'name'], ['1', '佐藤']])

UTF-8を先に試すのがポイントです。UTF-8は規則が厳しく、別の文字コードのファイルを誤って読めてしまうことが少ないためです(上で見たとおり、cp932 を先にするとUTF-8のファイルが文字化けしたまま読めてしまいます)。

対処2:errors= で止めずに読む

どうしても読めない数文字だけを置き換えて先に進みたいときは、errors= を指定します。cp932のファイルをあえて utf-8 で読んだ結果です。

errors 読めない部分の扱い 実行結果(2行目)
"strict"(既定) エラーにする UnicodeDecodeError
"replace" � に置き換える ['1', '����']
"ignore" 捨てる ['1', '']
"backslashreplace" \x8d のように残す ['1', '\\x8d\\xb2\\x93\\xa1']

errors= はデータを失う方法なので、正しい文字コードがわからないときの調査用や、多少の欠けを許容できる場合に使います。

対処3:文字コードを推定するライブラリ

charset-normalizer(pip install charset-normalizer)で推定できます。ただし短いファイルは推定を誤ることがあります。

from charset_normalizer import from_path
print(from_path("out_cp932.csv").best().encoding)

「佐藤」1語だけのcp932ファイルでは big5hkscs(中国語の文字コード)と推定されました。同じcp932で20行ほどの日本語を含むファイルでは cp932 と正しく推定されました。推定結果は目安として使い、候補(utf-8-sig / cp932)が決まっているなら対処1の方法が確実です。


区切り文字を変える:TSV・セミコロン

import csv
rows = [["id", "name"], [1, "ペン"]]
with open("items.tsv", "w", newline="", encoding="utf-8") as f:
    csv.writer(f, delimiter="\t").writerows(rows)
print(open("items.tsv", "rb").read())

with open("items.tsv", newline="", encoding="utf-8") as f:
    print(list(csv.reader(f, delimiter="\t")))

data = "id;price\n1;1,5\n"                        # 小数点がカンマの地域でよく使われる形式
print(list(csv.reader(data.splitlines(), delimiter=";")))
b'id\tname\r\n1\t\xe3\x83\x9a\xe3\x83\xb3\r\n'
[['id', 'name'], ['1', 'ペン']]
[['id', 'price'], ['1', '1,5']]

delimiter= に区切り文字を指定するだけで、TSV(タブ区切り)やセミコロン区切りも同じ書き方で扱えます。区切り文字がわからないときは csv.Sniffer で推定できます。

sample = "id|name|qty\n1|ペン|120\n"
dialect = csv.Sniffer().sniff(sample)
print(repr(dialect.delimiter), csv.Sniffer().has_header(sample))
'|' True

カンマ・改行・引用符を含む値とクォート指定

値の中にカンマや改行、" があっても、csvモジュールが自動で " で囲んでくれます。 quoting= を変えると囲み方を指定できます。同じ1行をそれぞれの設定で書き出した結果です。

import csv, io
row = [1, "ペン,黒", '5" 定規', "1行目\n2行目", None, ""]
for name in ["QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_STRINGS", "QUOTE_NOTNULL"]:
    buf = io.StringIO()
    csv.writer(buf, quoting=getattr(csv, name)).writerow(row)
    print(f"{name:17}", repr(buf.getvalue()))
QUOTE_MINIMAL     '1,"ペン,黒","5"" 定規","1行目\n2行目",,\r\n'
QUOTE_ALL         '"1","ペン,黒","5"" 定規","1行目\n2行目","",""\r\n'
QUOTE_NONNUMERIC  '1,"ペン,黒","5"" 定規","1行目\n2行目","",""\r\n'
QUOTE_STRINGS     '1,"ペン,黒","5"" 定規","1行目\n2行目",,""\r\n'
QUOTE_NOTNULL     '"1","ペン,黒","5"" 定規","1行目\n2行目",,""\r\n'
quoting 囲むもの None 空文字 "" 使いどころ
QUOTE_MINIMAL(既定) 必要な値だけ 空 空 ふつうはこれで十分
QUOTE_ALL すべて "" "" 取り込み先が「全項目囲み」を求めるとき
QUOTE_NONNUMERIC 数値以外 "" "" 読み込み時に数値を自動で float にしたいとき
QUOTE_STRINGS(3.12+) 文字列 空 "" None と空文字を区別したいとき
QUOTE_NOTNULL(3.12+) None 以外 空 "" 同上(数値も囲む)
QUOTE_NONE 囲まない - - escapechar が必要

値の中の " は "" と2つ重ねて表します(5" 定規 → "5"" 定規")。書き出したものを csv.reader で読み戻すと、['1', 'ペン,黒', '5" 定規', '1行目\n2行目', '', ''] と元の値に戻りました(None は空文字になります)。QUOTE_STRINGS と QUOTE_NOTNULL は Python 3.12 で追加されたため、3.11で実行すると AttributeError: module 'csv' has no attribute 'QUOTE_STRINGS' になりました。

QUOTE_NONE でカンマを含む値を書くと、エスケープ文字の指定を求められます。

csv.Error: need to escape, but no escapechar set

→ escapechar="\\" を指定すると 1,ペン\,黒 のように書き出されます。

QUOTE_NONNUMERIC を読み込み時に指定すると、囲まれていない値が float になります。

s = '"id","name","qty"\n1,"ペン",120\n'
print(list(csv.reader(io.StringIO(s), quoting=csv.QUOTE_NONNUMERIC)))
[['id', 'name', 'qty'], [1.0, 'ペン', 120.0]]

ヘッダーをスキップする・行番号を取る

import csv
with open("items.csv", newline="", encoding="utf-8") as f:
    reader = csv.reader(f)
    header = next(reader)          # 1行目を取り出してスキップ
    print("header:", header)
    for row in reader:
        print(row)
header: ['id', 'name', 'qty']
['1', 'ペン', '120']
['2', 'ノート', '45']
['3', 'クリップ', '300']

next(reader) で1行目を取り出すと、ループは2行目から始まります。 エラーの場所を知らせたいときは reader.line_num でファイル上の行番号がわかります(DictReader でも使えます。上のファイルでは「ペン」が2行目でした)。


読み込んだ値を数値に変換する

import csv
with open("items.csv", newline="", encoding="utf-8") as f:
    rows = list(csv.DictReader(f))
print(rows[0], type(rows[0]["qty"]))
items = [{"id": int(r["id"]), "name": r["name"], "qty": int(r["qty"])} for r in rows]
print(items[0])
print(sum(i["qty"] for i in items))
{'id': '1', 'name': 'ペン', 'qty': '120'} <class 'str'>
{'id': 1, 'name': 'ペン', 'qty': 120}
465

空欄を int() すると ValueError: invalid literal for int() with base 10: '' になります。 空欄がありうる列は、変換用の関数を用意しておきます。

def to_int(s, default=None):
    return int(s) if s.strip() else default
print(to_int(""), to_int(" 12 "))
None 12

日付の列は datetime.strptime()、金額のように誤差を避けたい列は decimal.Decimal() で変換します。


大きいCSVは1行ずつ処理する

for row in reader: で1行ずつ処理すれば、ファイルが大きくてもメモリはほとんど増えません。 100万行(約17.6MB)のCSVで、qty列の合計を求めたときのメモリのピーク(tracemalloc で計測)を比べました。

読み方 合計 Pythonが確保したメモリのピーク
for row in csv.DictReader(f):(1行ずつ) 24500000 0.2MB
rows = list(csv.DictReader(f))(全部読み込み) 24500000 320.8MB

計測なしで処理時間を測ると、次のとおりでした(Python 3.14.7、実行環境によって変わります)。

方法 時間
csv.reader(リスト) 0.57秒
csv.DictReader(辞書) 1.49秒
pd.read_csv()(pandas 3.0.6) 0.33秒

DictReader は行ごとに辞書を作るぶん reader より時間がかかります。 件数が多く速さが必要なら reader か pandas が向いています。なお、1つの値が非常に長いCSVで _csv.Error: field larger than field limit (131072) が出た場合は、csv.field_size_limit() で上限を上げられます。


pandasとの対応表

集計・結合・並べ替えなど「表として加工する」ならpandasの read_csv / to_csv が便利です。

import pandas as pd
df = pd.read_csv("items.csv")
print(df)
print(df.dtypes)
df.to_csv("items_pd.csv", index=False, encoding="utf-8-sig")

実行結果(pandas 3.0.6):

   id  name  qty
0   1    ペン  120
1   2   ノート   45
2   3  クリップ  300
id      int64
name      str
qty     int64
dtype: object

pandasは数値の列を自動で int64 などに変換します。 pandas 3.0 では文字列の列が str 型として表示されました。to_csv の出力は b'\xef\xbb\xbfid,name,qty\n1,...' で、BOMが付き、行末は \n でした(pandasの行末は既定で実行するOSの改行、この環境ではLinuxの \n)。

やりたいこと csvモジュール pandas
読む csv.reader(f) / csv.DictReader(f) pd.read_csv(p)
書く csv.writer(f).writerows(rows) df.to_csv(p, index=False)
文字コード open(..., encoding="cp932") read_csv(p, encoding="cp932")
区切り文字 delimiter="\t" sep="\t"
ヘッダーなし csv.reader をそのまま使う header=None, names=[...]
先頭の行を飛ばす next(reader) skiprows=1
使う列だけ 自分で取り出す usecols=["id", "qty"]
型を指定 自分で int() など dtype={"id": str}
日付として読む datetime.strptime() parse_dates=["created"]
大きいファイル for row in reader: chunksize=100_000
クォート quoting=csv.QUOTE_ALL quoting=csv.QUOTE_ALL
行番号列を書かない (もともと書かない) index=False
行末 既定 \r\n(lineterminator=) 既定はOSの改行(lineterminator=)

pandasで to_csv するときは index=False を付けると、先頭に行番号の列が入りません。id のような先頭ゼロを残したい列は dtype={"id": str} で文字列として読みます。

csvモジュールとpandasの使い分け

判断ポイント csvモジュール pandas
インストール 不要(標準) 必要
向いている処理 1行ずつの変換・振り分け・書き出し 集計、結合、並べ替え、欠損値の処理
メモリ 1行ずつなら少ない 基本は全体を読み込む(chunksize で分割可)
型 すべて文字列(自分で変換) 自動で推定(意図しない変換に注意)
配布・軽さ スクリプト1つで動く 依存が増える

「読んで、変換して、書く」だけならcsvモジュール、「表として分析・加工する」ならpandasが目安です。


よくある失敗と直し方

症状・エラー 原因 直し方
Windowsで1行おきに空行が入る newline="" がない open(..., newline="")
値の中の改行が変わる 読み込みで newline="" がない 読むときも newline=""
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8d Shift_JIS系のファイル encoding="cp932"
エラーなしで日本語が化ける UTF-8を cp932 で読んだ encoding="utf-8-sig"
KeyError: 'id'('id' になっている) BOM付きを utf-8 で読んだ encoding="utf-8-sig"
Excelで開くと文字化け BOMなしUTF-8で書いた encoding="utf-8-sig" で書く
ValueError: dict contains fields not in fieldnames fieldnames にないキー fieldnames に追加、または extrasaction="ignore"
ValueError: invalid literal for int() 空欄や文字を数値変換 空欄を判定してから変換
計算がおかしい('120' + '45') 値が文字列のまま int() / float() で変換

よくある質問

Q. with open() を使わないといけませんか? A. 使わなくても読み書きはできますが、with を使うと処理が終わったとき(エラー時も含む)に自動でファイルが閉じられます。 閉じ忘れると書き込んだ内容が反映されないことがあるので、with がおすすめです。

Q. ヘッダーがないCSVを辞書で読むには? A. csv.DictReader(f, fieldnames=["id", "name", "qty"]) のように列名を渡します。1行目もデータとして読まれます。

Q. Excelで開く予定があるCSVは、utf-8-sigとcp932のどちらで書けばよいですか? A. 今のExcelで開くなら utf-8-sig がおすすめです。絵文字や一部の記号など、cp932 では書けない文字も扱えます。取り込み先のシステムがShift_JISを指定している場合は cp932 にします。

Q. 文字列でCSVを組み立てる(",".join(row))のではだめですか? A. 値にカンマ・改行・" が含まれると列がずれます。csvモジュールはこれらを自動で " で囲んでくれるので、csv.writer を使うのが確実です。


まとめ

  • CSVは open(p, newline="", encoding=...) で開き、csv.reader / csv.writer に渡すのが基本形
  • 列名で扱うなら DictReader / DictWriter。書くときは writeheader() を忘れずに
  • newline="" がないとWindowsで \r\r\n になり空行が入る。読み込みでも値の中の改行が変わる
  • Excelで開くCSVは utf-8-sig で書く(先頭に EF BB BF)。UTF-8を読むときも utf-8-sig にするとBOMの有無に関係なく読める
  • UnicodeDecodeError は文字コードの不一致。utf-8-sig → cp932 の順に試す
  • カンマや改行を含む値は自動でクォートされる。QUOTE_ALL などで囲み方を指定できる
  • 大きいファイルは1行ずつ、集計・加工はpandasを使い分ける

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PythonでCSVを読み書き|コピペ用テンプレートと文字化け対策」

株式会社RJCでは、CSVの入出力のような身近な処理も、実際のバイト列まで確かめながら仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?