DBS
DBS

Reputation: 1147

Python: Using the open and read functions

I'm following an exercise in the book Learn Python the Hard Way. In the following code example, I'm opening, truncating and then writing to a file. When I try to use print target.read() without another repetitive target = open(filename) statement, I get an error message stating that it cannot list the contents of the script I'm currently working on because it's not open.

I'm wondering why do I need the repetitive target = open(filename) statement if I opened the file previously using the target = open(filename, 'w') statement.

from sys import argv

script, filename = argv

print "We're going to erase %r." % filename
print "If you don't want that, hit CTRL-C (^C)."
print "If you don't want that, hit RETURN."

raw_input("?")

print "Opening the file..."
target = open(filename, 'w')

print "Truncating the file.  Goodbye!"
target.truncate()

print "Now I'm going to ask you for three lines."

line1 = raw_input("line 1: ")
line2 = raw_input("line 2: ")
line3 = raw_input("line 3: ")

target.write(line1, "\n", line2, "\n", line3)

target = open(filename)
print target.read()

print "And finally, we close it."
target.close()

Upvotes: 1

Views: 173

Answers (2)

Patrick Maupin
Patrick Maupin

Reputation: 8137

EDIT 1 adds more information on file pointer operations.

The 'w' mode you used is for write-only.

To open a file for read/write access, you can use a file mode of 'r+' or 'rb+', but even if you do this, you will still have to rewind the file pointer to the start of the file using seek to read it after you write it.

f = open('filename', 'rb+')

The file has an associated file pointer (in the program's memory, not in the file itself) that defines where the next file operation will take place. If you're not careful, you can easily overwrite parts of the file you did not mean to.

To find out what the current pointer is, you can use the tell method of the file:

print(f.tell())

To change the current file pointer, you can use the seek method:

f.seek(0)

The seek method has an optional second parameter that lets you seek relative to the end of the file or relative to the current file pointer. By default, it seeks to an absolute position. Seeking to the end of the file is useful if you want to read some stuff from the file and then append to it:

f.seek(0, 2)  # Seeks past everything in the file

If you only want to append to a file without reading anything in it first, you can open it in append mode ('a' or 'ab'). This will open the file and seek to the end and be ready for writing. Using any other mode besides append will automatically seek to the beginning of the file when you open it.

If you have opened the file in text mode ('r+' rather than 'rb+') you can only seek to the beginning of the file. (Text mode is used to be able to support line endings from different operating systems on input. Opinions vary, but I think it is more trouble than it is worth, because it hides what is going on, and it is extremely easy to deal with different line endings from pure Python code.)

Upvotes: 3

MattDMo
MattDMo

Reputation: 102862

This is terrible code to begin with, because it teaches you all sorts of bad habits, and is outdated to boot. When dealing with file objects, use the with statement and a context manager:

with open(filename, "w") as target:
    print "Truncating the file.  Goodbye!"
    target.truncate()

    print "Now I'm going to ask you for three lines."

    line1 = raw_input("line 1: ")
    line2 = raw_input("line 2: ")
    line3 = raw_input("line 3: ")

    target.write(line1, "\n", line2, "\n", line3)

# now we're out of the `with` block, and `target` has 
# been closed (and saved) automatically

# next block
with open(filename) as target:
    print target.read()

# and we're outside the block again, and `target` has
# been closed again, without having to call `.close()`
# explicitly. Isn't that easier to understand?

File objects get automatically closed (any any output written to them flushed to disk and saved before closure) when you exit the with block.

In the original code, target.close() was not called after .write(), but calling open() again on the same file with the same file handler name had the same effect. This is not intuitive, and is one reason why the Zen of Python (type import this into your Python interpreter) states "Explicit is better than implicit." While file closure is implicit in a with block, the very definition of that block says that the file will be closed when it ends.

Upvotes: 3

Related Questions