[Tutor] writing & reading files

Michael P. Reilly arcege@speakeasy.net
Wed, 16 Jan 2002 17:12:21 -0500


On Wed, Jan 16, 2002 at 12:25:59PM -0800, Frank Holmes wrote:
> 
> Still working with this little phonebook program.  When it runs, if 
> 'phoneyold' doesn't exist it creates it and writes data to file. Problem is, 
> if I close the program, open it again and again add entries it overwrites 
> the file and none of the previous entries exist. I have tried replacing the 
> 'w' in f=open('phoneyold','w') with 'a' to append to the file (problem is it 
> is a dictionary) but although when I check the data file the entry is there, 
> I cannot retrieve it. I have also tried 'w+' to append, but again all 
> previous data is dumped when I add. Again I am stumped. How can I add data, 
> close the file, re open it , add again and not dump previous data?

You have the right idea.  But you are trying to update an object to a
file, not just append new data.  The open-file modes are only for where
the data is placed, not how the data is.  Try this:

def add_name():
  # we get the pickled dictionary from the file to update in the function
  # 'r+' means read-write, pointer at beginning of file, do not overwrite
  f = open('phoneyold', 'r+')
  # we'll overwrite the global 'd1' variable since it does not seem to
  # be used in get_name() anyway, we could make it global tho
  d1 = pickle.load(f)

  dname = raw_input('Enter Name:\n')  # the prompt can be here too
  fname = raw_input('Facility:\n')
  hnum  = raw_input('Phone1:\n')
  if hnum == "":
    hnum = "none"
  ph = raw_input('Phone2:\n')
  pg = raw_input('Pager:\n')
  cop= raw_input('Cell:\n')
  com= raw_input('Comments:\n')
  # adds to the existing dictionary from the file
  d1[dname] = (dname, fname, hnum, ph, pg, cop, com)

  f.seek(0)  # rewind to the beginning of the file to write
  # pickle the dictionary back to the file, overwritten the old data
  pickle.dump(d1, f)
  f.close()

The problem here seems to be trying to keep the file and the global
d1 object in sync.  About the only way to do that would be to create a
new dictionary-like class so when the dictonary is updated, the data is
written to the file.  Luckily, there is already something that does that.
Look into the shelve module, it creates a new dictionary like object
which reads and writes pickled Python objects to a file.

With the shelve module, the d1 object could be used in both the add_name()
and get_name() modules, without having to reopen the file each time.

  -Arcege

> import pickle
> 
> def add_name():
>     print 'Enter Name:'
>     dname=raw_input()
>     print 'Facility:'
>     fname=raw_input()
>     print 'phone1:'
>     hnum=raw_input()
>     if hnum == " " :       #in no huntline entered, hunt =NONE
>         hnum='none'
>     print'phone2:'
>     ph=raw_input()
>     print 'Pager:'
>     pg=raw_input()
>     print 'cell:'
>     cop=raw_input()
>     print 'Comments:'
>     com=raw_input()
>     l=(dname, fname, hnum, ph, pg, cop, com)
>     d1[dname]=l
>     f=open('phoneyold','w')
>     pickle.dump(d1,f)
>     f.close()
> 
> 
> 
> def get_name():
>     print "enter name to search"
>     name=raw_input()
>     f=open('phoneyold','r')
>     p_d1=pickle.load(f)
>     if name in p_d1.keys():
>         g= p_d1[name]
>         print 'Name:', g[0]
>         print
>         print 'place:', g[1]
>         print
>         print 'phone1:', g[2]
>         print
>         print 'Phone2:',g[3]
>         print
>         print 'Pager:', g[4]
>         print
>         print 'cell:', g[5]
>         print
>         print 'Comments:',g[6]
>     f.close()
> 
> 
> d1={}
> while 1:
>     print
>     print "Hello, welcome to Docsearch."
>     print
>     print "Please enter selection:"
>     print "Type '1' to search"
>     print
>     print "Type '2' to add name to database or 'quit' to exit"