I have some Python3 code that opens a file in write mode, writes something to it, and then closes the file. The filename is an int. For some reason, the code doesn't work as expected. When I run the f.write() statement, a 6 is printed to the screen. And when I run the f.close() statement, the string that was supposed to be written is printed to the screen.
>>> f = open(2, 'w')
>>> f.write('FooBar')
6
>>> f.close()
FooBar>>>
>>>
I checked the directory that I ran this in and the file (named 2) was not created. Can anyone explain what is going on? I suspect it has to do with the filename being an int, but I'm not sure.
You're passing in a file descriptor number (2 for stderr).
See the documentation for open(), emphasis mine:
file is a path-like object giving the pathname (absolute or relative to the current working directory) of the file to be opened or an integer file descriptor of the file to be wrapped.
As to why nothing happens before .close() (or .flush(): Your stream is line buffered, and you're not writing a newline.
f = open(2, 'wb', buffering=0)
to disable buffering.
If you wish to write to a file called '2', you must pass a string.
f = open('2', 'w')
Alternatively to a file name (type str) open also accepts a file descriptor (type int). 2 is the file descriptor of stderr on Linux, so you are opening the standard error stream for writing, so everything you write to that file object will appear in your terminal/console! The reason it appears only after you do file.close() is that by default the write content isn't immediately written to the file but rather kept in a buffer which gets written only when a newline \n is encountered in the write content, and of course when the file is closed. You can force a writeout to file by calling file.flush().
The reason for the 6 you get on screen is that the return value of file.write is always the number of characters that has been written.
In case you wanted to create a file with the name 2 in the current working directory, you need to wrap the 2 in quotes:
>>> f = open("2", 'w')
>>> f.write('FooBar')
6
>>> f.close()
>>>
Related
I'm trying to store a file I create on an ftp server.
I've been able to create the temp file and store it as an empty file, but I haven't been able to write any data to the file before storing it.
Here is the partially working code:
#Loggin to server.
ftp = FTP(Integrate.ftp_site)
ftp.login(paths[0], paths[1])
ftp.cwd(paths[3])
f = tempfile.SpooledTemporaryFile()
# Throws error.
f.write(bytes("hello", 'UTF-8'))
#No error, doesn't work.
#f.write("hello")
#Also, doesn't throw error, and doesn't write anything to the file.
# f.write("hello".encode('UTF-8'))
file_name = "test.txt"
ftp.storlines("Stor " + file_name, f)
#Done.
f.close()
ftp.quit()
What am I doing wrong?
Thanks
Seeking!
To know where to read or write in the file (or file-like object), Python keeps a pointer to a location in the file. The documentation simply calls it "the file's current position". So, if you have a filed with these lines in it:
hello world
how are you
You can read it with Python like in the following code. Note that the tell() function tells you the file's position.
>>> f = open('file.txt', 'r')
>>> f.tell()
0
>>> f.readline()
'hello world\n'
>>> f.tell()
12
Python is now twelve characters "into" the file. If you'd count the characters, that means it's right after the newline character (\n is a single character). Continuing to read from the file with readlines() or any other reading function will use this position to know where to start reading.
Writing to the file will also use and increment the position. This means that if, after writing to the file you read from the file, Python will start reading at the position it has saved (which is right after whatever you just wrote), not the beginning of the file.
The ftp.storlines() function uses the same readlines() function, which only starts reading at the file's position, so after whatever you wrote. You can solve this by seeking back to the start of the file before calling ftp.storlines(). Use f.seek(0) to reset the file position to the very start of the file.
Oops.
I uninstalled both pythons afterwards and re-downloaded the 32-bit.
Now I'm trying to open a test.txt file after starting python in PowerShell and it gives me this
>>> open('C:/test/test.txt')
<open file 'C:/test/test.txt', mode 'r' at 0x021CB7B0>
>>> open('C:/test/test.txt')
<open file 'C:/test/test.txt', mode 'r' at 0x021CB758>
>>> open('C:/test/test.txt')
<open file 'C:/test/test.txt', mode 'r' at 0x021CB7B0>
>>> open('C:/test/test.txt')
<open file 'C:/test/test.txt', mode 'r' at 0x021CB758>
and it continues alternating without opening the text file at all.
Also python -v on windows powershell gives me:
How can I fix my python?
This is ordinary behavior with Python objects (including file objects returned by open). It has to do with garbage collection, and nothing to do with the installation issues you were having.
When you call open, it creates a new file object. The text <open file 'C:/test/test.txt', mode 'r' at 0x021CB7B0> is the file object's repr. Later, when object will be garbage collected. Later still, when you create another new object, the memory from the first object may be reused. This is why you can see the same memory address more than once.
The reason that you see two addresses alternating is a bit more subtle. When you run the Python interpreter in interactive mode, it prints the repr of the value of any expression you type at the prompt (skipping None only). It also stores the most recently printed value in the variable _ (a single underscore). This means that each time you open that file, the returned file object is bound to _ for a short time. When you create the next file object, it replaces the first one in _ and the old file gets garbage collected (because it's not referred to by any other part of the code).
When you create the third file, it reuses the memory the first file used, since it's now free. It rebinds _ again, so the second file object is garbage collected. Now, when you create the fourth file, it reuses the memory from the second one. If you were to continue to create and destroy file objects (without doing anything else in between), the alternating memory addresses would continue indefinitely.
If you wrote your code a bit differently, you'd get different results. For instance, if you appended each newly opened file object to a list after creating it, they'd all end up with different memory addresses (since they'd all exist in memory at the same time).
file_objects = []
for i in range(5):
file_objects.append(open('C:/test/test.txt'))
print file_objects
However, while that's illustrative of what's going on, it sounds like what you really want is to open and read the contents of the file. To do that, you need to call the read method on the file object you get from open. A best practice is to use call open as part of a with statement, as this ensures that the file gets closed again after you're done with it:
with open('C:/test/test.txt') as f: # open the file, bind the file object to name f
text = f.read() # read the file contents into text
# the file is closed when the indented block ends
print text # print the contents read from the file
Well, that's the indented result. open() returns a file-object
if you want to read the content then you have use
open(r'C:\test\test.txt').read()
But it's better to use something like this,
with open(r'C:\test\test.txt') as f:
print f.read();
In python's OS module there is a method to open a file and a method to read a file.
The docs for the open method say:
Open the file file and set various flags according to flags and
possibly its mode according to mode. The default mode is 0777 (octal),
and the current umask value is first masked out. Return the file
descriptor for the newly opened file.
The docs for the read method say;
Read at most n bytes from file descriptor fd. Return a string
containing the bytes read. If the end of the file referred to by fd
has been reached, an empty string is returned.
I understand what it means to read n bytes from a file. But how does this differ from open?
"Opening" a file doesn't actually bring any of the data from the file into your program. It just prepares the file for reading (or writing), so when your program is ready to read the contents of the file it can do so right away.
Opening a file allows you to read or write to it (depending on the flag you pass as the second argument), whereas reading it actually pulls the data from a file that is typcially saved into a variable for processing or printed as output.
You do not always read from a file once it is opened. Opening also allows you to write to a file, either by overwriting all the contents or appending to the contents.
To read from a file:
>>> myfile = open('foo.txt', 'r')
>>> myfile.read()
First you open the file with read permission (r)
Then you read() from the file
To write to a file:
>>> myfile = open('foo.txt', 'r')
>>> myfile.write('I am writing to foo.txt')
The only thing that is being done in line 1 of each of these examples is opening the file. It is not until we actually read() from the file that anything is changed
open gets you a fd (file descriptor), you can read from that fd later.
One may also open a file for other purpose, say write to a file.
It seems to me you can read lines from the file handle without invoking the read method but I guess read() truly puts the data in the variable location. In my course we seem to be printing lines, counting lines, and adding numbers from lines without using read().
The rstrip() method needs to be used, however, because printing the line from the file handle using a for in statement also prints the invisible line break symbol at the end of the line, as does the print statement.
From Python for Everybody by Charles Severance, this is the starter code.
"""
7.2
Write a program that prompts for a file name,
then opens that file and reads through the file,
looking for lines of the form:
X-DSPAM-Confidence: 0.8475
Count these lines and extract the floating point
values from each of the lines and compute the
average of those values and produce an output as
shown below. Do not use the sum() function or a
variable named sum in your solution.
You can download the sample data at
http://www.py4e.com/code3/mbox-short.txt when you
are testing below enter mbox-short.txt as the file name.
"""
# Use the file name mbox-short.txt as the file name
fname = input("Enter file name: ")
fh = open(fname)
for line in fh:
if not line.startswith("X-DSPAM-Confidence:") :
continue
print(line)
print("Done")
in a py module, I write:
outFile = open(fileName, mode='w')
if A:
outFile.write(...)
if B:
outFile.write(...)
and in these lines, I didn't use flush or close method.
Then after these lines, I want to check whether this "outFile" object is empty or not. How can I do with it?
There are a few problems with your code.
You can't .write to a file that you opened with 'r'. You need to open(fileName, 'w').
If A or B then you've certainly written to the file, so it's not empty!
Barring those. you can get the length of a file with
os.stat(outFile.fileno())
EDIT: I'll explain what flush does. Python is often used to do quite large amounts of file reads and writes, which can be slow. It is thus tweaked to make them as fast as possible. One way that is does so is to "buffer" such writes and then do them all in one big block: when you write a small string, Python will remember it but won't actually write it to the file until it thinks it should.
This means that if you want to tell whether you have written data to the file by inspecting the file, you have to tell Python to write all the data it's remembering first, or else you might not see it. flush is the command to write all the buffered data.
Of course, if you ask Python whether it's written anything to the file, say by inspecting the position in the file (.tell()), then it will know about the buffering.
If you've already written to the file, you can use .tell() to check if the current file position is nonzero:
>>> handle = open('/tmp/file.txt', 'w')
>>> handle.write('foo')
>>> handle.tell()
3
This won't work if you .seek() back to the beginning of the file.
You can use os.stat to get file info:
import os
fileSize = os.stat(fileName).st_size
with open("filename.txt", "r+") as f:
if f.read():
# file isn't empty
f.write("something")
# uncomment this line if you want to delete everything else in the file
# f.truncate()
else:
# file is empty
f.write("somethingelse")
"r+" mode always you to read & write.
"with" will automatically close file
When using this code in python:
f = open('ping.log', 'r+')
f.write("["+time.ctime()+"]"+"Status")
f.close()
My file always gets overwritten. And only has one line in it, like this:
[Fri Sep 02 16:30:56 2011]Status
Why is it getting overwritten?
It's failing because you are effectively recreating the file each time as you are overwriting the first N bytes every time. If you wrote less bytes you'd see the "old" information still there.
You need to open the file for "append"
'a' opens the file for appending
Source
r+ sets the initial file pointer to the beginning. Either seek to the end or use a mode.
Check this question. Open the file with the "a" mode:
f = open("ping.log","a")
...
http://docs.python.org/tutorial/inputoutput.html#reading-and-writing-files
The first argument is a string containing the filename. The second
argument is another string containing a few characters describing the
way in which the file will be used. mode can be 'r' when the file will
only be read, 'w' for only writing (an existing file with the same
name will be erased), and 'a' opens the file for appending; any data
written to the file is automatically added to the end. 'r+' opens the
file for both reading and writing. The mode argument is optional; 'r'
will be assumed if it’s omitted.
so use
f = open('ping.log', 'a')
f.write("["+time.ctime()+"]"+"Status")
f.close()