note.nkmk.me

Pythonでファイルの読み込み、書き込み(作成・追記)

Date: 2018-04-24 / tags: Python, ファイル操作
このエントリーをはてなブックマークに追加

Pythonでのファイルの読み書き(入出力)について説明する。ファイルの中身を文字列やリストとして取得したり、ファイル作成、上書き、追記したりする方法など。

  • open(), withによるファイル読み書き(入出力)
    • エンコード指定: 引数encoding
  • テキストファイルの読み込み
    • 読み込み用でファイルオープン: 引数mode=r
    • ファイル全体を文字列として読み込み: read()
    • ファイル全体をリストとして読み込み: readlines()
    • ファイルを一行ずつ読み込み: readline()
  • テキストファイルの書き込み(新規作成・上書き)
    • 書き込み用でファイルオープン: 引数mode=w
    • 文字列を書き込み: write()
    • リストを書き込み: writelines()
  • ファイルが存在しない場合のみ書き込み(新規作成のみ)
    • 新規作成専用でファイルオープン: 引数mode=x
    • ファイルの存在を確認してからオープン
  • テキストファイルの書き込み(追記・挿入)
    • 末尾に追記
    • 先頭、途中に挿入
  • バイナリファイルの読み書き
スポンサーリンク

open, withによるファイル読み書き(入出力)

読み込み・書き込みいずれの場合も組み込み関数open()でファイルを開く。

第一引数にパスの文字列を指定するとそのパスが示すファイルオブジェクトが開かれる。読み書きの指定またはテキストファイルかバイナリファイルかの指定などは引数modeを使う(後述)。

テキストファイルの場合はio.TextIOWrapper型として読み込まれれる。

path = 'data/src/test.txt'

f = open(path)

print(type(f))
# <class '_io.TextIOWrapper'>

f.close()

上の例のようにopen()したファイルオブジェクトはclose()メソッドでクローズする必要がある。

withブロックを使うとブロックの終了時に自動的にクローズされる。閉じ忘れがなくなるので便利。

with open(path) as f:
    print(type(f))
# <class '_io.TextIOWrapper'>

エンコーディング指定: 引数encoding

テキストファイル読み込み時のデコード、テキストファイル書き込み時のエンコードで使われるエンコーディングはopen()の引数encodingで指定する。

テキストファイルの読み込み

読み込み用でファイルオープン: mode='r'

open()の引数mode'r'とすると読み込み用としてファイルが開かれる。引数modeのデフォルト値は'r'なので、省略してもOK。

mode='r'では第一引数に存在しないパスを指定するとエラー(FileNotFoundError例外)となる。

# with open('data/src/test_error.txt') as f:
#     print(type(f))
# FileNotFoundError: [Errno 2] No such file or directory: 'data/src/test_error.txt'

ファイル全体を文字列として読み込み: read()

ファイルオブジェクトのread()メソッドを使うと、開いたファイル全体を文字列として取得できる。

with open(path) as f:
    s = f.read()
    print(type(s))
    print(s)
# <class 'str'>
# line 1
# line 2
# line 3

ファイルオブジェクトはwithブロックの終了時にクローズされるが、当然ながら、代入した変数はwithブロックの外(ファイルオブジェクトをクローズした後)でも使える。

with open(path) as f:
    s = f.read()

print(s)
# line 1
# line 2
# line 3

ファイル全体をリストとして読み込み: readlines()

ファイルオブジェクトのreadlines()メソッドを使うと、開いたファイル全体を行ごとに分割したリストとして取得できる。改行コード\nを含んだ文字列が要素となる。

with open(path) as f:
    l = f.readlines()
    print(type(l))
    print(l)
# <class 'list'>
# ['line 1\n', 'line 2\n', 'line 3']

改行コードを削除したい場合はリスト内包表記を使って各要素でstrip()を呼べばOK。

with open(path) as f:
    l_strip = [s.strip() for s in f.readlines()]
    print(l_strip)
# ['line 1', 'line 2', 'line 3']

リストのインデックス指定[]をすることで、任意の行の文字列(改行コード込み)を取得できる。

with open(path) as f:
    l = f.readlines()
    print(l[1])
# line 2
#

ファイルを一行ずつ読み込み: readline()

ファイルオブジェクトをそのままfor文で回すとファイルの先頭から一行ずつ文字列として取得できる。

with open(path) as f:
    for s_line in f:
        print(s_line)
# line 1
#
# line 2
#
# line 3
#

ファイルオブジェクトのreadline()メソッドでも一行ずつ取得できる。

with open(path) as f:
    s_line = f.readline()
    print(s_line)
# line 1
#

readline()メソッドで読んでいくと、最後(EOF)には空文字列''が返される。

with open(path) as f:
    while True:
        s_line = f.readline()
        print(s_line)
        if not s_line:
            break
# line 1
#
# line 2
#
# line 3
#

いずれの場合も行末の改行コードを含む文字列が取得できる。

テキストファイルの書き込み(新規作成・上書き)

書き込み用でファイルオープン: mode='w'

open()の引数mode'w'とすると書き込み用としてファイルが開かれる。

ファイルが存在しなければ新規作成、存在していれば上書き(既存の内容は削除)で保存される。追記・挿入については後述。

path_w = 'data/src/test_w.txt'

s = 'New file'

with open(path_w, mode='w') as f:
    f.write(s)

with open(path_w) as f:
    print(f.read())
# New file

存在しないファイルは新規作成されるが、その直上までのディレクトリ(フォルダ)は存在していなければエラー(FileNotFoundError例外)となる。

# with open('data/src/new_dir/test_w.txt', mode='w') as f:
#     f.write(s)
# FileNotFoundError: [Errno 2] No such file or directory: 'data/src/new_dir/test_w.txt'

新しいディレクトリにファイルを新規作成したい場合は以下の記事を参照。

文字列を書き込み: write()

ファイルオブジェクトのwrite()メソッドを使うと文字列を書き込むことができる。

s = 'New file'

with open(path_w, mode='w') as f:
    f.write(s)

with open(path_w) as f:
    print(f.read())
# New file

改行を含む文字列もそのまま書き込まれる。

s = 'New line 1\nNew line 2\nNew line 3'

with open(path_w, mode='w') as f:
    f.write(s)

with open(path_w) as f:
    print(f.read())
# New line 1
# New line 2
# New line 3

文字列の改行については以下の記事も参照。

write()の引数には文字列のみ指定可能。それ以外の型だとエラー(TypeError例外)となる。

整数型intや浮動小数点型floatなどの数値や他の型を書き込みたい場合はstr()で文字列に変換してからwrite()に渡す。

リストを書き込み: writelines()

ファイルオブジェクトのwritelines()メソッドを使うとリストを書き込むことができる。

l = ['One', 'Two', 'Three']

with open(path_w, mode='w') as f:
    f.writelines(l)

with open(path_w) as f:
    print(f.read())
# OneTwoThree

writelines()では改行コードは挿入されず、要素がそのまま連結されて書き込まれる。

リストの要素ごとに改行して書き込みたい場合は、改行コードとjoin()メソッドで改行込みの文字列を作成し、write()メソッドで書き込む。

with open(path_w, mode='w') as f:
    f.write('\n'.join(l))

with open(path_w) as f:
    print(f.read())
# One
# Two
# Three

writelines()の引数に指定できるのは文字列を要素とするリストのみ。

整数型intや浮動小数点型floatなどの数値や他の型を要素とするリストを書き込みたい場合は文字列のリストに変換する必要がある。以下の記事を参照。

ファイルが存在しない場合のみ書き込み(新規作成のみ)

上述のように、引数mode='w'では、ファイルが存在しなければ新規作成、存在していれば上書き(既存の内容は削除)となり、誤って既存のファイルを指定しまった場合は内容が上書きされてしまう。

ファイルが存在しない場合のみ書き込み、つまり、新規作成のみで上書きは禁止するには以下の二つの方法がある。

新規作成専用でファイルオープン: mode='x'

open()の引数mode'x'とすると、ファイルが存在する場合にはエラー(FileExistsError)となり、ファイルが存在しない場合のみファイルが書き込み用として開かれ保存(新規作成)される。

バージョン3.3で追加された。

# with open(path_w, mode='x') as f:
#     f.write(s)
# FileExistsError: [Errno 17] File exists: 'data/src/test_w.txt'

try, exceptで例外処理をすれば、ファイルが存在しない場合は新規作成、ファイルが存在している場合は何もしないという処理が可能。

try:
    with open(path_w, mode='x') as f:
        f.write(s)
except FileExistsError:
    pass

ファイルの存在を確認してからオープン

標準ライブラリのosモジュールのos.path.isfile()でファイルの存在確認ができる。

これを利用してファイルが存在しない場合のみopen()で書き込み処理を行うことが可能。

import os

if not os.path.isfile(path_w):
    with open(path_w, mode='w') as f:
        f.write(s)

ファイルの存在確認についての詳細は以下の記事を参照。

テキストファイルの追記・挿入

末尾に追記: mode='a'

open()の引数mode'a'とすると追記モードでファイルが開かれる。

write(), writelines()を使うと既存のファイルの末尾に追記できる。

with open(path_w, mode='a') as f:
    f.write('Four')

with open(path_w) as f:
    print(f.read())
# One
# Two
# ThreeFour

最終行を追加したい場合は改行コードも含めて追記する。

with open(path_w, mode='a') as f:
    f.write('\nFour')

with open(path_w) as f:
    print(f.read())
# One
# Two
# ThreeFour
# Four

なお、存在しないファイルに対してはmode='w'と同じくファイルが新規作成される。

先頭、途中に挿入

mode='r+'

open()の引数mode'r+'とすると、読み書き用でファイルが開かれる。

write(), writelines()を使うと既存のファイルの先頭に書き込まれるが、挿入ではなく上書きとなる。

with open(path_w, mode='r+') as f:
    f.write('123456')

with open(path_w) as f:
    print(f.read())
# 123456o
# ThreeFour
# Four

ファイルオブジェクトのメソッドseek()で位置を移動して書き込むことも可能だが、行単位ではなく文字単位で指定する必要がある。

with open(path_w, mode='r+') as f:
    f.seek(3)
    f.write('-')

with open(path_w) as f:
    print(f.read())
# 123-56o
# ThreeFour
# Four

readlines(), insert()を使う

ファイルオブジェクトのメソッドreadlines()、リストオブジェクトのメソッドinsert()を使うと、先頭の行や途中の行に新たな文字列を挿入できる。

readlines()でファイルをリストとして読み込んで、insert()で要素を挿入した後にwritelines()で書き込む。

insert()の第一引数で挿入する行数を指定できる。

with open(path_w) as f:
    l = f.readlines()

l.insert(0, 'FIRST\n')

with open(path_w, mode='w') as f:
    f.writelines(l)

with open(path_w) as f:
    print(f.read())
# FIRST
# 123-56o
# ThreeFour
# Four

リストへの要素の追加・挿入については以下の記事を参照。

リストの要素を削除すると行の削除になる。

バイナリファイルの読み書き

これまで説明したmodeの末尾にbをつけるとバイナリファイルとしての読み書きとなる。

例えばmode='rb'はバイナリファイルの読み込み、moode='ab'はバイナリファイルの末尾に追記となる。

テキストファイルと同様、バイナリファイルでもファイルオブジェクトのメソッドとしてread(), readline(), readlines(), write(), writelinesが使える。

バイナリファイルの編集のほか、Webサイトからダウンロードした画像を保存する際などにも使う。

画像ファイルを開いて処理して保存する場合は、PillowやOpenCVなどのライブラリを使う。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事