Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

Changing data with syswrite ?

by pbyfire (Novice)
on Apr 27, 2012 at 22:10 UTC ( #967726=perlquestion: print w/replies, xml ) Need Help??
pbyfire has asked for the wisdom of the Perl Monks concerning the following question:

So, I am attempting to read all binary files in a directory, seek to a header section, advance the position 94 bytes, and then change the next 10 bytes. With all of my research I have gotten close with the code below but syswrite is looking for numeric information. I should probably also be performing the replacement on a copy of the file but it could be added later. Anyone who knows the simplest method of replacing the 10 bytes in the syswrite statement has my appreciation and thanks.

#!/usr/bin/perl use strict; use warnings; use Data::HexDump; my $tktdir = "/home/bkirch/PERL_LSN/TICKETS"; my $file; my $offset; opendir(TKS, $tktdir) || die "Oops ... $!"; my @files = readdir TKS; close TKS; foreach my $file (@files) { open(FH,"+<$tktdir/$file") or die "Oops - Cant open ticket $!"; binmode FH; while (<FH>) { if (/SCSI:INQ:80/) { $offset = tell (FH); # print "$offset\n"; #seek (FH, $offset, 94); seek (FH, $offset, 94); $offset = tell (FH); # print "$offset\n"; #read(FH, $SN, 10); sysread (FH, $offset, 10); # print "$offset\n"; my $BUF = ""; syswrite (FH, $BUF, 10, $offset); print "$BUF\n"; # s[$offset][TEST123456]g; } } }

Thanks JavaFan and graff for responding to my question. You can tell I am a beginner by the print debug statements in the code. When the code is run it checks the binary file for the pattern match and the first instance of "tell" actually places a pointer at the first instance of "S" in SCSI. seek moves the pointer forward 94 bytes and the second instance of tell resets the pointer at the beginning character of the data to be replaced. This is verified by the (commented out read statement when the program is run). In trying JavaFan's solution I run into errors (on Windows) with regard to the options used (-pi -e). I hope to run this routine on both Windows and Linux. I will keep trying but again thanks for your suggestions. -pbyfire

Replies are listed 'Best First'.
Re: Changing data with syswrite ?
by JavaFan (Canon) on Apr 27, 2012 at 23:04 UTC
    There are a number of problems:
    1. At the moment you use tell, you get the position the file pointer is: at the end of the current line. The regexp match does not influence that.
    2. seek takes three arguments, a file pointer (FH), a position to seek to, and an argument which determines how that position should be interpreted: from the beginning of the file, from the end, or from the current position. Your arguments don't make sense.
    3. A sysread advances the filepointer as well. If you want to replace the 10 characters you read, you got to seek 10 positions back before doing your syswrite.
    4. Your $BUF is empty -- shouldn't that contain at least 10 characters?
    5. As the documentation of sysread says: sysread uses unbuffered I/O, don't mix it with buffered. Do not use sysread when you also use <>.
    6. You are trying to open (as a file) anything in the directory, including . and ...

    Perhaps the following works for you (untested):

    $ perl -0777 -pi -e 's/(SCSI:INQ:80.{94}).{10}/${1}TEST123456/sg' /hom +e/bkirch/PERL_LSN/TICKETS/*
Re: Changing data with syswrite ?
by graff (Chancellor) on Apr 28, 2012 at 19:12 UTC
    I like JavaFan's one-liner solution, provided that the assumptions it makes are suitable to your situation. It assumes that each file isn't too big to fit in memory, that the 10 bytes you want to replace will need to have the same replacement value in all files, and that all files of interest have names that don't begin with ".".

    If the replacement value needs to vary from one file to the next (and assuming you have a way for a perl script to work that out), it would be easiest to use JavaFan's method: for a given file, slurp it into a single scalar (e.g. $_), apply a regex replacement, and write a new copy of the file.

    If your files are actually too big (which these days means more than a gigabyte or two per file), you'll want to use the read and write functions (rather than "sysread" and "syswrite"); that way, you'll be using buffered i/o in all operations. Follow JavaFan's advice (and read the man pages, too) about how and when to use "tell" and "seek"; depending on what's supposed to go into those 10 bytes that you're replacing, you might need to use pack.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://967726]
Front-paged by Corion
[yash1337]: kl

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (6)
As of 2017-04-30 19:34 GMT
Find Nodes?
    Voting Booth?
    I'm a fool:

    Results (542 votes). Check out past polls.