2010-12-19 4 views
8

Est-il possible avec les bibliothèques perl standard d'ouvrir un fichier et de le modifier, sans avoir à le fermer, puis de le rouvrir? Tout ce que je sais faire c'est soit lire un fichier dans une chaîne ferme le fichier puis écraser le fichier avec un nouveau; ou lisez et ensuite ajoutez à la fin d'un fichier.Ouvrir le fichier pour lire et écrire (sans ajout) dans perl

Ce qui suit fonctionne actuellement mais; Je dois l'ouvrir et le fermer deux fois, au lieu d'une fois:

#!/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 
    } 
} 
+0

1k + vues et 1 seule mise à jour. . . – GlassGhost

+0

2 upvotes maintenant: D – GLES

Répondre

15

Vous avez déjà ouvert le fichier pour la lecture et l'écriture en ouvrant avec le mode <+, vous êtes tout simplement pas faire quelque chose d'utile - Si vous souhaitez remplacer le contenu du fichier au lieu d'écrire à la position actuelle (la fin du fichier), vous devez retourner au début, écrire ce que vous devez, puis truncate pour vous assurer qu'il ne reste plus rien si vous avez raccourci le fichier.

Mais puisque ce que vous essayez de faire est le filtrage in situ d'un fichier, est-ce que je pourrais vous suggérer d'utiliser l'extension d'édition de perl, au lieu de faire tout le travail vous-même?

#!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; 
    } 
} 

Et c'est tout le code dont vous avez besoin - Perl gère le reste. La définition de $^I variable équivaut à l'utilisation de -i commandline flag. J'ai fait plusieurs changements à votre code en cours de route - use utf8 ne fait rien pour un programme sans littéral UTF-8 dans la source, binmode ing stdin et stdout ne fait rien pour un programme qui n'utilise jamais stdin ou stdout, sauvegarder le CWD ne fait rien pour un programme qui n'est jamais chdir s. Il n'y avait aucune raison de lire chaque fichier en une fois, donc je l'ai changé en ligne, et j'ai rendu les expressions rationnelles moins gênantes (et accessoirement, le modificateur regex /o est bon pour presque rien aujourd'hui, excepté l'ajout de bogues difficiles à trouver à votre code).

+1

+1 pour '$^I' :-) – friedo

+0

@hobbs, Le processus est basé sur une ligne. Que faire si je veux utiliser regexp qui contient newline? – solotim

+1

@solotim dépend des détails. Vous pouvez changer '$ /' pour quelque chose de plus approprié que '" \ n "' - en particulier, si vous définissez '$ /' à 'undef' alors perl lira tout le contenu du fichier en une seule lecture, les modifier, puis réécrire. La mémoire est assez grande pour que ce soit une approche raisonnable pour de nombreux fichiers. Mais si ce n'est pas le cas, vous devrez faire le travail vous-même. – hobbs

Questions connexes