I am having a great time trying to figure out why there doesn't need to be a closing attribute for this few lines of code I wrote:
from sys import argv
from os.path import exists
script, from_file, to_file = argv
file_content = open(from_file).read()
new_file = open(to_file, 'w').write(file_content)
new_file.close()
file_content.close()
I read some things and other people's posts about this, but their scripts were a lot more complicated than what I'm currently learning, so I couldn't figure out why.
I am doing Learning Python the Hard Way and would appreciate any help.
file_content is a string variable, which contains contents of the file -- it has no relation to the file. The file descriptor you open with open(from_file) will be closed automatically: file sessions are closed after the file-objects exit the scope (in this case, immediately after .read()).
open(...) returns a reference to a file object, calling read on that reads the file returning a string object, calling write writes to it returning None, neither of which have a close attribute.
>>> help(open)
Help on built-in function open in module __builtin__:
open(...)
open(name[, mode[, buffering]]) -> file object
Open a file using the file() type, returns a file object. This is the
preferred way to open a file.
>>> a = open('a', 'w')
>>> help(a.read)
read(...)
read([size]) -> read at most size bytes, returned as a string.
If the size argument is negative or omitted, read until EOF is reached.
Notice that when in non-blocking mode, less data than what was requested
may be returned, even if no size parameter was given.
>>> help(a.write)
Help on built-in function write:
write(...)
write(str) -> None. Write string str to file.
Note that due to buffering, flush() or close() may be needed before
the file on disk reflects the data written.
Theres a couple ways of remedying this:
>>> file = open(from_file)
>>> content = file.read()
>>> file.close()
or with python >= 2.5
>>> with open(from_file) as f:
... content = f.read()
The with will make sure the file is closed.
When you do file_content = open(from_file).read(), you set file_content to the contents of the file (as read by read). You can't close this string. You need to save the file object separately from its contents, something like:
theFile = open(from_file)
file_content = theFile.read()
# do whatever you need to do
theFile.close()
You have a similar problem with new_file. You should separate the open(to_file) call from the write.
Related
I'm a total beginner in Python. I've been trying to shorten the #1 version (which works fine) to a cleaner code and I thought I could just squeeze it into a one-liner. Why doesn't the #2 work?
I'm getting the "NoneType" object has no attribute 'seek' when I try to run it.
from sys import argv
script, filename = argv
# 1
open_file = open(filename, 'w+')
open_file.write("Hello world!")
open_file.seek(0)
print open_file.read()
# 2
open_file = open(filename, 'w+').write("Hello world!").seek(0).read()
print open_file
I have tried numerous ways but I still can't get it to work.
Thanks a lot!
From the documentation:
write(b):
Write the given bytes-like object, b, to the underlying raw stream, and return the number of bytes written
So, it returns the number of bytes written, not a file object, so you cannot chain another call after the write(). Note you also cannot chain seek() as that returns an offset into the file.
The reason why a one-liner is not working, is because .write() does not return back the original file descriptor. Instead, write() returns the number of characters/bytes (depending on the opened file mode) that have been written.
Unfortunatelly I don't think there's a way to do what you want in one go, that would not sacrifice readability. What you could do is wrap your code into a function, or write your own file-like object that would immediatelly seek after write.
For writing,
with open(filename, 'w+') as f: f.write("Hello world!")
and to print content
with open(filename, 'r+') as f: print(f.read())
works for me! Nonetype error is because of no return type as pointed out by others.
You are getting NoneType because file.write function return None. Or in this case int (How many bytes it has write on the file)
You must close the file before you open again it. open_file.close()
Going through Zed Shaw's book Exercise 17 [about copying one file to another] where he reduces his these two lines of code
in_file = open(from_file)
indata = in_file.read()
into one as :
indata = open(from_file).read()
there's also a piece of code where he writes
out_file = open(to_file, 'w')
out_file.write(indata)
So I was reducing this into one line same as above :
out_file = open(to_file, 'w').write(indata)
This seems to work fine but when I close the out_file there's an error as:
Traceback (most recent call last):
File "filesCopy.py", line 27, in <module>
out_file.close()
AttributeError: 'int' object has no attribute 'close'
I am unable to grasp what is going on and how close() is working here?
The two are not equivalent. If you write out_file = open(to_file, 'w').write(indata), you have implicitly written:
# equivalent to second code sample
temp = open(to_file, 'w')
out_file = temp.write(indata)
Now as we can see in the documentation of write():
f.write(string) writes the contents of string to the file, returning the number of characters written.
So it returns an integer. So in your second sample out_file is not a file handler, but an integer. Further in the code, you somewhere aim to close the out_file file handler with out_file.close(). But since out_file is no longer a file handler, it thus makes no sense to call close on this.
Nevertheless, by using a context, you do no longer need to perform a .close() yourself, so more elegantly is probably:
with open(to_file, 'w') as out_file:
out_file.write(indata)
The reduction in the book itself is allowed (well at least semantically, it is better to use context manager), since the author probably never closes the file handle explicitly.
Following is usually better approach, both for reading & writing:
with open("myfile.txt", "w") as f:
# do something with f
There is no need to close f with this code.
With code val = open(to_file, 'w').write(indata) "val" will be return value of write function, not open function.
The write method returns the number of characters written in your file which is an integer not a file object and therefore doesn't have a close method.
In [6]: a = open('test', 'w')
In [7]: t = a.write('ssss')
In [8]: t
Out[8]: 4
Also, calling the I/O methods directly on open() is recommended only if you don't want to have any further interaction with the file. Besides, the most proper way to deal with file objects is to use a with statement that closes the file automatically at the end of the block and there's no need to call the close() manually.
with open('filename', 'w') as f:
# do something
The read() function reads the file and then returns the file content, so when you assign indata to read() it's assigning the returned file content. The difference is that the write() function returns the number of characters written, therefore your outdata is now an int object.
Read more about it here: https://docs.python.org/3.6/tutorial/inputoutput.html
Therefore, you cannot combine the write() function into one line and expect to have a referenced file object to close after, and that's disastrous.
The preferred way is to use the with block. Refer to #Willem's answer for more details.
The author "Zed" has already clarified when you will read the page 64 from that book. Please read below:
When I try to make this script shorter, I get an error when I close the files at the end.
You probably did something like this, indata = open(from_file).read(), which means you don’t need to then do in_file.close() when you reach the end of the script. It should already be closed by Python once that one line runs.
Started Python a week ago and I have some questions to ask about reading and writing to the same files. I've gone through some tutorials online but I am still confused about it. I can understand simple read and write files.
openFile = open("filepath", "r")
readFile = openFile.read()
print readFile
openFile = open("filepath", "a")
appendFile = openFile.write("\nTest 123")
openFile.close()
But, if I try the following I get a bunch of unknown text in the text file I am writing to. Can anyone explain why I am getting such errors and why I cannot use the same openFile object the way shown below.
# I get an error when I use the codes below:
openFile = open("filepath", "r+")
writeFile = openFile.write("Test abc")
readFile = openFile.read()
print readFile
openFile.close()
I will try to clarify my problems. In the example above, openFile is the object used to open file. I have no problems if I want write to it the first time. If I want to use the same openFile to read files or append something to it. It doesn't happen or an error is given. I have to declare the same/different open file object before I can perform another read/write action to the same file.
#I have no problems if I do this:
openFile = open("filepath", "r+")
writeFile = openFile.write("Test abc")
openFile2 = open("filepath", "r+")
readFile = openFile2.read()
print readFile
openFile.close()
I will be grateful if anyone can tell me what I did wrong here or is it just a Pythong thing. I am using Python 2.7. Thanks!
Updated Response:
This seems like a bug specific to Windows - http://bugs.python.org/issue1521491.
Quoting from the workaround explained at http://mail.python.org/pipermail/python-bugs-list/2005-August/029886.html
the effect of mixing reads with writes on a file open for update is
entirely undefined unless a file-positioning operation occurs between
them (for example, a seek()). I can't guess what
you expect to happen, but seems most likely that what you
intend could be obtained reliably by inserting
fp.seek(fp.tell())
between read() and your write().
My original response demonstrates how reading/writing on the same file opened for appending works. It is apparently not true if you are using Windows.
Original Response:
In 'r+' mode, using write method will write the string object to the file based on where the pointer is. In your case, it will append the string "Test abc" to the start of the file. See an example below:
>>> f=open("a","r+")
>>> f.read()
'Test abc\nfasdfafasdfa\nsdfgsd\n'
>>> f.write("foooooooooooooo")
>>> f.close()
>>> f=open("a","r+")
>>> f.read()
'Test abc\nfasdfafasdfa\nsdfgsd\nfoooooooooooooo'
The string "foooooooooooooo" got appended at the end of the file since the pointer was already at the end of the file.
Are you on a system that differentiates between binary and text files? You might want to use 'rb+' as a mode in that case.
Append 'b' to the mode to open the file in binary mode, on systems
that differentiate between binary and text files; on systems that
don’t have this distinction, adding the 'b' has no effect.
http://docs.python.org/2/library/functions.html#open
Every open file has an implicit pointer which indicates where data will be read and written. Normally this defaults to the start of the file, but if you use a mode of a (append) then it defaults to the end of the file. It's also worth noting that the w mode will truncate your file (i.e. delete all the contents) even if you add + to the mode.
Whenever you read or write N characters, the read/write pointer will move forward that amount within the file. I find it helps to think of this like an old cassette tape, if you remember those. So, if you executed the following code:
fd = open("testfile.txt", "w+")
fd.write("This is a test file.\n")
fd.close()
fd = open("testfile.txt", "r+")
print fd.read(4)
fd.write(" IS")
fd.close()
... It should end up printing This and then leaving the file content as This IS a test file.. This is because the initial read(4) returns the first 4 characters of the file, because the pointer is at the start of the file. It leaves the pointer at the space character just after This, so the following write(" IS") overwrites the next three characters with a space (the same as is already there) followed by IS, replacing the existing is.
You can use the seek() method of the file to jump to a specific point. After the example above, if you executed the following:
fd = open("testfile.txt", "r+")
fd.seek(10)
fd.write("TEST")
fd.close()
... Then you'll find that the file now contains This IS a TEST file..
All this applies on Unix systems, and you can test those examples to make sure. However, I've had problems mixing read() and write() on Windows systems. For example, when I execute that first example on my Windows machine then it correctly prints This, but when I check the file afterwards the write() has been completely ignored. However, the second example (using seek()) seems to work fine on Windows.
In summary, if you want to read/write from the middle of a file in Windows I'd suggest always using an explicit seek() instead of relying on the position of the read/write pointer. If you're doing only reads or only writes then it's pretty safe.
One final point - if you're specifying paths on Windows as literal strings, remember to escape your backslashes:
fd = open("C:\\Users\\johndoe\\Desktop\\testfile.txt", "r+")
Or you can use raw strings by putting an r at the start:
fd = open(r"C:\Users\johndoe\Desktop\testfile.txt", "r+")
Or the most portable option is to use os.path.join():
fd = open(os.path.join("C:\\", "Users", "johndoe", "Desktop", "testfile.txt"), "r+")
You can find more information about file IO in the official Python docs.
Reading and Writing happens where the current file pointer is and it advances with each read/write.
In your particular case, writing to the openFile, causes the file-pointer to point to the end of file. Trying to read from the end would result EOF.
You need to reset the file pointer, to point to the beginning of the file before through seek(0) before reading from it
You can read, modify and save to the same file in python but you have actually to replace the whole content in file, and to call before updating file content:
# set the pointer to the beginning of the file in order to rewrite the content
edit_file.seek(0)
I needed a function to go through all subdirectories of folder and edit content of the files based on some criteria, if it helps:
new_file_content = ""
for directories, subdirectories, files in os.walk(folder_path):
for file_name in files:
file_path = os.path.join(directories, file_name)
# open file for reading and writing
with io.open(file_path, "r+", encoding="utf-8") as edit_file:
for current_line in edit_file:
if condition in current_line:
# update current line
current_line = current_line.replace('john', 'jack')
new_file_content += current_line
# set the pointer to the beginning of the file in order to rewrite the content
edit_file.seek(0)
# delete actual file content
edit_file.truncate()
# rewrite updated file content
edit_file.write(new_file_content)
# empties new content in order to set for next iteration
new_file_content = ""
edit_file.close()
I am bassicly trying to read a number from a file, convert it to an int, add one to it, then rewrite the new number back to the file. However every time I run this code when i open the .txt file it is blank. Any help would be appreciated thanks! I am a python newb.
f=open('commentcount.txt','r')
counts = f.readline()
f.close
counts1 = int(counts)
counts1 = counts1 + 1
print(counts1)
f2 = open('commentcount.txt','w') <---(the file overwriting seems to happen here?)
f2.write(str(counts1))
Having empty files
This issue is caused by you failing to close the file descriptor. You have f.close but it should be f.close() (a function call). And you also need an f2.close() in the end.
Without the close it takes a while until the contents of the buffer arrive in the file. And it is a good practice to close file descriptors as soon as they are not used.
As a side note, you can use the following syntactic sugar to ensure that the file descriptor is closed as soon as possible:
with open(file, mode) as f:
do_something_with(f)
Now, regarding the overwriting part:
Writing to file without overwriting the previous content.
Short answer: You don't open the file in the proper mode. Use the append mode ("a").
Long answer:
It is the intended behavior. Read the following:
>>> help(open)
Help on built-in function open in module __builtin__:
open(...)
open(name[, mode[, buffering]]) -> file object
Open a file using the file() type, returns a file object. This is the
preferred way to open a file. See file.__doc__ for further information.
>>> print file.__doc__
file(name[, mode[, buffering]]) -> file object
Open a file. The mode can be 'r', 'w' or 'a' for reading (default),
writing or appending. The file will be created if it doesn't exist
when opened for writing or appending; it will be truncated when
opened for writing. Add a 'b' to the mode for binary files.
Add a '+' to the mode to allow simultaneous reading and writing.
If the buffering argument is given, 0 means unbuffered, 1 means line
buffered, and larger numbers specify the buffer size. The preferred way
to open a file is with the builtin open() function.
Add a 'U' to mode to open the file for input with universal newline
support. Any line ending in the input file will be seen as a '\n'
in Python. Also, a file so opened gains the attribute 'newlines';
the value for this attribute is one of None (no newline read yet),
'\r', '\n', '\r\n' or a tuple containing all the newline types seen.
So, reading the manuals shows that if you want the content to be kept you should open in append mode:
open(file, "a")
you should use the with statement. this assume that the file descriptor is closed no matter what:
with open('file', 'r') as fd:
value = int(fd.read())
with open('file', 'w') as fd:
fd.write(value + 1)
You never close the file. If you don't properly close the file the OS might not commit any changes. To avoid this problem it is recommended that you use Python's with statement to open files as it it will close them for you once you are done with the file.
with open('my_file.txt', a) as f:
do_stuff()
python open file paramters:
w:
Opens a file for writing only. Overwrites the file if the file exists.
If the file does not exist, creates a new file for writing.
You can use a (append):
Opens a file for appending. The file pointer is at the end of the file
if the file exists. That is, the file is in the append mode. If the
file does not exist, it creates a new file for writing.
for more information you can read here
One more advice is to use with:
with open("x.txt","a") as f:
data = f.read()
............
For example:
with open('c:\commentcount.txt','r') as fp:
counts = fp.readline()
counts = str(int(counts) + 1)
with open('c:\commentcount.txt','w') as fp:
fp.write(counts)
Note this will work only if you have a file name commentcount and it has a int at the first line since r does not create new file, also it will be only one counter...it won't append a new number.
I am having a great time trying to figure out why there doesn't need to be a closing attribute for this few lines of code I wrote:
from sys import argv
from os.path import exists
script, from_file, to_file = argv
file_content = open(from_file).read()
new_file = open(to_file, 'w').write(file_content)
new_file.close()
file_content.close()
I read some things and other people's posts about this, but their scripts were a lot more complicated than what I'm currently learning, so I couldn't figure out why.
I am doing Learning Python the Hard Way and would appreciate any help.
file_content is a string variable, which contains contents of the file -- it has no relation to the file. The file descriptor you open with open(from_file) will be closed automatically: file sessions are closed after the file-objects exit the scope (in this case, immediately after .read()).
open(...) returns a reference to a file object, calling read on that reads the file returning a string object, calling write writes to it returning None, neither of which have a close attribute.
>>> help(open)
Help on built-in function open in module __builtin__:
open(...)
open(name[, mode[, buffering]]) -> file object
Open a file using the file() type, returns a file object. This is the
preferred way to open a file.
>>> a = open('a', 'w')
>>> help(a.read)
read(...)
read([size]) -> read at most size bytes, returned as a string.
If the size argument is negative or omitted, read until EOF is reached.
Notice that when in non-blocking mode, less data than what was requested
may be returned, even if no size parameter was given.
>>> help(a.write)
Help on built-in function write:
write(...)
write(str) -> None. Write string str to file.
Note that due to buffering, flush() or close() may be needed before
the file on disk reflects the data written.
Theres a couple ways of remedying this:
>>> file = open(from_file)
>>> content = file.read()
>>> file.close()
or with python >= 2.5
>>> with open(from_file) as f:
... content = f.read()
The with will make sure the file is closed.
When you do file_content = open(from_file).read(), you set file_content to the contents of the file (as read by read). You can't close this string. You need to save the file object separately from its contents, something like:
theFile = open(from_file)
file_content = theFile.read()
# do whatever you need to do
theFile.close()
You have a similar problem with new_file. You should separate the open(to_file) call from the write.