Altering 1 line in an existing file

Discussion in 'Ruby' started by Jason, Mar 5, 2007.

  1. Jason

    Jason Guest

    I'm in the process of creating an application launcher in ruby. I've hit
    one little hang up though. I want to have the launcher access a file
    containing a log of how many times each application has been run, for
    ranking purposes.

    So far I have the launcher creating the file if it doesn't exist, but
    I'm not clear on how to write to that file or update existing lines in
    it.

    Example of file:

    Firefox Web Browser=7
    Archive Manager=3

    If I create this file manually I'm able to pull the values out and
    manipulate them using the following code:

    #Open "rankings" file
    rankingsFile = File.new("/home/jasbur/.duckduck/rankings")

    #Check each line of "rankings" for existing record, if not assign 1 to
    @rankingToWrite
    rankingsFile.each_line {|line|
    lineMatch = line.match("#{appName.chomp}=")
    if lineMatch
    existingRanking = lineMatch.post_match.to_i
    newRanking = existingRanking + 1
    puts "New Ranking for #{appName.chomp} is
    #{newRanking}"
    else
    @rankingToWrite = 1
    end
    }

    What I want to do is take "newRanking" and overwrite the old ranking
    (existingRanking) in the file. I've seen some people recommend writing a
    whole new file and destroying the old one. It seems like there should be
    a more elegant way of doing this though. Any ideas?

    --
    Posted via http://www.ruby-forum.com/.
     
    Jason, Mar 5, 2007
    #1
    1. Advertising

  2. Jason

    John Carter Guest

    On Mon, 5 Mar 2007, Jason wrote:

    > I'm in the process of creating an application launcher in ruby. I've hit
    > one little hang up though. I want to have the launcher access a file
    > containing a log of how many times each application has been run, for
    > ranking purposes.


    Don't forget the Atomic unit of writing for disk files is a cluster. A
    cluster is 4096 bytes on an ext3 fs (I believe)

    ie. Even if you just wish to change 1 byte on the disk, the disk is
    going to be doing (at least) a 4096 byte write.

    > What I want to do is take "newRanking" and overwrite the old ranking
    > (existingRanking) in the file. I've seen some people recommend writing a
    > whole new file and destroying the old one. It seems like there should be
    > a more elegant way of doing this though. Any ideas?


    If the file is significantly bigger than 4096 bytes, you can divide it
    up into fix length records and to seeks and syswrites.

    Although by the time you get into that sort of thing using a standard
    ISAM library like libgdbm is often best. Ruby has bindings for it.


    John Carter Phone : (64)(3) 358 6639
    Tait Electronics Fax : (64)(3) 359 4632
    PO Box 1645 Christchurch Email :
    New Zealand
     
    John Carter, Mar 5, 2007
    #2
    1. Advertising

  3. Wow, I appreciate the advice. But, I didn't understand much of that.
    Isn't there any way to just do something similar to a gsub and write it
    back?

    --
    Posted via http://www.ruby-forum.com/.
     
    Jason Burgett, Mar 5, 2007
    #3
  4. Jason

    Gary Wright Guest

    On Mar 4, 2007, at 9:08 PM, Jason Burgett wrote:
    > Wow, I appreciate the advice. But, I didn't understand much of that.
    > Isn't there any way to just do something similar to a gsub and
    > write it
    > back?


    It isn't all that complicated. Assume you have a file named
    'counterfile'
    that contains:

    counter: 0

    The file is a single line of text with the 0 appearing at byte offset 9.
    The 'c' in this example is at byte offset 0. Then the following code
    will 'update' the counter by overwriting the file starting at byte
    offset 9.

    File.open('counterfile', 'r+') { |f|
    f.seek(9) # position file at byte offset 9
    f.puts(ARGV[0]) # write the first command line argument to the file
    }


    That is it. Stick that code in a file called 'update' and then run:

    ruby update 100

    Take a look at 'counterfile' and you'll see:

    counter: 100

    Your file has been updated.

    You have to remember that from the OS perspective, a file is simply a
    stream
    of bytes. The OS doesn't really perceive the file as a collection of
    lines of
    text. If you ran that code again and gave '2' as the command line
    argument,
    you're going to end up with a 0 and a newline left over from the
    previous write
    because the '2' and the newline will only replace the 1 and the first
    zero of
    '100'.

    Simply discarding and rewriting a file can often be much simpler than
    figuring out
    how to remember file offsets and arrange for a file to be updated in
    place.
    It can get even more complicated if you are dealing with multi-byte
    text encodings.

    In any case, File#seek is the basic way to move to a new position in
    a file
    is ultimately how random access I/O is implemented.

    Gary Wright
     
    Gary Wright, Mar 5, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Daragoth
    Replies:
    4
    Views:
    616
    Just an Illusion
    Jun 30, 2004
  2. nrm
    Replies:
    3
    Views:
    543
  3. scad
    Replies:
    23
    Views:
    1,183
    Alf P. Steinbach
    May 17, 2009
  4. Replies:
    0
    Views:
    194
  5. Adam Funk
    Replies:
    9
    Views:
    200
    Adam Funk
    May 20, 2009
Loading...

Share This Page