# Why writing the file is partial

**URL:** <https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744>\
**Category:** Ruby\
**Created:** [June 13, 2007, 6:58pm UTC](https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744 "2007-06-13T18:58:48Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [June 13, 2007, 6:58pm UTC](https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744/1 "2007-06-13T18:58:48Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [June 13, 2007, 7:20pm UTC](https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744/2 "2007-06-13T19:20:53Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [June 13, 2007, 7:50pm UTC](https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744/3 "2007-06-13T19:50:58Z")

</div>

On 6/13/07, Robert K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [June 13, 2007, 8:05pm UTC](https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744/4 "2007-06-13T20:05:20Z")

</div>

> 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

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [June 13, 2007, 8:17pm UTC](https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744/5 "2007-06-13T20:17:04Z")

</div>

On 6/13/07, Li Chen [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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/](http://talklikeaduck.denhaven2.com/)

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [June 13, 2007, 11:31pm UTC](https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744/6 "2007-06-13T23:31:42Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![alex-osu3](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/13edae/32.png) [@alex-osu3](https://www.ruby-forum.com/u/alex-osu3)\
**Post date:** [July 30, 2007, 10:45pm UTC](https://www.ruby-forum.com/t/why-writing-the-file-is-partial/106744/7 "2007-07-30T22:45:57Z")

</div>

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
