Read while not eof python

How to find out whether a file is at its `eof`?

It’s worth taking a look at the with statement for opening files — it handles closing and exceptions for you nicely, and reads well.

22 Answers 22

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 > 0 while True: chunk = fp.read(n) if chunk == '': break process(chunk) 
for chunk in iter(lambda: fp.read(n), ''): process(chunk) 

@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.

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.

According to the BufferedIOBase doc: «For interactive raw streams (tty/terminal), a short result does not imply that EOF is imminent.»

@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.

The «for-else» design is often overlooked. See: Python Docs «Control Flow in Loop»:

with open('foobar.file', 'rb') as f: for line in f: foo() else: # No more lines to be read from file bar() 

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 .

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.

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:

f.tell() == os.fstat(f.fileno()).st_size 

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.

Читайте также:  Pdf learning php mysql and javascript

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.

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; 

@LeonardoRaele: an empty line would cause readline to return «\n» . It only returns an empty string if the file is actually at EOF.

What if the file doesn’t end in a \n , I guess readline() will add an \n in that case? (to lazy to check atm., but this detail make the API a bit confusing. Would be nice if the doc where clearer)

According to the docs: f.readline() reads a single line from the file; a newline character ( \n ) is left at the end of the string, and is only omitted on the last line of the file if the file doesn’t end in a newline. This makes the return value unambiguous; if f.readline() returns an empty string, the end of the file has been reached, while a blank line is represented by ‘\n’ , a string containing only a single newline.

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.

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.

@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’) .

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):

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.

You can not use 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.

f=open(file_name) for line in f: print line 

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

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

while not EOF(f): line = f.readline() " do something with line" 
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.

Читайте также:  You may use these html

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:

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 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) 

Источник

How to read user input until EOF in python?

I came across this problem in UVa OJ. 272-Text Quotes Well, the problem is quite trivial. But the thing is I am not able to read the input. The input is provided in the form of text lines and end of input is indicated by EOF. In C/C++ this can be done by running a while loop:

How can this be done in python .? I have searched the web but I did not find any satisfactory answer. Note that the input must be read from the console and not from a file.

5 Answers 5

import sys complete_input = sys.stdin.read() 

sys.stdin is a file like object that you can treat like a Python File object.

Help on built-in function read:

read(size=-1, /) method of _io.TextIOWrapper instance Read at most n characters from stream.

Read from underlying buffer until we have n characters or we hit EOF. If n is negative or omitted, read until EOF. 

What signals the input to terminate in this case then? Can u please see the input format given the problem [ link provided in the question]. I am not sure whether this works for this or not. Thanks

You can read input from console till the end of file using sys and os module in python. I have used these methods in online judges like SPOJ several times.

First method (recommened):

from sys import stdin for line in stdin: if line == '': # If empty string is read then stop the loop break process(line) # perform some operation(s) on given string 

Note that there will be an end-line character \n at the end of every line you read. If you want to avoid printing 2 end-line characters while printing line use print(line, end=») .

Second method:

import os # here 0 and 10**6 represents starting point and end point in bytes. lines = os.read(0, 10**6).strip().splitlines() for x in lines: line = x.decode('utf-8') # convert bytes-like object to string print(line) 

This method does not work on all online judges but it is the fastest way to read input from a file or console.

Читайте также:  Python присвоение через запятую

Third method:

while True: line = input() if line == '': break process(line) 

replace input() with raw_input() if you’re still using python 2.

Источник

How to loop until EOF in Python?

I need to loop until I hit the end of a file-like object, but I’m not finding an «obvious way to do it», which makes me suspect I’m overlooking something, well, obvious. 🙂 I have a stream (in this case, it’s a StringIO object, but I’m curious about the general case as well) which stores an unknown number of records in «» format, e.g.:

data = StringIO("\x07\x00\x00\x00foobar\x00\x04\x00\x00\x00baz\x00") 

Now, the only clear way I can imagine to read this is using (what I think of as) an initialized loop, which seems a little un-Pythonic:

len_name = data.read(4) while len_name != "": len_name = struct.unpack(" 

In a C-like language, I'd just stick the read(4) in the while 's test clause, but of course that won't work for Python. Any thoughts on a better way to accomplish this?

6 Answers 6

You can combine iteration through iter() with a sentinel:

for block in iter(lambda: file_obj.read(4), ""): use(block) 

I think I like this one best as well; what it's doing is very clear because there's so little code. Thanks for the help!

Just a reminder to be kind and rewind the file if you've been writing to it, before iterating over it, ie file_obj.seek(0).

Have you seen how to iterate over lines in a text file?

for line in file_obj: use(line) 

You can do the same thing with your own generator:

def read_blocks(file_obj, size): while True: data = file_obj.read(size) if not data: break yield data for block in read_blocks(file_obj, 4): use(block) 

I prefer the already mentioned iterator-based solution to turn this into a for-loop. Another solution written directly is Knuth's "loop-and-a-half"

while 1: len_name = data.read(4) if not len_name: break names.append(data.read(len_name)) 

You can see by comparison how that's easily hoisted into its own generator and used as a for-loop.

In this particular case, I think I like the iter() solution better, but I feel quite foolish for not having thought of this. A well deserved +1 for you. 😉

Wow. Yeah, that iter() solution is nice. Combined with a "lambda :" and depending on closures makes it a bit harder to understand, but sweet none-the-less.

I see, as predicted, that the typical and most popular answer are using very specialized generators to "read 4 bytes at a time". Sometimes generality isn't any harder (and much more rewarding;-), so, I've suggested instead the following very general solution:

import operator def funlooper(afun, *a, **k): wearedone = k.pop('wearedone', operator.not_) while True: data = afun(*a, **k) if wearedone(data): break yield data 

Now your desired loop header is just: for len_name in funlooper(data.read, 4): .

Edit: made much more general by the wearedone idiom since a comment accused my slightly less general previous version (hardcoding the exit test as if not data: ) of having "a hidden dependency", of all things!-)

The usual swiss army knife of looping, itertools , is fine too, of course, as usual:

import itertools as it for len_name in it.takewhile(bool, it.imap(data.read, it.repeat(4))): . 
import itertools as it def loop(pred, fun, *args): return it.takewhile(pred, it.starmap(fun, it.repeat(args))) for len_name in loop(bool, data.read, 4): . 

Источник

Оцените статью