スポンサーリンク

コードが書ける!数式が書ける!AAが書ける!スタンプが貼れる!

無料の匿名掲示板型SNS「このはちゃんねる

新規会員募集中!

【Python】テキストファイルを読み書きモードで開く(モードr+, r+t)【入門第64回】

192, 2019-09-23

目次

テキストファイルの読み書き

こんにちは、narupoです。

今回から少し高度なファイル入出力についてやっていきます。
今回はテキストファイルを読み書きモードで開く方法を解説します。

テキストファイルの入出力処理を書いていると、テキストファイルを読みながら同じファイルに書き込みもしたい時があります。
そういうときはopen関数のmode引数に文字列r+r+tを指定してテキストファイルを開きます。
r+またはr+tモードで開いたテキストファイルは読み込みと書き込みが両方可能になります。
このモードで得られるファイルオブジェクトのタイプは_io.TextIOWrapperです。
ファイルオブジェクトのメソッドを使うとファイルに読み書きすることが出来ます。

今回は具体的には↓を見ていきます。

  • テキストファイルを読み書きモードで開く
  • ファイルオブジェクトのタイプ
  • テキストファイルの読み込み
  • テキストファイルへの書き込み
  • 同時に読み書きするサンプルプログラム

ほかのファイル入出力についての入門記事は↓をご覧ください。

テキストファイルを読み書きモードで開く

テキストファイルを読み書きモードで開くにはopen関数を↓のように使います。

with open('animals.txt', mode='r+', encoding='utf-8') as fp:
    pass

open関数の第1引数にファイルのパスを指定します。
mode引数にはr+またはr+tを指定します。
encodingにはテキストファイルのエンコーディングを指定します。

r+またはr+tモードは、開こうとするファイルが存在しない場合は例外FileNotFoundErrorを送出します。

try:
    with open('not-found', mode='r+', encoding='utf-8') as fp:
        pass
except FileNotFoundError:
    print('ファイルが見つかりません')

↑のコードの実行結果は↓のようになります。

ファイルが見つかりません

open関数の具体的な使い方については↓の記事をご覧ください。

ファイルオブジェクトのタイプ

r+またはr+tモードで開いたファイルオブジェクトのタイプは_io.TextIOWrapperです。

with open('animals.txt', mode='r+', encoding='utf-8') as fp:
    print(type(fp))

↑のコードの実行結果は↓のようになります。

<class '_io.TextIOWrapper'>

このTextIOWrapperTextIOBaseを継承したクラスです。
さらにTextIOBaseIOBaseを継承しています。
TextIOBaseIOBaseの公式ドキュメントを見ればこのファイルオブジェクトで使えるメソッドを一望できます。

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

↓のような内容のテキストファイルanimals.txtの読み込みをやってみます。

猫
犬
猿

readlinesメソッドを使って行のリストとしてテキストファイルを読み込むには↓のようにします。

with open('animals.txt', mode='r+', encoding='utf-8') as fp:
    lines = fp.readlines()
    print(lines)

↑のコードの実行結果は↓のようになります。

['猫\n', '犬\n', '猿\n']

その他のメソッドの使い方については↓の記事をご覧ください。

テキストファイルへの書き込み

↓のような内容のテキストファイルanimals.txtへの書き込みをやってみます。

猫
犬
猿

r+またはr+tモードで開いたファイルオブジェクトのオフセット位置はファイルの先頭、つまりtellメソッドが0を返す位置にあります。

with open('animals.txt', mode='r+', encoding='utf-8') as fp:
    print(fp.tell())

↑のコードの実行結果は↓のようになります。

0

この状態でファイルに書き込みをするとどうなるのでしょうか?
やってみましょう。

with open('animals.txt', mode='r+', encoding='utf-8') as fp:
    fp.write('ポチ')

↑のコードを実行するとanimals.txtの中身は↓のようになります。

ポチŠ¬
猿

ぎえー!

壊 れ て し ま い ま し た 。

このようにテキストファイルのオフセット位置が先頭の時などに文字列を書き込んだりすると、高い確率でファイルの内容が壊れます。
なぜかというと、テキストファイルはバイナリファイルの一種だと前回お話ししました。
つまりテキストファイルに書かれているデータというものはバイトの列になっているんですね。
で、文字列を書き込んだ場合はエンコーディングされたバイト列が書き込まれています。
このバイトの列の途中を別のデータで書き替えたりすると、データを文字列にデコードすることが出来なくなって文字化けなどを起こしてファイルが壊れます。

たとえば「あ」という文字1つを見てみても、バイト列にした場合は数バイト必要な場合があります。
ほかの漢字などもそうです。ものによっては1バイト~数バイトのバイト数の差があります。
この並びを上書きなどで壊してしまうと文字化けが起こるんですね。

よって、基本的にテキストファイルに変更を加えたい場合は「一括変更」か「追記」に限られます。
ファイルのオフセット位置を変更するにはseekメソッドを使います。

import os

with open('animals.txt', mode='r+', encoding='utf-8') as fp:
    print(fp.tell())
    fp.seek(0, os.SEEK_END)
    print(fp.tell())

seekメソッドの第1引数には第2引数からの相対位置を、第2引数には基点位置を指定します。
os.SEEK_ENDはファイルの末尾を表す定数です。この定数を使うにはosモジュールのインポートが必要です。
↑のコードの実行結果は↓のようになります。

0
15

tellメソッドの返す値はテキストファイルの場合は不明瞭な値ですが、オフセット位置が進んでいるのはわかると思います。
この状態でwriteメソッドを呼び出すとテキストファイルの末尾に追記することが出来ます。

import os

with open('animals.txt', mode='r+', encoding='utf-8') as fp:
    fp.seek(0, os.SEEK_END)
    fp.write('加えられた豚\n')

↑のコードを実行するとanimals.txtの中身は↓のようになります。

猫
犬
猿
加えられた豚

豚が加わっていますね。

その他の書き込み用メソッドについては↓の記事をご覧ください。

同時に読み書きするサンプルプログラム

サンプルプログラムとしてちょっと変わったプログラムをご紹介します。
このプログラムはanimals.txtというテキストファイルに、プログラムを実行するたびに「にゃーん」と追記していくプログラムです。

import os

fname = 'animals.txt'

if not os.path.exists(fname):
    with open(fname, mode='w', encoding='utf-8') as fout:
        fout.write('にゃーん\n')
else:
    with open(fname, mode='r+', encoding='utf-8') as fp:
        line = fp.readline()
        fp.seek(0, os.SEEK_END)
        fp.write(line)

まず↓の所でファイルが存在しなかった場合に「にゃーん」と1行だけ書かれたテキストファイルを新規作成します。

if not os.path.exists(fname):
    with open(fname, mode='w', encoding='utf-8') as fout:
        fout.write('にゃーん\n')

↓の所でファイルの1行目を読み込んで(つまり「にゃーん」を読み込んで)、ファイルのオフセット位置を末尾に移動して行を追記しています。

else:
    with open(fname, mode='r+', encoding='utf-8') as fp:
        line = fp.readline()
        fp.seek(0, os.SEEK_END)
        fp.write(line)

なんて変なプログラムだ

おそろしい

おわりに

今回はテキストファイルの読み書きを通して少しだけランダムアクセスもやってみました。
テキストファイルのランダムアクセスはある意味バイナリファイルよりも難しい気がします。

以上、次回に続きます。

また見てね

関連動画





投稿者名です。64字以内で入力してください。

必要な場合はEメールアドレスを入力してください(全体に公開されます)。

投稿する内容です。

スポンサーリンク

スポンサーリンク

スポンサーリンク

スポンサーリンク