Open file for reading and writing(not appending) in 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){
开发者_如何学JAVA 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
}
}
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, binmode
ing stdin and stdout does nothing for a program that never uses stdin or stdout, saving the CWD does nothing for a program that never chdir
s. 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).
精彩评论