Why writing the file is partial

Hi all,

Thank you for your valuable inputs for my previous post.

Right now I encounter another odd situation. I want to search some
strings and replace them all in place. ButI can partially update/replace
part of them. I wonder if any experts there can explain it.

Li

And here are my codes:

my_direrctory=“C:\flow\test”

pat=/2.000000\$P1G\2.000000/
sub=‘1.000000$P1G\\1.000000’

Dir.chdir(my_direrctory)
Dir.foreach(my_direrctory) do |filename| #return a file name
next if filename=~/^./ # skip . and …
my_file_path=my_direrctory+"\"+filename #get absolute file name
File.open( my_file_path,“r+”) do |file| #pass a file to the block
file.each_line do |line|
if pat.match(line)
line.gsub!(pat,sub) #replace the line in place
file.print line #write/update the file
end
end
end
end

#####input file format###
test.001
xxx\2.000000$P1G\2.000000\xxx
xxx\2.000000$P1G\2.000000\xxx
xxx\2.000000$P1G\2.000000\xxx
xxx\2.000000$P1G\2.000000\xxx

the updated file###

test.001
xxx\2.000000$P1G\2.000000\xxx
xxx\1.000000$P1G\1.000000\xxx
xxx\2.000000$P1G\2.000000\xxx
xxx\1.000000$P1G\1.000000\xxx

On 13.06.2007 18:58, Li Chen wrote:

And here are my codes:
File.open( my_file_path,“r+”) do |file| #pass a file to the block
test.001
xxx\2.000000$P1G\2.000000\xxx
xxx\1.000000$P1G\1.000000\xxx

Reading and writing one file at the time is a dangerous thing to do -
especially if pattern and replacement can have different lengths. If
you want to do it properly, then you need to #seek before you switch
from reading to writing and back AFAIK. But I’d use a temporary file,
this is much safer. Then you can even do it in a one liner:

ruby -i.bak -pe ‘gsub /pattern/, “replacement”’ your_file1 your_file2

Kind regards

robert

On 6/13/07, Robert K. [email protected] wrote:

On 13.06.2007 18:58, Li Chen wrote:

xxx\2.000000$P1G\2.000000\xxx
xxx\1.000000$P1G\1.000000\xxx
xxx\2.000000$P1G\2.000000\xxx
xxx\1.000000$P1G\1.000000\xxx

Reading and writing one file at the time is a dangerous thing to do -
especially if pattern and replacement can have different lengths. If
you want to do it properly, then you need to #seek before you switch
from reading to writing and back AFAIK.

Right, I think what’s happening here is that he reads the first line,
the file cursor is positioned after the first line, so he overwrites
the SECOND line with the updated first line, and is now positioned at
the end of the second line, etc. etc.

He needs to seek back to the beginning of the line before he writes:

    file.each_line do |line|
           if pat.match(line)
                 line.gsub!(pat,sub)  #replace the line in place
                 file.seek(-line.length, IO::SEEK_CUR)
                 file.print line    #write/update the file
           end
    end
 end

But this will only work in the case where the replacement is the same
length at the original, if you you’re either going to leave stuff
behind, or will overwrite the next line. In either case you’re more
likely to end up with gibberish than something you like.

But I’d use a temporary file,
this is much safer.

Amen, and it will preserve the original file “just in case” you have
to debug the program.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

He needs to seek back to the beginning of the line before he writes:

    file.each_line do |line|
           if pat.match(line)
                 line.gsub!(pat,sub)  #replace the line in place
                 file.seek(-line.length, IO::SEEK_CUR)
                 file.print line    #write/update the file
           end
    end
 end

But this will only work in the case where the replacement is the same
length at the original, if you you’re either going to leave stuff
behind, or will overwrite the next line. In either case you’re more
likely to end up with gibberish than something you like.

What am I supposed to do if the replacement is not same size?

Thanks,

Li

On 6/13/07, Li Chen [email protected] wrote:

But this will only work in the case where the replacement is the same
length at the original, if you you’re either going to leave stuff
behind, or will overwrite the next line. In either case you’re more
likely to end up with gibberish than something you like.

What am I supposed to do if the replacement is not same size?

Write to another file, then rename when you are done.

This is standard posix practice.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 13.06.2007 20:16, Rick DeNatale wrote:

Write to another file, then rename when you are done.

This is standard posix practice.

And you can even do it in a one liner. See ruby’s command line options
-i and -p. You can then do

ruby -i.bak -pe ‘gsub /…/, “…”’ file

Kind regards

robert

Rick Denatale wrote:

He needs to seek back to the beginning of the line before he writes:

    file.each_line do |line|
           if pat.match(line)
                 line.gsub!(pat,sub)  #replace the line in place
                 file.seek(-line.length, IO::SEEK_CUR)
                 file.print line    #write/update the file
           end
    end
 end

But this will only work in the case where the replacement is the same
length at the original, if you you’re either going to leave stuff
behind, or will overwrite the next line. In either case you’re more
likely to end up with gibberish than something you like.

HI Rick,

Now I work on a small project with deals with process files and upgrade
the them in place. Just as you point out the #seek only works if the
replacement is the same as the original. And the replacement will get
unpredictalbe results or fail if the length is different. I wonder if
other methods are available for this situation in Ruby?

Thanks,

Li