Python Concepts/Files
Objective
[edit | edit source]
|
Lesson
[edit | edit source]
What's A File[edit | edit source]With work on a computer, files are usually used in daily tasks. You may spend your days writing word processor documents for a news company or you may like to listen to your mp3 files during your free time. You most likely already have an abstract idea of what a file is: a piece of information that's stored on a disk. So what exactly is a file? A file is just a group of 1's and 0's that are stored on the disk. Since the operating system takes care of managing them, you don't have to worry about their technical details. The data within a file may be as simple as a few words of text, or nothing at all ( Whatever the size and shape of a file, the usual operations on files are open, read and/or write, and close.
ifile = open('test.txt') # ifile (input file) is a file object
# Same as ifile = open('test.txt', 'rt') where 'rt' (default) means 'read text'.
for line in ifile : # ifile behaves like an iterable
print (line, end='')
ifile.close()
The content of file 'test.txt': Hello, world! Hola, mundo! Goodbye, world! Technical definition of a file object[edit | edit source]>>> import io
>>>
>>> f = open('test1.txt') ; f
<_io.TextIOWrapper name='test1.txt' mode='r' encoding='UTF-8'>
>>> isinstance(f, io.TextIOWrapper)
True
>>> f.close()
>>> f
<_io.TextIOWrapper name='test1.txt' mode='r' encoding='UTF-8'>
>>> isinstance(f, io.TextIOWrapper)
True # Still valid, even though f is closed.
>>> f.readable()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file
>>>
>>> # Open file in binary mode:
>>>
>>> f = open('test1.txt', 'r+b') ; f
<_io.BufferedRandom name='test1.txt'>
>>> isinstance(f, io.BufferedRandom)
True
>>> f.close()
>>> f
<_io.BufferedRandom name='test1.txt'>
>>> isinstance(f, io.BufferedRandom)
True # Still valid, even though f is closed.
>>>
|
Opening A File
[edit | edit source]
The concept of opening a file seems simple enough, but it leads to significant questions: Does the file exist? If not, why not? If the file exists, is it where you expect it to be? If so, do you have permission to open it? You may be able to open it for reading, but what about writing or truncating the file? If you open the file, is it OK if somebody else opens it while you have it open? You might decide to lock all others out of the file while you have it open. If so, normal etiquette requires that you do what you have to do quickly and then close it so that others may access it. Computer scientists prepare for errors and handle them gracefully. Therefore, the above code is rewritten to handle errors: inputFile = 'test.txt'
# Open the file
status = 0
try:
ifile = open(inputFile)
except:
print ("Error detected when opening '{}'.".format(inputFile))
status = 99
if status : exit (status)
# Read the file
status = 0
try:
for line in ifile :
print (line, end='')
except:
print ("Error detected when reading '{}'.".format(inputFile))
status = 98
if status : exit (status)
# Close the file
status = 0
try:
ifile.close()
except:
print ("Error detected when closing '{}'.".format(inputFile))
status = 97
if status : exit (status)
exit (0)
Handling Errors[edit | edit source]In the example immediately above there is more error-handling code than operational code. If you think this is unrealistic, remember that software engineers are notorious for overestimating their ability and underestimating the time to complete a given project. Simple mistakes can lead to disastrous and expensive consequences.
The third launch in the series, 30 April 1999, failed because an engineer entered one parameter as -0.1992476 instead of the correct -1.992476. More than one billion dollars (that's billion with a 'b') was wasted. "Milstar satellite overview" This page doesn't mention the failed third launch. "History of Milstar" From Wikipedia. "A single error can kill a mission" "Examples from the Launch World"
The following code is copied directly from a famous instructional book for Perl: opendir(ETC, "/etc") || die "no etc?";
foreach $name (sort readdir(ETC)) {
print "$name\n";
}
close(ETC);
Can you spot the error? Rewrite the code to catch potential errors: opendir(ETC, "/etc") || die "no etc?";
foreach $name (sort readdir(ETC)) {
print "$name\n";
}
close(ETC) || die "";
Execution of this piece of code fails at opendir(ETC, "/etc") || die "no etc?";
foreach $name (sort readdir(ETC)) {
print "$name\n";
}
closedir(ETC) || die '';
Your attitude may be: "It doesn't matter about the opendir(ETC, "/etc") || die "no etc?";
foreach $name (sort readdir(ETC)) {
print "$name\n";
}
exit (0);
Catching errors often reveals simple mistakes in software that can go undetected for a long time.
python's [edit | edit source] |
Information about the file
[edit | edit source]
Information available after opening[edit | edit source]>>> f = open ('test.txt')
>>> f
<_io.TextIOWrapper name='test.txt' mode='r' encoding='UTF-8'> # file object
>>>
>>> f = open ('test.txt') # File is silently reopened without error.
>>>
>>> f.closed
False # File is open
>>>
>>> f.fileno()
3 # The underlying file descriptor, an int.
>>>
>>> f.isatty()
False # Input is not coming from a terminal.
>>>
>>> f.readable()
True # We expect the file to be readable. It was opened without error.
>>>
>>> f.seekable()
True # We can cause the file to seek to any desired position within the file.
>>>
>>> f.tell()
0 # Internal pointer is at beginning of file. This is expected after opening file.
>>>
>>> f.writable()
False # Not writable, opened for reading only. An attempt to write or truncate raises OSError.
>>>
>>> # Size of file:
>>> f.seek(0,2) # Change stream position to 0 bytes from end of file.
43 # At end of file. Therefore, file contains 43 bytes.
>>> f.tell()
43 # Current position of stream.
>>>
Function [edit | edit source] |
Seeking within a text file
[edit | edit source]
Within text files the method >>> f = open ('test.txt', mode='rt')
>>>
>>> f.seek( 16, 0 ) # Put beginning of stream at position 16 relative to beginning of file.
16
>>> f.seek( 13 ) # Same as f.seek( 13, 0 )
13
>>>
>>> f.seek( -5, 0 ) # Try to position stream before beginning of file.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: negative seek position -5
>>>
>>> f.tell()
13 # Position of stream pointer is unchanged.
>>>
>>> f.seek( -5, 1 ) # Try to position stream -5 bytes relative to current position:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
io.UnsupportedOperation: can't do nonzero cur-relative seeks
>>>
>>> f.tell()
13 # Position of stream pointer is unchanged.
>>>
>>> f.seek( f.tell()+4 ) # Equivalent of f.seek( 4, 1 ).
17
>>>
>>> f.seek( 0,2 ) # Position stream at 0 bytes relative to end-of-file.
43
>>>
>>> f.seek( -5, 2 ) # Try to position stream -5 bytes relative to end-of-file:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
io.UnsupportedOperation: can't do nonzero end-relative seeks
>>>
>>> f.seek( f.seek(0,2) - 7 ) # Equivalent of f.seek( -7, 2 ).
36
>>>
>>> f.seek( 1234567 )
1234567
>>> f.tell()
1234567 # Yes, you can put beginning of stream after end-of-file without error.
>>>
|
Reading from a single file
[edit | edit source]
f.read()[edit | edit source]>>> f = open ('test.txt')
>>> f
<_io.TextIOWrapper name='test.txt' mode='r' encoding='UTF-8'> # file object
>>>
>>> f.read() # reads the whole file.
'Hello, world!\nHola, mundo!\nGoodbye, world!\n'
>>> f.read()
'' # At end-of-file.
>>>
>>> f.seek(0) # To read file again, put beginning of stream at beginning of file.
0
>>> f.read()
'Hello, world!\nHola, mundo!\nGoodbye, world!\n'
>>> f.read()
'' # At end-of-file again.
>>>
f.readline()[edit | edit source]>>> f = open ('test.txt', mode='rt')
>>> f.readline() # Read one line of the file.
'Hello, world!\n' # '\n' at end has not been removed.
>>> f.readline() # Read next line of the file.
'Hola, mundo!\n'
>>> f.readline() # Read next line of the file.
'Goodbye, world!\n'
>>> f.readline() # Read next line of the file.
'' # At end-of-file.
>>>
To iterate using f = open ('test.txt', mode='rt')
while True :
s = f.readline()
if s == '' : break
print (s, end='')
Hello, world! Hola, mundo! Goodbye, world!
f = open ('test.txt', mode='rt')
while True :
posn = f.tell()
s = f.readline(8)
if s == '' : break
print (" %2d %s" % (posn , s), end='')
0 Hello, w 8 orld! 14 Hola, mu 22 ndo! 27 Goodbye, 35 world! File object as iterable[edit | edit source]>>> f = open ('test.txt', mode='rt')
>>>
>>> lines = list(f) ; lines
['Hello, world!\n', 'Hola, mundo!\n', 'Goodbye, world!\n']
>>> lines = list(f) ; lines
[] # At end-of-file
>>> f.seek(0) # Put beginning of stream at beginning of file.
0
>>> lines = list(f) ; lines
['Hello, world!\n', 'Hola, mundo!\n', 'Goodbye, world!\n']
>>> lines = list(f) ; lines
[]
>>>
>>> f.seek(20) # Put beginning of stream at desired position.
20
>>> list(f)
['mundo!\n', 'Goodbye, world!\n']
>>> list(f)
[]
>>>
f = open('test.txt')
for line in f : # This code is memory efficient,
print (line, end='') # fast and simple.
f.close()
Hello, world! Hola, mundo! Goodbye, world! Display all lines in the file that contain the word 'world': >>> f = open ('test.txt', mode='rt')
>>>
>>> [p for p in f if 'world' in p]
['Hello, world!\n', 'Goodbye, world!\n']
>>>
>>> f.close()
|
Reading international text
[edit | edit source]
File test1.txt contains: η ρωμαϊκή μυθολογία (Roman mythology) Всероссийская перепись населения 2010 года (2010 All-Russia Population Census) ..../...//..../...//..../...//..../...//..../...//..../...//..../...//..../...// The last line is included to facilitate counting characters.
Without knowing anything about Greek or Russian we see immediately that the Greek characters for iota ϊ ί are different, as are the Russian characters и й. The next thing to notice is that the file contains 249 bytes, but each line contains 38, 79, 81 characters or 198 characters for the whole file. Not to worry. In text files Python performs the appropriate encoding and decoding nicely: f = open('test1.txt')
for line in f :
print (len(line), line, end='')
f.close()
38 η ρωμαϊκή μυθολογία (Roman mythology) 79 Всероссийская перепись населения 2010 года (2010 All-Russia Population Census) 81 ..../...//..../...//..../...//..../...//..../...//..../...//..../...//..../...// The same again with different detail: f = open ('test1.txt', mode='rt')
while True :
posn = f.tell()
s = f.readline(30) # In text files read 30 characters.
print (" %3d %s" % (posn , s), end='')
if s == '' : break
f.close()
0 η ρωμαϊκή μυθολογία (Roman myt 47 hology) 55 Всероссийская перепись населен 113 ия 2010 года (2010 All-Russia 149 Population Census) 168 ..../...//..../...//..../...// 198 ..../...//..../...//..../...// 228 ..../...//..../...// 249 Length of first line in bytes = 55. Length of first line in characters = 38. Length of second line in bytes = 168-55 = 113. Length of second line in characters = 79. Length of third line in bytes = 249-168 = 81. Length of third line in characters = 81.
Take care if you reposition the stream into the middle of international text: f = open ('test1.txt', mode='rt')
f.seek(4)
posn = f.tell()
s = f.readline(30)
print (" %3d %s" % (posn , s))
Traceback (most recent call last): File "t3.py", line 11, in <module> s = f.readline(30) File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/codecs.py", line 321, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 0: invalid start byte
|
Reading from multiple input streams
[edit | edit source]
The function >>> import fileinput
>>>
>>> fileinput.input( files=('test.txt', 'test1.txt') ) # The 2 named files provide the input stream.
<fileinput.FileInput object at 0x101a96208>
>>>
>>> list ( fileinput.input( files=('test.txt', 'test1.txt') ) )
['Hello, world!\n',
'Hola, mundo!\n',
'Goodbye, world!\n',
'η ρωμαϊκή μυθολογία (Roman mythology)\n',
'Всероссийская перепись населения 2010 года (2010 All-Russia Population Census)\n',
'..../...//..../...//..../...//..../...//..../...//..../...//..../...//..../...//\n']
# Output above was edited for clarity.
Successive invocations of the stream do not require reopening or resetting the stream: >>> len(list ( fileinput.input( files=('test.txt', 'test1.txt') ) ))
6
>>> len(list ( fileinput.input( files=('test.txt', 'test1.txt') ) ))
6
>>> (list ( fileinput.input( files=('test.txt', 'test1.txt') ) ))[3]
'η ρωμαϊκή μυθολογία (Roman mythology)\n'
>>> (list ( fileinput.input( files=('test.txt', 'test1.txt') ) ))[4]
'Всероссийская перепись населения 2010 года (2010 All-Russia Population Census)\n'
>>> (list ( fileinput.input( files=('test.txt', 'test1.txt') ) ))[1]
'Hola, mundo!\n'
>>> (list ( fileinput.input( files=('test.txt', 'test1.txt') ) ))[1]
'Hola, mundo!\n'
>>>
>>> (list ( fileinput.input( files=('test.txt', 'test1.txt') ) ))[1:4]
['Hola, mundo!\n', 'Goodbye, world!\n', 'η ρωμαϊκή μυθολογία (Roman mythology)\n']
>>>
The functions for line in fileinput.input( files=('test.txt', '/dev/null', 'test1.txt') ) :
print ('filename =', fileinput.filename())
print (' ', line, end='')
print (' lineno = {}, filelineno = {}.'.format( fileinput.lineno(), fileinput.filelineno() ))
exit (0)
filename = test.txt Hello, world! lineno = 1, filelineno = 1. filename = test.txt Hola, mundo! lineno = 2, filelineno = 2. filename = test.txt Goodbye, world! lineno = 3, filelineno = 3. filename = test1.txt η ρωμαϊκή μυθολογία (Roman mythology) lineno = 4, filelineno = 1. filename = test1.txt Всероссийская перепись населения 2010 года (2010 All-Russia Population Census) lineno = 5, filelineno = 2. filename = test1.txt ..../...//..../...//..../...//..../...//..../...//..../...//..../...//..../...// lineno = 6, filelineno = 3. The null file |
Writing text to a disk file
[edit | edit source]
The function In text mode it returns the number of characters written, in binary mode the number of bytes. s = '''η ρωμαϊκή μυθολογία (Greek characters)
Всероссийская перепись (Russian or Cyrillic)
The Quick BROWN foX (English characters)
'''
length_of_s = len(s) # in characters
ofile = open('test1a.txt', 'w')
number_written = ofile.write(s) # in characters
end_of_file = ofile.tell() # in bytes
ofile.close()
print (
'''
length_of_s = {}
number_written = {}
end_of_file = {}
'''.format(length_of_s, number_written, end_of_file)
)
length_of_s = 125 number_written = 125 end_of_file = 163 On the UNIX command line: $ wc test1a.txt 3 17 163 test1a.txt $ The UNIX executable The file actually contains 16 words. The difference between 163 and 125 (38) is because of the inclusion of 17 Greek letters and 21 Russian. Each of the international characters requires 2 bytes. |
Binary operations on disk files
[edit | edit source]
Brief review of binary conversion[edit | edit source]An >>> b = 123456789
>>> b1 = hex(b) ; b1
'0x75bcd15'
>>> b2 = b1[2:] ; b2
'75bcd15'
>>> b3 = '0'*(len(b2)%2) + b2 ; b3 # Ensure that the string contains an even number of hex digits.
'075bcd15'
>>> len(b3) % 2
0 # Length of b3 is even.
>>>
>>> b4 = bytes.fromhex(b3) ; b4
b'\x07[\xcd\x15' # b4 is a bytes object containing integer b in binary format.
>>> isinstance(b4, bytes)
True
>>>
>>> list(b4)
[7, 91, 205, 21]
>>> 7 == b4[0] and 91 == b4[1] == ord('[') and 205 == b4[2] == 0xCD and 21 == b4[3] == 0x15
True
>>>
>>> (7<<24) + (91<<16) + (205<<8) + 21 == b # Check the conversion.
True
>>> # Convert from bytes object b4 to int:
>>>
>>> b5 = b4.hex() ; b5
'075bcd15'
>>> b6 = int(b5,16) ; b6
123456789
>>>
>>> b6 == b
True
>>>
Methods [edit | edit source] |
External operations on files
[edit | edit source]
Creating a file[edit | edit source]On the Unix command line: $ ls -la test1.txt test5.txt ls: test5.txt: No such file or directory -rw-r--r-- 1 user staff 249 Sep 15 06:53 test1.txt $ >>> f = open ('test1.txt', 'x') # 'x' for exclusive creation.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileExistsError: [Errno 17] File exists: 'test1.txt'
>>> f
<_io.BufferedRandom name='test1.bin'> # Unchanged. f refers to previous open.
>>>
>>> f = open ('test5.txt', 'x')
>>> f
<_io.TextIOWrapper name='test5.txt' mode='x' encoding='UTF-8'>
>>> f.closed
False
>>> f.readable()
False
>>> f.writable()
True
>>> f.close()
>>>
On the Unix command line: $ ls -la test1.txt test5.txt -rw-r--r-- 1 user staff 249 Sep 15 06:53 test1.txt -rw-r--r-- 1 user staff 0 Oct 4 08:28 test5.txt # File was created. $ Truncating a file[edit | edit source]>>> os.stat ('test1.txt').st_size
249
>>> os.truncate('test1.txt', 200)
>>> os.stat ('test1.txt').st_size
200
>>> os.stat ('test5.txt').st_size
0
>>> os.truncate('test5.txt', 150)
>>> os.stat ('test5.txt').st_size
150 # 150 bytes were added to file.
>>>
On the Unix command line: $ ls -la test1.txt test5.txt -rw-r--r-- 1 user staff 200 Oct 4 08:37 test1.txt -rw-r--r-- 1 user staff 150 Oct 4 08:38 test5.txt $ od -h test5.txt 0000000 0000 0000 0000 0000 0000 0000 0000 0000 * 0000220 0000 0000 0000 0000226 $ # test5.txt contains 150 null bytes after truncation. Accessing a file[edit | edit source]
$ ls -la t*n --w-r----- 1 user staff 25 Sep 29 13:12 test.bin -rw-r--r-- 1 user staff 25 Sep 29 08:03 test1.bin $ >>> os.access('test0.txt', os.F_OK)
False # The file does not exist.
>>>
>>> os.access('test.bin', os.F_OK)
True # The file exists.
>>>
>>> os.access('test.bin', os.R_OK)
False # It is not readable.
>>>
>>> os.access('test.bin', os.W_OK)
True # It is writable.
>>
>>> os.access('test.bin', os.X_OK)
False # It is not executable.
>>>
>>> os.access('test1.bin', os.F_OK + os.R_OK + os.W_OK) # Modes may be added.
True # The file exists and it's both readable and writable.
>>>
Changing a file's u,g,o permissions[edit | edit source]
$ ls -la t*n --w-r----- 1 user staff 25 Sep 29 13:12 test.bin -rw-r--r-- 1 user staff 25 Sep 29 08:03 test1.bin $ On the python command line: >>> import os
>>> import stat
>>> os.chmod('test.bin', stat.S_IRWXG) # read, write, execute for group.
>>>
On the Unix command line: $ ls -la t*n ----rwx--- 1 user staff 25 Sep 29 13:12 test.bin # Permissions changed to r,w,x for group. -rw-r--r-- 1 user staff 25 Sep 29 08:03 test1.bin $ Renaming a file[edit | edit source]
$ ls -la test1*t -rw-r--r-- 1 user staff 200 Oct 4 08:37 test1.txt -rw-r--r-- 1 user staff 163 Sep 18 18:07 test1a.txt $ On the python command line: >>> os.rename('test1.txt', 'test1a.txt')
>>>
On the Unix command line: $ ls -la test1*t -rw-r--r-- 1 user staff 200 Oct 4 08:37 test1a.txt $ The old file
Removing a file[edit | edit source]
On the Unix command line: $ ls -la test1*t -rw-r--r-- 1 user staff 200 Oct 4 08:37 test1a.txt $ On the python command line: >>> os.remove('test1a.txt')
>>>
On the Unix command line: $ ls -la test1*t ls: test1*t: No such file or directory $ The file This function and |
Objects that behave like files
[edit | edit source]
The terminal[edit | edit source]On Unix each terminal window has its unique device name, a name that looks like a file name, eg, /dev/ttys003. Communication with the console may be achieved by treating the console like a file: $ cat t5.py import os
print ('Name of my terminal is:', os.ttyname(0))
f = open(os.ttyname(0), 'wt')
print ('File object opened for writing to my terminal is:', f)
print ('Enter your date-of-birth [mm/dd/yyyy]: ', end='', flush=True, file=f) # Writing to terminal.
f.close()
f = open(os.ttyname(0))
dob = f.read() # Reading from terminal.
print ('File object opened for reading from my terminal is:', f)
f.close()
print ('You entered:', dob, end='')
$ python3.6 t5.py Name of my terminal is: /dev/ttys003 File object opened for writing to my terminal is: <_io.TextIOWrapper name='/dev/ttys003' mode='wt' encoding='UTF-8'> Enter your date-of-birth [mm/dd/yyyy]: 12/31/1999 # Enter dob followed by new-line and ^D for end-of-file. File object opened for reading from my terminal is: <_io.TextIOWrapper name='/dev/ttys003' mode='r' encoding='UTF-8'> You entered: 12/31/1999 $ Pipes[edit | edit source]
>>> fdr,fdw = os.pipe()
>>> fdr
3 # The file descriptor for reading from the pipe.
>>> fdw
4 # The file descriptor for writing to the pipe.
>>>
>>> os.write(fdw, b'Hello, world!') # Write to the file descriptor associated with the pipe.
13 # Number of bytes written.
>>> os.read(fdr, 7) # Read a max of 7 bytes from the file descriptor associated with the pipe.
b'Hello, '
>>> os.read(fdr, 99) # Read a max of 99 bytes from fdr.
b'world!'
>>> os.close(fdr)
>>> os.close(fdw)
>>>
Standard input is usually file descriptor 0, standard output is 1, and standard error is 2. Further files opened by a process will then be assigned 3, 4, 5, and so forth. Hence file descriptors 3 and 4 above. The pipe implements a fifo, first-in-first-out queue. Data added to the pipe is appended to the data in the pipe. Data removed from the pipe is read from the beginning of data in the pipe. Before trying to read data from a pipe ensure that there is data in the pipe: import os
fdr,fdw = os.pipe()
number_written = os.write(fdw, b'9876543210')
number_of_bytes_in_pipe = os.stat(fdr).st_size
if number_written == number_of_bytes_in_pipe == 10 :
pass # Integrity of data looks good.
else :
print ('Internal error: Input data corrupted.')
exit (99)
print ('number_of_bytes_in_pipe =', number_of_bytes_in_pipe)
number_of_bytes_read_from_pipe = 0
while os.stat(fdr).st_size > 0 :
data = os.read(fdr,1)
number_of_bytes_read_from_pipe += len(data)
print ('data =', data)
os.close(fdr)
os.close(fdw)
print ('number_of_bytes_read_from_pipe =', number_of_bytes_read_from_pipe)
exit (0)
number_of_bytes_in_pipe = 10 data = b'9' data = b'8' data = b'7' data = b'6' data = b'5' data = b'4' data = b'3' data = b'2' data = b'1' data = b'0' number_of_bytes_read_from_pipe = 10 It seems that functions |
File objects and file descriptors
[edit | edit source]
On the Unix command line: $ ls -l test.txt ; cat test.txt -rw-r--r-- 1 user staff 43 Sep 9 17:26 test.txt Hello, world! Hola, mundo! Goodbye, world! $ The function >>> f = open('test.txt')
>>> f
<_io.TextIOWrapper name='test.txt' mode='r' encoding='UTF-8'>
>>>
>>> fd_f = f.fileno() # fd_f (an int) is the file descriptor associated with f.
>>> fd_f
5
>>>
>>> os.stat(fd_f).st_size # The file descriptor can provide info about the file.
43 # Size of file 'test.txt' in bytes
>>>
>>> os.lseek(fd_f,10,0) # Seek to beginning-of-file + 10
10
>>> f.tell()
10
>>> os.lseek(fd_f,-3,1) # Seek -3 relative to current position.
7 # Using fd_f it works.
>>> f.seek(-3,1) # Using f it doesn't work in text mode.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
io.UnsupportedOperation: can't do nonzero cur-relative seeks
>>> f.tell()
7
>>>
>>> f.seek(14)
14
>>> os.lseek(fd_f,0,1) # Report current position.
14
>>> f.read(13)
'Hola, mundo!\n'
>>> f.tell()
27
>>> os.lseek(fd_f,0,1)
43 # Internal pointers of f and fd_f are NOT always the same.
>>>
>>> os.lseek(fd_f,-16,2) # Seek -16 relative to end-of-file.
27
>>> os.read(fd_f,99)
b'Goodbye, world!\n'
>>>
>>> f.closed
False
>>> f.close() # This also closes fd_f.
>>> f.closed
True
>>> os.stat(fd_f).st_size
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 9] Bad file descriptor: 5
>>>
Multiple file objects with same file descriptor[edit | edit source]Two or more file objects may have the same file descriptor: >>> f = open('test.txt')
>>> f1 = open(f.fileno(), 'w', closefd=False)
>>> f
<_io.TextIOWrapper name='test.txt' mode='r' encoding='UTF-8'>
>>> f1
<_io.TextIOWrapper name=5 mode='w' encoding='UTF-8'>
>>> f.fileno()
5
>>> f1.fileno()
5
>>> f.closed
False
>>> f1.closed
False
>>> f.close()
>>> f.closed
True
>>> f1.closed
False # f1 remains open
>>> f1.fileno()
5
>>> f1.readable()
False
>>> f1.writable()
True # This info is deceptive.
>>>
If you have two file objects associated with the same file descriptor and you close one of the file objects, the behavior of the other may be
unpredictable. Unless you really know what you're doing, when you close one file object of many associated with the same file descriptor close
them all. Also, don't close the file descriptor (with |
Temporary files
[edit | edit source]
python's
tempfile.NamedTemporaryFile(
mode='w+b', # For consistent behavior across platforms.
buffering=None,
encoding=None, # Buffering, encoding and newline are as for open().
newline=None,
suffix='', # With 'suffix' and 'prefix' you have some control over the file name.
prefix='tmp',
dir=None, # You can specify the directory where the file will be created.
delete=True # You can choose to keep the file after closure.
)
Opening a temporary file in text mode for deletion on closing: >>> import tempfile
>>>
>>> f1 = tempfile.NamedTemporaryFile(mode='r+t', suffix='.txt')
>>> f1
<tempfile._TemporaryFileWrapper object at 0x101b7ab38>
>>> isinstance(f1, tempfile._TemporaryFileWrapper)
True
>>> f1.name
'/var/folders/8s/dctgn1y57fgc9_h2mzckbqs80000gn/T/tmpew4jippj.txt'
>>> f1.readable()
True
>>> f1.writable()
True
>>> f1.seekable()
True
>>> f1.encoding
'UTF-8'
>>> f1.write('Hello, world!\n')
14
>>> f1.write('Καλώς ήρθατε στο Βικιεπιστήμιο\n')
31 # 27 Greek + 4 English characters = 27*2 + 4 = 58 bytes.
>>> f1.tell()
72 # 14 + 58
>>> f1.seek(0)
0
>>> f1.readline()
'Hello, world!\n'
>>> f1.readline()
'Καλώς ήρθατε στο Βικιεπιστήμιο\n'
>>> f1.readline()
''
>>> os.stat( f1.name )
os.stat_result(st_mode=33152, st_ino=24460790, st_dev=16777218, st_nlink=1, st_uid=501, st_gid=20, st_size=72, st_atime=1508154874, st_mtime=1508154545, st_ctime=1508154545)
>>> f1.close()
>>> f1.name
'/var/folders/8s/dctgn1y57fgc9_h2mzckbqs80000gn/T/tmpew4jippj.txt'
>>> os.stat( f1.name )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory:
'/var/folders/8s/dctgn1y57fgc9_h2mzckbqs80000gn/T/tmpew4jippj.txt'
>>>
Opening a temorary file in binary mode for retention on closing: >>> f1 = tempfile.NamedTemporaryFile(suffix='.bin', delete=False)
>>> f1
<tempfile._TemporaryFileWrapper object at 0x101a8c518>
>>>
>>> f1.write( b'When in the course of ....' )
26
>>> f1.name
'/var/folders/8s/dctgn1y57fgc9_h2mzckbqs80000gn/T/tmpdz14i44i.bin'
>>> f1.tell()
26
>>> f1.seek(0)
0
>>> f1.read()
b'When in the course of ....'
>>> f1.close()
>>>
The temporary file exists after closing: $ ls -la /var/folders/8s/dctgn1y57fgc9_h2mzckbqs80000gn/T/tmpdz14i44i.bin -rw------- 1 user staff 26 Oct 16 07:22 /var/folders/8s/dctgn1y57fgc9_h2mzckbqs80000gn/T/tmpdz14i44i.bin $
|
Assignments
[edit | edit source]
|
Further Reading or Review
[edit | edit source]
|
References
[edit | edit source]1. Python's documentation:
"7.2. Reading and Writing Files," "11.3. fileinput — Iterate over lines from multiple input streams," "4.8. Binary Sequence Types," "16.1.5. Files and Directories," "11.6. tempfile — Generate temporary files and directories"
2. Python's methods:
"7.2.1. Methods of File Objects," "16.2.3.1. I/O Base Classes," "16.2.3.4. Text I/O"
3. Python's built-in functions:
"open(file, mode=.....)," "bytes()," "bytearray()," "os.ftruncate(fd, length)," " os.stat(path, *, ...)," "os.truncate(path, length)," "os.access(path, mode, ....)," "os.chmod(path, mode, ....)," "os.rename(src, dst, ....)," "os.remove(path, ....)," "os.pipe()," "os.read(fd, n)," "os.write(fd, str)," "print(*objects, ....)"