Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

File I/O

by ced4dad (Initiate)
on Sep 23, 2003 at 20:55 UTC ( [id://293676]=perlquestion: print w/replies, xml ) Need Help??

ced4dad has asked for the wisdom of the Perl Monks concerning the following question:

I am a programmer of many years but have not previously had the need to venture into Perl. I have found it so far to be very complete and straight forward but can't seem to find an answer to this: It seems that the file I/O is to sequential text files. Is there an easy way to replace a record in the middle of the file other than reading them in record by record, rewriting them to a new file, changing and writing the record desired and then rewriting all of the following records, then deleting the old file and renaming the new file to the old name? From what I can find in documentation, that appears to be A way but is there a better one?

Replies are listed 'Best First'.
Re: File I/O
by davido (Cardinal) on Sep 23, 2003 at 21:20 UTC
    This is straight out of the Perl Cookbook:

    "Problem: You want to read in an old record from a binary file, change its values, and write back the record.
    Solution: After reading the old record, pack up the updated values, seek to the previous address, and write it back.
    "

    And here is the accompanying style-challenged snippet, also directly from the Perl Cookbook:

    use Fcntl; # for SEEK_SET and SEEK_CUR $ADDRESS = $RECSIZE * $RECNO; seek(FH, $ADDRESS, SEEK_SET) or die "Seeking: $!"; read(FH, $BUFFER, $RECSIZE) == $RECSIZE or die "Reading: $!"; @FIELDS = unpack ($FORMAT, $BUFFER); #update fields, then $BUFFER = pack($FORMAT, @FIELDS); seek(FH, -$RECSIZE, SEEK_CUR) or die "Seeking: $!"; print FH $BUFFER; close FH or die "Closing: $!";

    Even better answers can be found in the perldocs, perlfaq5 under the topics "How can I manipulate fixed-record-length files?" and "How do I randomly update a binary file?"

    Check into those online resources first (rather than just grabbing the Perl Cookbook's snippet); they will give you the best description, and a good understanding of the topic.

    Hope this helps...

    Dave

    "If I had my life to do over again, I'd be a plumber." -- Albert Einstein

Re: File I/O
by BrowserUk (Patriarch) on Sep 23, 2003 at 21:27 UTC

    Depends upon your definition of a "record". If your file contains fixed length records then is is fairly trivial to use perlfunc:seek and perlfunc:tell to position the file pointer to a specific record and overwrite the data in-place.

    However, as most PC based filesystems do not have fixed-length record filetypes built-in as many mainframes do, fixed length records are fairly few and far between in the PC world. Most files therefore variable length "records", which means that you have to scan the file sequentially and remember the start position and length of each record as you go. It also means that you have to re-write every subsequent record unless your update is exactly the same length as the preceeding one.

    However, the saving grace is that this has been done before, and being perl, that code is available to you on CPAN. Take a look at Tie::File. If your using a reasonably modern version of perl, this probably came with your distribution. It allows you to treat a file of fixed or variable length records as an array and takes care of all the file pointer shuffling and throws in some intelligent buffering to boot.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

      fixed length records are fairly few and far between in the PC world.

      God I wish. :-(


      ---
      demerphq

        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi


        I meant fixed length in the mainframe sense of records addressable (directly and only) by record number.

        Fixed length records on PC's are (for the most part) only variable length bits of a stream that all happen (even by design) to be the same length. There is nothing to stop you from positioning the pointer to mid record before reading or writing, and completely corrupting the record structure in the process.

        What's the reason for you frowny? Assuming your fixed-length records are delimited with newlines, you can just as easily process them as you would variable length records with the added bonus of being able to index you way directly to a given record. Even if they are not delimited, setting $/ = \80; or whatever the fixed length is, allows you to read them just as easily.

        I don't see the problem?


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
        If I understand your problem, I can solve it! Of course, the same can be said for you.

Re: File I/O
by sgifford (Prior) on Sep 23, 2003 at 21:17 UTC

    Use seek to go to the place where you want, then print the data you want (which doesn't have to be line-formatted).

    To read a record, again use seek then read it with read.

    To find out where you are in a file, use tell.

    If you want to avoid stdio's buffering, use sysopen, syswrite, sysseek, and sysread.

    All of these functions are outlined in the perlfunc manpage, or by running perldoc -f funcname.

Re: File I/O
by sandfly (Beadle) on Sep 23, 2003 at 23:09 UTC
    It is also easy to create and use keyed files in the Berkeley DB format - check out the DB_File module (it's in the standard distribution).

    Perhaps off-topic, DBD::SQLite is a CPAN module which implements a relational-database-in-a-file. There's a brief discussion of it in www.perl.com.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://293676]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (2)
As of 2024-04-25 06:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found