[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Read and re-write file with one open?

Adam Bender

4/30/2009 4:28:00 AM

[Note: parts of this message were removed to make it a legal post.]

I would like to write a Ruby script that opens a text file, performs a gsub
on each line, and then overwrites the file with the updated contents. Right
now I open the file twice: once to read and once to write. The reason for
this is that if I try to perform both operations on the same IO object by
calling io.rewind and writing from the beginning, and the substituted word
is shorter than what it is replacing, some portion of the end of the
original file remains. Is there an idiom for "clearing" the contents of the
file before writing?

Thanks,

Adam

19 Answers

Siddick Ebramsha

4/30/2009 4:56:00 AM

0

Instead of using the rewind method, you can use the reopen method to
open a same file in Write mode.
Example :-
file = File.open( "filename", "r" )
file.reopen( "filename", "w" )
--
Posted via http://www.ruby-....

Gregory Brown

4/30/2009 5:10:00 AM

0

On Thu, Apr 30, 2009 at 12:27 AM, Adam Bender <abender@gmail.com> wrote:
> I would like to write a Ruby script that opens a text file, performs a gs=
ub
> on each line, and then overwrites the file with the updated contents. =A0=
Right
> now I open the file twice: once to read and once to write. =A0The reason =
for
> this is that if I try to perform both operations on the same IO object by
> calling io.rewind and writing from the beginning, and the substituted wor=
d
> is shorter than what it is replacing, some portion of the end of the
> original file remains. =A0Is there an idiom for "clearing" the contents o=
f the
> file before writing?

Yes, but typically this is done by creating a new file and then
renaming it to replace the old one.

Here's an example from my upcoming book "Ruby Best Practices"[0]. It
naively strips comments from source files.
You can modify it to fit your needs.

----------

require "tempfile"
require "fileutils"

temp =3D Tempfile.new("without_comments")
File.foreach(ARGV[0]) do |line|
temp << line unless line =3D~ /^\s*#/
end
temp.close

FileUtils.cp(ARGV[0],"#{ARGV[0]}.bak") # comment out if you don't want back=
ups.
FileUtils.mv(temp.path,ARGV[0])

----------

-greg

PS: sorry for the shameless book plug, but it really might be helpful
for questions like these. :)


[0] http://rubybestpra...

7stud --

4/30/2009 5:26:00 AM

0

Adam Bender wrote:
> I would like to write a Ruby script that opens a text file, performs a
> gsub
> on each line, and then overwrites the file with the updated contents.
> Right
> now I open the file twice: once to read and once to write. The reason
> for
> this is that if I try to perform both operations on the same IO object
> by
> calling io.rewind and writing from the beginning, and the substituted
> word
> is shorter than what it is replacing, some portion of the end of the
> original file remains. Is there an idiom for "clearing" the contents of
> the
> file before writing?
>

Yes, opening the file in write mode! However, you are going to expose
yourself to this catastrophe. Suppose you read the contents of the
file into a variable, then open the file for writing, which then erases
the file, but immediately thereafter your program crashes or the power
goes out in your city. What are you left with? You will be left with
an empty file, and the variable that contained the contents of the file
will have evaporated into the ether. In other words, you will lose all
your data!

So the idiom for rewriting a file is:

1) Open the file for *reading*.
2) Open another file for writing with a name like origName-edited.txt
3) Read the original file line by line(saves memory, but is slower)
4) Write each altered line to the file origName-edited.txt
5) Delete the original file.
6) Change the name of the new file (origName-edited.txt) to origName.txt









--
Posted via http://www.ruby-....

Adam Bender

4/30/2009 7:12:00 AM

0

[Note: parts of this message were removed to make it a legal post.]

On Thu, Apr 30, 2009 at 1:26 AM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

> Yes, opening the file in write mode! However, you are going to expose
> yourself to this catastrophe. Suppose you read the contents of the
> file into a variable, then open the file for writing, which then erases
> the file, but immediately thereafter your program crashes or the power
> goes out in your city.
>
> So the idiom for rewriting a file is:
>
> 1) Open the file for *reading*.
> 2) Open another file for writing with a name like origName-edited.txt
> 3) Read the original file line by line(saves memory, but is slower)
> 4) Write each altered line to the file origName-edited.txt
> 5) Delete the original file.
> 6) Change the name of the new file (origName-edited.txt) to origName.txt


I see the potential for catastrophe with the way I suggested, however, there
is potential for catastrophe here if there is already an
"origName-edited.txt" file (I know, slim chance, but you never know). You
could get around this by generating new file names until you found one that
didn't exist, or writing to /tmp, of course. I think I'll switch to Greg
Brown's suggestion. Does Tempfile guarantee that it won't overwrite an
existing file?

Adam

7stud --

4/30/2009 7:55:00 AM

0

Adam Bender wrote:
> On Thu, Apr 30, 2009 at 1:26 AM, 7stud -- <bbxx789_05ss@yahoo.com>
> wrote:
>
>> 3) Read the original file line by line(saves memory, but is slower)
>> 4) Write each altered line to the file origName-edited.txt
>> 5) Delete the original file.
>> 6) Change the name of the new file (origName-edited.txt) to origName.txt
>
>
> I see the potential for catastrophe with the way I suggested, however,
> there
> is potential for catastrophe here if there is already an
> "origName-edited.txt" file (I know, slim chance, but you never know).
>

Of course, if that was a possibility then you would take extra measures
like create a new file name with rand, and then check it with
File.exists?, which is probably what Tempfile does.

> Does Tempfile guarantee that it won't overwrite an
existing file?

What the standard library docs aren't clear enough for you:

----
tempfile - manipulates temporary files
----

???!! lol. pathetic. But once in a great while you can actually find
some information on a standard library module using google:

http://www.rubytips.org/2008/01/11/using-temporary-files-in-ruby-te...

--
Posted via http://www.ruby-....

Robert Klemme

4/30/2009 9:08:00 AM

0

2009/4/30 Gregory Brown <gregory.t.brown@gmail.com>:
> On Thu, Apr 30, 2009 at 12:27 AM, Adam Bender <abender@gmail.com> wrote:
>> I would like to write a Ruby script that opens a text file, performs a g=
sub
>> on each line, and then overwrites the file with the updated contents. =
=A0Right
>> now I open the file twice: once to read and once to write. =A0The reason=
for
>> this is that if I try to perform both operations on the same IO object b=
y
>> calling io.rewind and writing from the beginning, and the substituted wo=
rd
>> is shorter than what it is replacing, some portion of the end of the
>> original file remains. =A0Is there an idiom for "clearing" the contents =
of the
>> file before writing?
>
> Yes, but typically this is done by creating a new file and then
> renaming it to replace the old one.
>
> Here's an example from my upcoming book "Ruby Best Practices"[0]. =A0It
> naively strips comments from source files.

A variant exploiting Ruby's command line parameters:

11:05:08 Temp$ ruby -e '10.times {|i| puts i}' >| x
11:05:22 Temp$ cat x
0
1
2
3
4
5
6
7
8
9
11:05:23 Temp$ ./x.rb x
11:05:29 Temp$ cat x
<<<0>>>
<<<1>>>
<<<2>>>
<<<3>>>
<<<4>>>
<<<5>>>
<<<6>>>
<<<7>>>
<<<8>>>
<<<9>>>
11:05:34 Temp$ cat x.bak
0
1
2
3
4
5
6
7
8
9
11:05:37 Temp$ cat x.rb
#!/opt/bin/ruby19 -pi.bak

$_.sub! /^/, '<<<'
$_.sub! /$/, '>>>'
11:05:40 Temp$

Kind regards

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestprac...

Gregory Brown

4/30/2009 1:59:00 PM

0

On Thu, Apr 30, 2009 at 3:11 AM, Adam Bender <abender@gmail.com> wrote:

> I see the potential for catastrophe with the way I suggested, however, th=
ere
> is potential for catastrophe here if there is already an
> "origName-edited.txt" file (I know, slim chance, but you never know). =A0=
You
> could get around this by generating new file names until you found one th=
at
> didn't exist, or writing to /tmp, of course. =A0I think I'll switch to Gr=
eg
> Brown's suggestion. =A0Does Tempfile guarantee that it won't overwrite an
> existing file?

Yes, Tempfile avoids file collisions.

-greg

James Dinkel

4/30/2009 2:41:00 PM

0

Gregory Brown wrote:
>
> Here's an example from my upcoming book "Ruby Best Practices"[0]. It
> naively strips comments from source files.
> You can modify it to fit your needs.
>
> ----------
>
> require "tempfile"
> require "fileutils"
>
> temp = Tempfile.new("without_comments")
> File.foreach(ARGV[0]) do |line|
> temp << line unless line =~ /^\s*#/
> end
> temp.close
>
> FileUtils.cp(ARGV[0],"#{ARGV[0]}.bak") # comment out if you don't want
> backups.
> FileUtils.mv(temp.path,ARGV[0])
>
> ----------
>
> -greg

What about if another program opens the file after it has been read by
the Ruby program but before the Ruby program has copied the temp file?
If the second program makes a change and saves it, those changes will be
lost when the Ruby program copies the temp file over it. Or if the
second program still has it open and the Ruby program finishes, then
when the second program saves it's open file, it will overwrite the Ruby
program's changes.
--
Posted via http://www.ruby-....

Gregory Brown

4/30/2009 2:54:00 PM

0

On Thu, Apr 30, 2009 at 10:41 AM, James Dinkel <jdinkel@gmail.com> wrote:

> What about if another program opens the file after it has been read by
> the Ruby program but before the Ruby program has copied the temp file?
> If the second program makes a change and saves it, those changes will be
> lost when the Ruby program copies the temp file over it. =A0Or if the
> second program still has it open and the Ruby program finishes, then
> when the second program saves it's open file, it will overwrite the Ruby
> program's changes.

Is this related to the OP's concerns? In this case, you'd need file
locking (see the Ruby API).
But I didn't see any mention of these sorts of issues in Adam's original po=
st.

If you need this feature, read the API docs for File#flock

-greg

timr

5/1/2009 6:58:00 PM

0

On Apr 29, 9:27 pm, Adam Bender <aben...@gmail.com> wrote:
> [Note:  parts of this message were removed to make it a legal post.]
>
> I would like to write a Ruby script that opens a text file, performs a gsub
> on each line, and then overwrites the file with the updated contents.  Right
> now I open the file twice: once to read and once to write.  The reason for
> this is that if I try to perform both operations on the same IO object by
> calling io.rewind and writing from the beginning, and the substituted word
> is shorter than what it is replacing, some portion of the end of the
> original file remains.  Is there an idiom for "clearing" the contents of the
> file before writing?
>
> Thanks,
>
> Adam