開いているファイルでread()を2回呼び出せないのはなぜですか?


98

私が行っている演習では、read()メソッドを使用して特定のファイルの内容を2回読み取ろうとしています。不思議なことに、2回目に呼び出したときに、ファイルの内容が文字列として返されないようです。

これがコードです

f = f.open()

# get the year
match = re.search(r'Popularity in (\d+)', f.read())

if match:
  print match.group(1)

# get all the names
matches = re.findall(r'<td>(\d+)</td><td>(\w+)</td><td>(\w+)</td>', f.read())

if matches:
  # matches is always None

もちろん、これが最も効率的でも最良の方法でもないことは知っています。これがここでのポイントではありません。ポイントは、なぜ私はread()二度電話をかけることができないのですか?ファイルハンドルをリセットする必要がありますか?またはそれを行うためにファイルを閉じる/再度開きますか?


2
読み取りによってファイルの状態が変化しないという考えはどこで得ましたか?どのリファレンスまたはチュートリアルを使用していますか?
S.Lott、

ファイルを閉じて再度開くと、以下の回答に基づいて機能するはずです。
Anthony

@Shynthriir:システムで他の影響(一時ファイル、incronなど)が発生する可能性があるため、ファイルを閉じて再度開くことは必ずしも良い考えではありません。
Ignacio Vazquez-Abrams

3
私は明白なことを述べるたい:あなたはDID 2回)(コールリードを!

4
W / R / T / S.Lott、そして5年以上:これは本当にPythonのドキュメントにある必要があります。特に不変のデータ/関数型プログラミングでの作業に慣れている場合は特に、ファイルオブジェクトを読み取ると状態が変わると想定する必要があるかどうかは明らかではありません...
Paul Gowder

回答:


155

呼び出しread()はファイル全体を読み取り、読み取りカーソルをファイルの終わりに残します(これ以上読み取るものはありません)。あなたが使用できるときに行の特定の番号を読み取るために探している場合 readline()readlines()または持つ行を繰り返し処理for line in handle:

質問に直接回答するには、ファイルが読み取られread()たら、を使用seek(0)して読み取りカーソルをファイルの先頭に戻します(ドキュメントはこちら)。ファイルが大きくなりすぎないことがわかっている場合read()は、findall式で使用して、出力を変数に保存することもできます。

PS 使い終わったら、ファイルを閉じることを忘れないでください;)


4
+1、はい、不要なファイルI / Oを回避するために、一時変数を読み取ってください。(明示的な)変数の数が少ないためにメモリを節約しているのは誤った経済です。
Nick T

2
@NickT:複数回読み取られる小さなファイルがOSによってキャッシュされるため(少なくともLinux / OSXでは)、2回読み取るための追加のファイルI / Oはありません。メモリに収まらない大きなファイルはキャッシュされませんが、スワッピングを開始するため、それらを変数に読み込みたくありません。したがって、疑問がある場合は、常に複数回読んでください。ファイルが小さいことが確実な場合は、最も優れたプログラムを提供するものを実行してください。
Claude

3
ティアダウンはで自動化できますwith
Cees Timmerman、2016年

30

ええ、上記のように...

私は例を書きます:

>>> a = open('file.txt')
>>> a.read()
#output
>>> a.seek(0)
>>> a.read()
#same output

17

これまでにこの質問に回答した人は誰でも完全に正しいread()です。ファイル内を移動するため、一度呼び出した後は、再度呼び出すことはできません。

私が追加するのは、特定のケースでは、最初に戻ってシークしたり、ファイルを再度開いたりする必要がないことです。ローカル変数に読み込んだテキストを保存して、それを2回使用するか、あなたのプログラムで好きなだけ何度でも:

f = f.open()
text = f.read() # read the file into a local variable
# get the year
match = re.search(r'Popularity in (\d+)', text)
if match:
  print match.group(1)
# get all the names
matches = re.findall(r'<td>(\d+)</td><td>(\w+)</td><td>(\w+)</td>', text)
if matches:
  # matches will now not always be None

1
+1実際には、これはこの演習で提案されたソリューションでした(code.google.com/intl/de-DE/edu/languages/google-python-class/…)。しかし、どういうわけか、文字列を変数に格納することを考えていませんでした。ああ!
ヘルパーメソッド

1
Python3では、pathlibを使用します。from pathlib import Path; text = Path(filename).read_text()オープン、クローズなどを処理します
PaulMcG 2017年


2

開いているすべてのファイルには、関連付けられた位置があります。
read()を実行すると、その位置から読み取ります。たとえばread(10)、新しく開いたファイルから最初の10バイトをread(10)読み取り、次に別の10バイトを読み取ります。 read()引数を指定しないと、ファイルの内容がすべて読み取られ、ファイルの位置がファイルの末尾に残ります。次に電話read()するとき、読むものはありません。

を使用seekして、ファイルの位置を移動できます。または、おそらくあなたの場合、どちらかを実行read()して両方の検索の結果を保持することをお勧めします。


1

read() 消費します。したがって、ファイルをリセットするか、再読み取りする前に先頭にシークすることができます。または、それがタスクに適しread(n)ている場合は、nバイトのみを消費するために使用できます。


1

私はいつも、読み取り方法が暗い路地を歩くようなものだと思っています。少し下がって停止しますが、歩数を数えていなければ、どこまで進んでいるかわかりません。Seekは再配置によってソリューションを提供します。他のオプションは、ファイルに沿った位置を返すT​​ellです。Pythonファイルがapiである可能性があります。読み取りとシークをread_from(position、bytes)に組み合わせて、より単純にすることができます。そうなるまで、このページを読む必要があります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.