首页 > 解决方案 > 如何检查文件内容并根据检查条件添加或更新文件?

问题描述

我对 Perl 很陌生,我需要编写一个 Perl 脚本来执行以下操作:

  1. 递归遍历一个目录并且只处理具有特定扩展名的文件(例如.txt)。
  2. 对于每个 .txt 文件,我需要在文件前面添加一个标题,或者如果标题已经存在,则更新标题。

标题看起来像这样:

//-----------------------------------------//
  Model : Info1
  Date  : Info2 
  Name  : Info3
//-----------------------------------------//

到目前为止我做了什么:

use File::Find;
use Cwd qw(getcwd);
use strict;

sub gen_header {
   my $divider = "//------------------------------------//\n";
   my $time = localtime();
   my $modelpath = getcwd();
   my $user = (getpwuid($<))[0];
   
   my $header;
   $header .= $divider;
   $header .= "//Model         : $modelpath\n";
   $header .= "//Date          : $time\n";
   $header .= "//Name          : $user\n";
   $header .= $divider;
   $header .= "\n";
   return header;
}

my $dir = "/src/dir1";
find (\&process_file, $dir);

sub process_file {
   my $filename = $_;
   my $out_file = $_.out;
   if (-f and /\.(txt)$/) {

      open (my $fh1, "<", $filename) || die "ERROR";
      open (my $fh2, ">", $out_file) || die "ERROR";
      
      if  (*header already exist*) {
         #Update header
         *code to update Info1, Info2 and Info3 in the header;*
      } else {
         #Prepend the header
         print $fh2 gen_header();
         while (<$fh1>) {
            print $fh2 $_;
         }
      }
      close $fh2;
      rename ($out_file, $filename) or die "Rename error";
   }
}

我设法创建了一个子例程来生成所需的标头,并且我想相信我递归遍历目录和处理文件的方式是正确的。不过,在那之后我很难弄清楚如何更新标题。所以问,

  1. 如何执行代码的“更新标头”部分?gen_header 子例程每次运行时都会返回一个带有最新信息的新标头,但是如何使用它来替换旧标头?
  2. 我递归遍历目录和处理文件的方式是正确的,还是有更好的方法来做我想做的事?

标签: perlfile-handling

解决方案


在没有看到您如何获取“标题”详细信息的情况下,我无法更具体。

但是,根据您迄今为止提供的内容:

如何执行代码的“更新标头”部分?gen_header 子例程每次运行时都会返回一个带有最新信息的新标头,但是如何使用它来替换旧标头?

你说你正在更新一个标题,所以我假设它已经存在。

但:

open ( my $input, '<', "existing_file" ) or die $!;
open ( my $output, '>', "new_file" ) or die $!;
select $output; 
print $my_new_header; # will go to $output

my $seen; 
while ( <$input> ) {
   m,//-----, && $seen++;  
   #this will skip until the second instance of '//-----' in your file, 
   # so it'll 'eat' the whole file if there's no header at all. 
   next unless $seen >= 2; 
   print; 
}

或者,如果您可以可靠地检测到标头的存在,您可以使用搜索和替换执行相同的方法:

while ( <$input> ) {
   s/Model\s+: .*/Model : $my_model/;
  # etc.
  print;
}

注意:如果您的开始和结束标记略有不同,您可以使用if ( m,//---, .. m,//--, ) {类型语法,但如果两个匹配项相同,这将不起作用。

我递归遍历目录和处理文件的方式是正确的,还是有更好的方法来做我想做的事?

File::Find 是完成这项工作的工具,你正在做的事情很好。

虽然你是在(txt)不必要地捕捉,但这是一件相当小的事情。

if (-f and /\.(txt)$/) {

除非您出于某种原因需要包含“txt”,否则出于清楚的原因$1,您最好使用。/\.txt$/


推荐阅读