It's worth taking a look at the with statement for opening files - it handles closing and exceptions for you nicely, and reads well.
Gareth Latty
Antworten:
68
fp.read() reads up to the end of the file, so after it's successfully finished you know the file is at EOF; there's no need to check. If it cannot reach EOF it will raise an exception.
When reading a file in chunks rather than with read(), you know you've hit EOF when read returns less than the number of bytes you requested. In that case, the following read call will return the empty string (not None). The following loop reads a file in chunks; it will call read at most once too many.
assert n > 0whileTrue:
chunk = fp.read(n)
if chunk == '':
break
process(chunk)
Or, shorter:
for chunk initer(lambda: fp.read(n), ''):
process(chunk)
Yes, you're right. So there is no effective way to check whether eof is reached?
Alcott
1
@Alcott: there's aix's method for ordinary files. When reading in chunks, say with fp.read(n), you'll know you've hit EOF when that returns less than n characters.
Fred Foo
3
Unless you have some reason to process a file in chunks, it's generally more natural to process it line by line, which python provides as files are iterators - so you can just do for line in file: ... and let the for loop deal with it for you.
Gareth Latty
17
According to the BufferedIOBase doc: "For interactive raw streams (tty/terminal), a short result does not imply that EOF is imminent."
Quentin Pradet
4
@larsmans just used this, thanks! Though mine was for a binary stream, I should note here that if chunk == '': only works for literal string streams, if chunk == b'': is needed for binary streams, note the extra b.
There is literally no point to this else:. Not writing it and just having bar() works the same. else only makes a difference if you use break.
Artyer
Someone might read this and care :) I did not know you could iterate over f line-by-line (even in binary mode!). I'm not a fan of else: there's no point to it, it just adds a line and more indented code. Its purpose and behavior is confusing just like finally in try/except.
Staplerfahrer
31
I'd argue that reading from the file is the most reliable way to establish whether it contains more data. It could be a pipe, or another process might be appending data to the file etc.
If you know that's not an issue, you could use something like:
agreed if you call read() and you are at EOF its going to return ''
krystan honour
5
I prefer fh.seek(0, 2); file_size = fh.tell(); fh.seek(0) beforehand and then fh.tell() == file_size later on. Is there an advantage to doing it your way? NOTE: I would certainly suggest caching the size to a variable and not calling os.fstat on every loop.
Bruno Bronosky
2
Note that this won't work if the file is open in text mode: f.tell() gives you the file position in characters and os.fstat(f.fileno()).st_size gives you the file length in bytes. @BrunoBronosky's method will work, though.
rmalouf
14
As python returns empty string on EOF, and not "EOF" itself, you can just check the code for it, written here
f1 = open("sample.txt")
whileTrue:
line = f1.readline()
print line
if ("" == line):
print"file finished"break;
@GreenAsJade, f.read(1) will return the empty string at EOF.
user545424
Huh! And ... is the seek essential, and not just part of whatever? What's it's role?
GreenAsJade
When you use f.read(1) and the file is not at EOF, then you just read one byte, so the f.seek(-1,1) tells the file to move back one byte.
user545424
1
@Chris, as far as I know any non empty string will always evaluate to True. You can check this in the interpreter by running bool('\0').
user545424
9
You can compare the returned value of fp.tell() before and after calling the read method. If they return the same value, fp is at eof.
Furthermore, I don't think your example code actually works. The read method to my knowledge never returns None, but it does return an empty string on eof.
When using f = open(...) rather than with open(...) as f, you also should make sure to call f.close() when you're finished or there can be unintended side effects
Lovethenakedgun
6
I really don't understand why python still doesn't have such a function. I also don't agree to use the following
f.tell() == os.fstat(f.fileno()).st_size
The main reason is f.tell() doesn't likely to work for some special conditions.
The method works for me is like the following. If you have some pseudocode like the following
whilenot EOF(f):
line = f.readline()
" do something with line"
You can replace it with:
lines = iter(f.readlines())
whileTrue:
try:
line = next(lines)
" do something with line"except StopIteration:
break
This method is simple and you don't need to change most of you code.
f = open(filename,'r')
f.seek(-1,2) # go to the file end.
eof = f.tell() # get the end of file location
f.seek(0,0) # go back to file beginningwhile(f.tell() != eof):
<body>
You can use the file methodsseek() and tell() to determine the position of the end of file. Once the position is found, seek back to the file beginning
Can you explain what your solution is doing by editing your post? Posting only code is often not enough.
Noel Widmer
2
Python doesn't have built-in eof detection function but that functionality is available in two ways: f.read(1) will return b'' if there are no more bytes to read. This works for text as well as binary files. The second way is to use f.tell() to see if current seek position is at the end. If you want EOF testing not to change the current file position then you need bit of extra code.
Below are both implementations.
Using tell() method
import os
defis_eof(f):
cur = f.tell() # save current position
f.seek(0, os.SEEK_END)
end = f.tell() # find the size of file
f.seek(cur, os.SEEK_SET)
return cur == end
Using read() method
defis_eof(f):
s = f.read(1)
if s != b'': # restore position
f.seek(-1, os.SEEK_CUR)
return s == b''
You can use tell() method after reaching EOF by calling readlines()
method, like this:
fp=open('file_name','r')
lines=fp.readlines()
eof=fp.tell() # here we store the pointer# indicating the end of the file in eof
fp.seek(0) # we bring the cursor at the begining of the fileif eof != fp.tell(): # we check if the cursor
do_something() # reaches the end of the file
Although I would personally use a with statement to handle opening and closing a file, in the case where you have to read from stdin and need to track an EOF exception, do something like this:
Use a try-catch with EOFError as the exception:
try:
input_lines = ''for line in sys.stdin.readlines():
input_lines += line
except EOFError as e:
print e
Reading a file in batches of BATCH_SIZE lines (the last batch can be shorter):
BATCH_SIZE = 1000# lineswithopen('/path/to/a/file') as fin:
eof = Falsewhile eof isFalse:
# We use an iterator to check later if it was fully realized. This# is a way to know if we reached the EOF.# NOTE: file.tell() can't be used with iterators.
batch_range = iter(range(BATCH_SIZE))
acc = [line for (_, line) inzip(batch_range, fin)]
# DO SOMETHING WITH "acc"# If we still have something to iterate, we have read the whole# file.ifany(batch_range):
eof = True
file=open("filename.txt")
f=file.readlines() #reads all lines from the file
EOF=-1#represents end of file
temp=0for k inrange(len(f)-1,-1,-1):
if temp==0:
if f[k]=="\n":
EOF=k
else:
temp+=1
print("Given file has",EOF,"lines")
file.close()
with
statement for opening files - it handles closing and exceptions for you nicely, and reads well.Antworten:
fp.read()
reads up to the end of the file, so after it's successfully finished you know the file is at EOF; there's no need to check. If it cannot reach EOF it will raise an exception.When reading a file in chunks rather than with
read()
, you know you've hit EOF whenread
returns less than the number of bytes you requested. In that case, the followingread
call will return the empty string (notNone
). The following loop reads a file in chunks; it will callread
at most once too many.assert n > 0 while True: chunk = fp.read(n) if chunk == '': break process(chunk)
Or, shorter:
for chunk in iter(lambda: fp.read(n), ''): process(chunk)
quelle
eof
is reached?fp.read(n)
, you'll know you've hit EOF when that returns less thann
characters.for line in file: ...
and let the for loop deal with it for you.if chunk == '':
only works for literal string streams,if chunk == b'':
is needed for binary streams, note the extra b.The "for-else" design is often overlooked. See: Python Docs "Control Flow in Loop":
Example
with open('foobar.file', 'rb') as f: for line in f: foo() else: # No more lines to be read from file bar()
quelle
else:
. Not writing it and just havingbar()
works the same.else
only makes a difference if you usebreak
.I'd argue that reading from the file is the most reliable way to establish whether it contains more data. It could be a pipe, or another process might be appending data to the file etc.
If you know that's not an issue, you could use something like:
quelle
''
fh.seek(0, 2); file_size = fh.tell(); fh.seek(0)
beforehand and thenfh.tell() == file_size
later on. Is there an advantage to doing it your way? NOTE: I would certainly suggest caching the size to a variable and not callingos.fstat
on every loop.f.tell()
gives you the file position in characters andos.fstat(f.fileno()).st_size
gives you the file length in bytes. @BrunoBronosky's method will work, though.As python returns empty string on EOF, and not "EOF" itself, you can just check the code for it, written here
f1 = open("sample.txt") while True: line = f1.readline() print line if ("" == line): print "file finished" break;
quelle
readline
to return"\n"
. It only returns an empty string if the file is actually at EOF.When doing binary I/O the following method is useful:
while f.read(1): f.seek(-1,1) # whatever
The advantage is that sometimes you are processing a binary stream and do not know in advance how much you will need to read.
quelle
f.read(1)
will return the empty string at EOF.f.read(1)
and the file is not atEOF
, then you just read one byte, so thef.seek(-1,1)
tells the file to move back one byte.bool('\0')
.You can compare the returned value of
fp.tell()
before and after calling theread
method. If they return the same value, fp is at eof.Furthermore, I don't think your example code actually works. The
read
method to my knowledge never returnsNone
, but it does return an empty string on eof.quelle
fp.tell()
, for example, if it is in an iteration state:OSError: telling position disabled by next() call
read returns an empty string when EOF is encountered. Docs are here.
quelle
f=open(file_name) for line in f: print line
quelle
f = open(...)
rather thanwith open(...) as f
, you also should make sure to callf.close()
when you're finished or there can be unintended side effectsI really don't understand why python still doesn't have such a function. I also don't agree to use the following
The main reason is
f.tell()
doesn't likely to work for some special conditions.The method works for me is like the following. If you have some pseudocode like the following
while not EOF(f): line = f.readline() " do something with line"
You can replace it with:
lines = iter(f.readlines()) while True: try: line = next(lines) " do something with line" except StopIteration: break
This method is simple and you don't need to change most of you code.
quelle
If file is opened in non-block mode, returning less bytes than expected does not mean it's at eof, I'd say @NPE's answer is the most reliable way:
quelle
The Python read functions will return an empty string if they reach EOF
quelle
f = open(filename,'r') f.seek(-1,2) # go to the file end. eof = f.tell() # get the end of file location f.seek(0,0) # go back to file beginning while(f.tell() != eof): <body>
You can use the file methods seek() and tell() to determine the position of the end of file. Once the position is found, seek back to the file beginning
quelle
Python doesn't have built-in eof detection function but that functionality is available in two ways:
f.read(1)
will returnb''
if there are no more bytes to read. This works for text as well as binary files. The second way is to usef.tell()
to see if current seek position is at the end. If you want EOF testing not to change the current file position then you need bit of extra code.Below are both implementations.
Using tell() method
import os def is_eof(f): cur = f.tell() # save current position f.seek(0, os.SEEK_END) end = f.tell() # find the size of file f.seek(cur, os.SEEK_SET) return cur == end
Using read() method
def is_eof(f): s = f.read(1) if s != b'': # restore position f.seek(-1, os.SEEK_CUR) return s == b''
How to use this
while not is_eof(my_file): val = my_file.read(10)
Play with this code.
quelle
Here is a way to do this with the Walrus Operator (new in Python 3.8)
f = open("a.txt", "r") while (c := f.read(n)): process(c) f.close()
Useful Python Docs (3.8):
Walrus operator: https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions
Methods of file objects: https://docs.python.org/3/tutorial/inputoutput.html#methods-of-file-objects
quelle
You can use
tell()
method after reachingEOF
by callingreadlines()
method, like this:fp=open('file_name','r') lines=fp.readlines() eof=fp.tell() # here we store the pointer # indicating the end of the file in eof fp.seek(0) # we bring the cursor at the begining of the file if eof != fp.tell(): # we check if the cursor do_something() # reaches the end of the file
quelle
Get the EOF position of the file:
def get_eof_position(file_handle): original_position = file_handle.tell() eof_position = file_handle.seek(0, 2) file_handle.seek(original_position) return eof_position
and compare it with the current position:
get_eof_position == file_handle.tell()
.quelle
Although I would personally use a
with
statement to handle opening and closing a file, in the case where you have to read from stdin and need to track an EOF exception, do something like this:Use a try-catch with
EOFError
as the exception:try: input_lines = '' for line in sys.stdin.readlines(): input_lines += line except EOFError as e: print e
quelle
Reading a file in batches of
BATCH_SIZE
lines (the last batch can be shorter):BATCH_SIZE = 1000 # lines with open('/path/to/a/file') as fin: eof = False while eof is False: # We use an iterator to check later if it was fully realized. This # is a way to know if we reached the EOF. # NOTE: file.tell() can't be used with iterators. batch_range = iter(range(BATCH_SIZE)) acc = [line for (_, line) in zip(batch_range, fin)] # DO SOMETHING WITH "acc" # If we still have something to iterate, we have read the whole # file. if any(batch_range): eof = True
quelle
This code will work for python 3 and above
file=open("filename.txt") f=file.readlines() #reads all lines from the file EOF=-1 #represents end of file temp=0 for k in range(len(f)-1,-1,-1): if temp==0: if f[k]=="\n": EOF=k else: temp+=1 print("Given file has",EOF,"lines") file.close()
quelle
I use this function:
# Returns True if End-Of-File is reached def EOF(f): current_pos = f.tell() file_size = os.fstat(f.fileno()).st_size return current_pos >= file_size
quelle
You can use below code snippet to read line by line, till end of file:
line = obj.readline() while(line != ''): # Do Something line = obj.readline()
quelle