開発言語 Python(その12)

【連載】

にわか管理者のためのLinux運用入門

【第173回】開発言語 Python(その12)

[2019/04/09 12:05]後藤大地 ブックマーク ブックマーク

サーバ/ストレージ

ファイルの読み書き

前回は「The Python Tutorial」を基に、文字列フォーマットについて解説した。The Python Tutorialの次の説明は、ファイルからのデータの読み込み/ファイルへのデータの書き込みについてだ。ファイルの扱いについては、UNIXの基本的なファイルの扱いがそのままPython風になったような作りになっている。open()でファイルを開いてファイルオブジェクトを取得し、ファイルオブジェクトのread()やreadline()で読み込み、write()で書き込みができるといった仕組みだ。

標準入力からの読み込み/標準出力への書き込みでもかなりの処理を行うことができるが、「データとして複数のファイルを指定したい」とか、「出力先を複数にしたい」となってくると、入出力対象としてファイルを扱いたくなる。今回は、ファイルを入出力対象とする際の基本的な仕組みを紹介する。

ファイルの読み込み

次のサンプルはPythonでファイルを読み込むものだ。

daichi@ubuntu1804:~$ cat data.txt 
A 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
B 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
C 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
D 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
E 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
F 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
G 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
H 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
I 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
J 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
K 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
L 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
M 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
N 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
O 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
P 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Q 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
daichi@ubuntu1804:~$ python3
Python 3.6.6 (default, Sep 12 2018, 18:26:19) 
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('data.txt','r')
>>> f.read()
'A 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nC 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nD 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nE 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nF 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nG 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nH 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nI 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nJ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nK 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nL 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nM 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nN 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nO 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nP 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nQ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.closed
False
>>> f.close()
>>> f.closed
True
>>>

このサンプルの処理の本質的な部分は、次の記述だ。

  1. f = open(‘data.txt’,’r’)
  2. f.read()
  3. f.close()


open()は2つの引数を取り、1つ目はファイルパス、2つ目はモードとなっている。「r」なら読み込み、「w」なら書き込み、「a」なら追記、「r+」なら読み書き、「b」ならバイナリファイル、といった具合だ。これらのモードは同時に複数指定することができ、例えば「rb+」と指定すれば「バイナリファイルを読み書き可能なものとして開く」、という指定になる。「b」が指定されていない場合には、データはテキストファイルとして扱われる。

read()は「ファイルの中身を全て持ってくる」という意味になる。read()は引数としてサイズを取ることができ、引数にサイズを指定した場合にはそのサイズまでファイルの中身を取ってくる。上記サンプルではサイズを指定していないので、ファイルの中身が全て読み込まれている。

close()は開いたファイルを閉じる処理だ。Pythonは明示的にclose()しなくても、いずれかのタイミングでガベージコレクタによって自動的にファイルのclose()処理が行われるのだが、それまで不要なリソースが確保され続けることになる。基本的に、不要になったらその場でclose()で閉じるというのがスマートなやり方だ。

1行ずつ読み込む

read()だとデータを丸ごと読み込んでしまうのだが、対象がテキストデータの場合には、まるごとではなく1行ごとにデータを読み込んでほしいことが多い。この場合に使えるのがreadline()だ。readline()では、次のように1行ずつデータを読み込んで返してくれる。

>>> f = open('data.txt','r')
>>> f.readline()
'A 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'B 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'C 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'D 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.closed
False
>>> f.readline()
'E 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'F 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'G 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'H 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'I 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'J 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'K 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'L 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'M 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'N 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'O 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'P 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
'Q 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.readline()
''
>>> f.readline()
''
>>> f.closed
False
>>> f.close()
>>> f.closed
True
>>>

先程のサンプルでは「f.closed」という書き方を使っているが、これはファイルオブジェクトがすでにclose()されたかどうかをチェックするものだ。Pythonだとあまりこの辺りが気になることはないのだが、オープンしたファイルはクローズするものということで、明示的にサンプルに掲載されている。

withを使ったプラクティス

チュートリアルではファイルをオープンして使用する方法として次のように「with as」を使う方法を紹介している。

>>> with open('data.txt','r') as f:
...     f.read()
... 
'A 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nB 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nC 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nD 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nE 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nF 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nG 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nH 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nI 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nJ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nK 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nL 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nM 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nN 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nO 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nP 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\nQ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20\n'
>>> f.closed
True
>>> f.close()
>>> f.closed
True
>>>

サンプルを見てわかるように、この書き方をするとwithを抜けた段階で開いたファイルオブジェクトが自動的にクローズされることがわかる。クローズ処理が自動で行われるほか、途中で例外が発生した場合にもこの方法であればファイルをクローズすることができる。

forとの組み合わせ

Pythonではfor制御構文とファイルオブジェクトを組み合わせることが可能で、次のような書き方をするとファイルオブジェクトから自動的に1行ずつデータが読み込まれて処理が行われる。

>>> f = open('data.txt','r')
>>> i = 1
>>> for v in f:
...     print('{:d} - '.format(i),end='')
...     i += 1
...     print(v,end='')
... 
1 - A 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
2 - B 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
3 - C 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
4 - D 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
5 - E 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
6 - F 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
7 - G 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
8 - H 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
9 - I 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
10 - J 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
11 - K 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
12 - L 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
13 - M 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
14 - N 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
15 - O 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
16 - P 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
17 - Q 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
>>>

「ファイルからデータを1行ずつ読み込んで処理を行う」というのはよくある処理だが、Pythonではそれをこのように簡単に記述することができる。

ファイルへの書き込み

ファイルへの書き込みは次のようにwrite()を使って行えばよい。

>>> f = open('data2.txt','w')
>>> f.write('A 0 1 2 3 4 5 6 7 8 9 10\n')
25
>>> f.write('B 0 1 2 3 4 5 6 7 8 9 10\n')
25
>>> f.write('C 0 1 2 3 4 5 6 7 8 9 10\n')
25
>>> f.write('D 0 1 2 3 4 5 6 7 8 9 10\n')
25
>>> f.write('E 0 1 2 3 4 5 6 7 8 9 10\n')
25
>>> f.close()
>>> f.closed
True
>>> quit()
daichi@ubuntu1804:~$ ls -l data2.txt 
-rw-rw-r-- 1 daichi daichi 125 Apr  8 07:36 data2.txt
daichi@ubuntu1804:~$ cat data2.txt 
A 0 1 2 3 4 5 6 7 8 9 10
B 0 1 2 3 4 5 6 7 8 9 10
C 0 1 2 3 4 5 6 7 8 9 10
D 0 1 2 3 4 5 6 7 8 9 10
E 0 1 2 3 4 5 6 7 8 9 10
daichi@ubuntu1804:~$

また、今回は取り上げていないが、seek()を使うとファイルの中の指し示す先を移動させることができる。基本的にOSが提供しているベーシックな機能はPythonでもそのまま利用できる仕組みになっている。

ファイルの読み書きができるようになると、俄然プログラミング言語感が出てくる。ここまでできるようになれば、後は文字列を解析する方法なんかを調べれば、ちょっとしたテキストデータの加工処理のようなものはコーディングして自動的に処理できるようになってくる。そこまで使えれば、システム運用していく上でかなり強力な”武器”になるはずだ。

【参考資料】
The Python Tutorial

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

一覧はこちら

連載目次

もっと知りたい!こちらもオススメ

なぜ今、統合システムなのか? 押さえておくべき「3つのインパクト」

なぜ今、統合システムなのか? 押さえておくべき「3つのインパクト」

ガートナー ジャパンは10月31日~11月2日、都内で「Gartner Symposium/ITxpo 2017」を開催。11月1日には同社 主席アナリストの青山浩子氏が登壇し「CIOが理解すべき統合システムの3大インパクト」と題する講演を行った。本稿では、講演の内容をダイジェストでお届けする。

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で IT Search+ の人気記事をお届けします

会員登録(無料)

注目の特集/連載
[解説動画] Googleアナリティクス分析&活用講座 - Webサイト改善の正しい考え方
[解説動画] 個人の業務効率化術 - 短時間集中はこうして作る
知りたい! カナコさん 皆で話そうAIのコト
教えてカナコさん! これならわかるAI入門
対話システムをつくろう! Python超入門
Kubernetes入門
AWSで作るクラウドネイティブアプリケーションの基本
PowerShell Core入門
徹底研究! ハイブリッドクラウド
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

ページの先頭に戻る