\chapter{Files}

\section{Reading and writing text files}


The following function copies a file, reading and writing up to fifty
characters at a time. The first argument is the name of the original
file; the second is the name of the new file:
\begin{python}
def copy_file(oldfile, newfile):
    infile = open(oldfile, 'r')
    outfile = open(newfile, 'w')
    while True:
        text = infile.read(50)
        if text == "":
            break
        outfile.write(text)
    infile.close()
    outfile.close()
    return
\end{python}
This functions continues looping, reading 50 characters from
\pythoninline{infile} and writing the same 50 charaters to
\pythoninline{outfile} until the end of \pythoninline{infile} is
reached, at which point text is empty and the break statement is
executed. 

\section{Text files}

A \myidx{text file} is a file that contains printable characters and
whitespace, organized into lines separated by newline
characters. Since Python is specifically designed to process text
files, it provides methods that make the job easy.
To demonstrate, we'll create a text file with three lines of text
separated by newlines:
\begin{pythonInteractive}
>>> outfile = open("test.dat","w")
>>> outfile.write("line one\nline two\nline three\n")
>>> outfile.close()
\end{pythonInteractive}
The \pythoninline{readline} method reads all the characters up to and
including the next newline character: 
\begin{pythonInteractive}
>>> infile = open("test.dat","r")
>>> print inf.readline()
line one
   
>>>
\end{pythonInteractive}

\pythoninline{readlines} returns all of the remaining lines as a list
of strings: 
\begin{pythonInteractive}
>>> print infile.readlines()
['line two\012', 'line three\012']
\end{pythonInteractive}
In this case, the output is in list format, which means that the
strings appear with quotation marks and the newline character appears
as the escape sequence $\backslash$$\backslash$012.
At the end of the file, \pythoninline{readline} returns the empty string and
\pythoninline{readlines} returns the empty list:
\begin{pythonInteractive}
>>> print infile.readline()
   
>>> print infile.readlines()
[]
\end{pythonInteractive}

The following is an example of a line-processing program.
\pythoninline{filter} makes a copy of \pythoninline{oldfile}, omitting
any lines that begin with \#: 
\begin{python}
def filter(oldfile, newfile):
    infile = open(oldfile, 'r')
    outfile = open(newfile, 'w')
    while True:
        text = infile.readline()
        if text == "":
           break
        if text[0] == '#':
           continue
        outfile.write(text)
    infile.close()
    outfile.close()
    return
\end{python}
The \myidx{\pythoninline{continue} statement} ends the current iteration of the
loop, but continues looping. The flow of execution moves to the top
of the loop, checks the condition, and proceeds accordingly.
Thus, if text is the empty string, the loop exits. If the first
character of text is a hash mark, the flow of execution goes to the
top of the loop. Only if both conditions fail do we copy text into
the new file.


\section{Counting Letters}
\label{sec-count-letters}
The \pythoninline{ord} function returns the integer representation of
a character: 
\begin{python}
>>> ord('a')
97
>>> ord('A')
65
>>>
\end{python}
This example explains why \pythoninline{'Apple'~$<$~'apple'} evaluates
to \pythoninline{True}. 

The \pythoninline{chr} function is the inverse of \pythoninline{ord}.
It takes an integer as an argument and returns its character
representation: 
\begin{pythonInteractive}
>>> for i in range(65, 71):
...     print chr(i)
...
A
B
C
D
E
F
>>>
\end{pythonInteractive}
The following program, \pythoninline{countletters.py} counts the number of times
each character occurs in the book Alice in Wonderland (\brenNote{put aiw.txt somewhere}):
\begin{python}
#
# countletters.py
#

def display(i):
    if i == 10: return 'LF'
    if i == 13: return 'CR' 
    if i == 32: return 'SPACE' 
    return chr(i)

infile = open('alice_in_wonderland.txt', 'r')
text = infile.read()
infile.close()

counts = 128 * [0]

for letter in text:
    counts[ord(letter)] += 1

outfile = open('alice_counts.dat', 'w')
outfile.write("%-12s%s\n" % ("Character", "Count"))
outfile.write("=================\n")

for i in range(len(counts)):
    if counts[i]:
        outfile.write("%-12s%d\n" % (display(i), counts[i]))

outfile.close()
\end{python}
Run this program and look at the output file it generates using a
text editor. You will be asked to analyze the program in the exercies
below.


\section{Glossary}
\begin{description}

 \item[continue statement:]A statement that causes the current
   iteration of a loop to end. The flow of execution goes to the top
   of the loop, evaluates the condition, and proceeds accordingly.
 \item[file system:]A method for naming, accessing, and organizing
   files and the data they contain.
 \item[directory:]A named collection of files, also called a
   folder. Directories can contain files and other directories, which
   are refered to as \emph{subdirectories} of the directory that
   contains them.
 \item[path:]The name and location of a file within a file system. For
   example \pythoninline{/usr/share/dict/words}
   indicates a file named words found in the \pythoninline{dict} subdirectory of the \pythoninline{share} subdirectory of the \pythoninline{usr} directory.
 \item[delimiter:]A sequence of one or more characters used to specify
   the boundary between separate parts of text.
 \item[command line:]The sequence of characters read into the
   \emph{command interpreter} in a \emph{command line interface} (see
   the Wikipedia article on command line interface for more
   information).
 \item[command line argument:] A value passed to a program along with
   the program's invocation at the \emph{command prompt} of a command
   line interface (CLI).
 \item[Jython:] An implementation of the Python programming language
   written in Java. (see the Jython home page at
   \url{http://www.jython.org} for more information.)
 \item[\pythoninline{argv}:]\pythoninline{argv} is short for
\emph{argument vector} and is a 
   variable in the sys module which stores a list of command line
   arguments passed to a program at run time.
 \end{description}

\section{Laboratory Exercises}
\begin{enumerate}
\item \pythoninline{unsorted\_fruits.txt} contains a list of 26
fruits, each one with a name that begins with a different letter of
the alphabet.
   \\
   Write a program named \pythoninline{sort\_fruits.py} that reads in the fruits from
   \pythoninline{unsorted\_fruits.txt} and writes them out in alphabetical order to a
   file named \pythoninline{sorted\_fruits.txt}.
 \item Answer the following questions about
   \pythoninline{countletters.py}: \begin{enumerate}
   \item Explain in detail what the three lines do:
\begin{python}
infile = open('alice_in_wonderland.txt', 'r')
text = infile.read()
infile.close()
\end{python}
What would \pythoninline{type(text)} return after these lines have been
executed?
   \item What does the expression \pythoninline{128~*~[0]} evaluate
to? Read about ASCII in Wikipedia and explain why you think the variable, \pythoninline{counts}
     is assigned to \pythoninline{128~*~[0]} in light of what you read.
   \item What does
\begin{python}
for letter in text:
    counts[ord(letter)] += 1
\end{python}
do to \pythoninline{counts}?
   \item Explain the purpose of the \pythoninline{display} function.
Why does it 
     check for values \pythoninline{10}, \pythoninline{13}, and
\pythoninline{32}? What is special about those values?
   \item Describe in detail what the lines
\begin{python}
outfile = open('alice_counts.dat', 'w')
outfile.write("%-12s%s\n" % ("Character", "Count"))
outfile.write("=================\n")
\end{python}
do. What will be in \pythoninline{alice\_counts.dat} when they finish executing?
\item Finally, explain in detail what
\begin{python}
for i in range(len(counts)):
    if counts[i]:
        outfile.write("%-12s%d\n" % (display(i), counts[i]))
\end{python}
does. What is the purpose of \pythoninline{if~counts[i]}?
\end{enumerate}

\item Write a program called \pythoninline{alice\_words.py} that
creates a text file 
   named \pythoninline{alice\_words.txt} containing an alphabetical listing of all
   the words found in \pythoninline{alice\_in\_wonderland.txt} together with the
   number of times each word occurs. The first 10 lines of your output
   file should look something like this:
\begin{python}
Word              Count
=======================
a                 631
a-piece           1
abide             1
able              1
about             94
above             3
absence           1
absurd            2
\end{python}
How many times does the word, \pythoninline{alice}, occur in the book?
\item What is the longest word in Alice in Wonderland? How many
charactes does it have?
\end{enumerate}
