Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open file for reading and writing(not appending) in perl

Tags:

file

file-io

perl

Is there any way with the standard perl libraries to open a file and edit it, without having to close it then open it again? All I know how to do is to either read a file into a string close the file then overwrite the file with a new one; or read and then append to the end of a file.

The following currently works but; I have to open it and close it twice, instead of once:

#!/usr/bin/perl
use warnings; use strict;
use utf8; binmode(STDIN, ":utf8"); binmode(STDOUT, ":utf8");
use IO::File; use Cwd; my $owd = getcwd()."/"; # OriginalWorkingDirectory
use Text::Tabs qw(expand unexpand);
$Text::Tabs::tabstop = 4; #sets the number of spaces in a tab

opendir (DIR, $owd) || die "$!";
my @files = grep {/(.*)\.(c|cpp|h|java)/}  readdir DIR;
foreach my $x (@files){
    my $str;
    my $fh = new IO::File("+<".$owd.$x);
    if (defined $fh){
        while (<$fh>){ $str .= $_; }
        $str =~ s/( |\t)+\n/\n/mgos;#removes trailing spaces or tabs
        $str = expand($str);#convert tabs to spaces
        $str =~ s/\/\/(.*?)\n/\/\*$1\*\/\n/mgos;#make all comments multi-line.
        #print $fh $str;#this just appends to the file
        close $fh;
    }
    $fh = new IO::File(" >".$owd.$x);
    if (defined $fh){
        print $fh $str; #this just appends to the file
        undef $str; undef $fh; # automatically closes the file
    }
}
like image 602
GlassGhost Avatar asked Dec 19 '10 04:12

GlassGhost


People also ask

How do you open a file in read/write and append mode in Perl?

If you want to open a file for reading and writing, you can put a plus sign before the > or < characters. open DATA, "+>file. txt" or die "Couldn't open file file.

How do I open a file for reading in Perl script?

You use open() function to open files. The open() function has three arguments: Filehandle that associates with the file. Mode : you can open a file for reading, writing or appending.

How do I open a file for writing in Perl?

In order to write to the file, it is opened in write mode as shown below: open (FH, '>', “filename. txt”); If the file is existing then it truncates the old content of file with the new content.

How do you read and write in the same file in Perl?

FreeKB - Perl (Scripting) Read and write to the same file. Perl's approach to reading and writing to the same file is to store the current file into an array or a temporary file, to update the array or temporary file, and to then replace the original file with the updated array or temporary file.


1 Answers

You already opened the file for reading and writing by opening it with the mode <+, you're just not doing anything useful with it -- if you wanted to replace the contents of the file instead of writing to the current position (the end of the file) then you should seek back to the beginning, write what you need to, and then truncate to make sure that there's nothing left over if you made the file shorter.

But since what you're trying to do is inplace filtering of a file, might I suggest that you use perl's inplace editing extension, instead of doing all of the work yourself?

#!perl
use strict;
use warnings;
use Text::Tabs qw(expand unexpand);
$Text::Tabs::tabstop = 4;

my @files = glob("*.c *.h *.cpp *.java");

{
   local $^I = ""; # Enable in-place editing.
   local @ARGV = @files; # Set files to operate on.
   while (<>) {
      s/( |\t)+$//g; # Remove trailing tabs and spaces
      $_ = expand($_); # Expand tabs
      s{//(.*)$}{/*$1*/}g; # Turn //comments into /*comments*/
      print;
    }
}

And that's all the code you need -- perl handles the rest. Setting the $^I variable is equivalent to using the -i commandline flag. I made several changes to your code along the way -- use utf8 does nothing for a program with no literal UTF-8 in the source, binmodeing stdin and stdout does nothing for a program that never uses stdin or stdout, saving the CWD does nothing for a program that never chdirs. There was no reason to read each file in all at once so I changed it to linewise, and made the regexes less awkward (and incidentally, the /o regex modifier is good for almost precisely nothing these days, except adding hard-to-find bugs to your code).

like image 132
hobbs Avatar answered Oct 13 '22 19:10

hobbs