合并Perl中的txt文件,但之前要修改它们,保持原始文件不变

时间:2014-12-03 14:19:19

标签: perl

我已经发布了一个问题并在我的代码中修复了问题,但现在我的"规范已经改变了#34;所以说,现在我需要改变一些事情。

这里有一个代码,它从当前目录获取所有.txt文件,切断第一个文件的最后一行,每个后续文件的第一行和最后一行以及最后一个文件的第一行并写入新文件中的所有内容(换句话说:合并所有文件,删除页眉和页脚,以便新文件只有一个页眉和一个页脚)。

#!/usr/bin/perl
use warnings;
use Cwd;
use Tie::File;
use Tie::Array;
my $cwd = getcwd();
my $buff = '';

# Get all files in cwd.
my @files = grep ( -f ,<*.txt>);

#  Cut off header and footer of $files [1] to $files[$#files-1], 
#  but only footer of $files[0] and header of $#files[$#files]
for (my $i = 0; $i <= $#files; $i++) {

    print 'Opening ' . $files[$i] . "\n";

    tie (@lines, Tie::File, $files[$i]) or die "can't update $file: $!";
    splice @lines, 0, 1 unless $i == 0;
    splice @lines, -1, 1 unless $i == $#files;
    untie @lines;

    open (file, "<", $files[$i]) or die "can't update $file: $!";

    while (my $line =<file>) {
        $buff .= $line;
    }
    close file;

}

# Write the buffer to a new file.
my $allfilename = $cwd.'/Trace.txt';
print 'Writing all files into new file: ' . $allfilename . "\n";

open $outputfile, ">".$allfilename or die "can't write to new file $outputfile: $!";
# Write the buffer into the output file.
print $outputfile $buff;

close $outputfile;

我的问题:我想要更改原始文件,但我的代码确实如此,而且我无法提出解决方案。现在最简单的方法(简单意思是不需要更改太多代码),只需将所有文件复制到tmp目录,弄乱它们并保持原始文件不变。问题:简单地使用dircopy并不适合我,因为你必须为dircopy函数提供一个新的tmp目录,使代码只能用于Windows或UNIX系统(但我需要可移植性)。

接下来的方法是使用File :: Temp模块,但我真的遇到了关于这个问题的文档。

有人对这个有好主意吗?

4 个答案:

答案 0 :(得分:1)

#!/usr/bin/env perl

use strict;
use warnings;
use autodie;

my $outfile = 'Trace.txt';

# Get all files in cwd.
my @files = grep { -f && $_ ne $outfile } <*.txt>;

open my $outfh, '>', $outfile;

for my $file (@files) {
    my @lines = do { local @ARGV = $file; <> };

    shift @lines unless $file eq $files[0];
    pop @lines   unless $file eq $files[-1];

    print $outfh @lines;
}

答案 1 :(得分:1)

我怀疑您在回答your previous question时确实不想修改原始文件。

我不明白为什么你在打印之前回过头来累积缓冲区中的所有文本,或者为什么你删除了use strict,这对于任何编写良好的Perl代码都是必不可少的。< / p>

这是我之前的解决方案,修改后保持输入数据不变。

use strict;
use warnings;

use Tie::File;

my @files = grep -f, glob '*.txt';

my $all_filename = 'Trace.txt';
open my $out_fh, '>', $all_filename or die qq{Unable to open "$all_filename" for output: $!};

for my $i ( 0 .. $#files ) {

  my $file = $files[$i];
  next if $file eq $all_filename;

  print "Opening $file\n";

  tie my @lines, 'Tie::File', $file or die qq{Can't open "$file": $!};
  my ($start, $end) = (0, $#lines);
  ++$start unless $i == 0;
  --$end   unless $i == $#files;

  print $out_fh "$_\n" for @lines[$start..$end];
}

close $out_fh;

答案 2 :(得分:0)

只是不要使用Tie :: File。或者你有没有理由这样做,例如你的所有文件都不适合你的记忆或什么? 非常接近当前实现的版本将类似于以下(未经测试的)代码。它只是跳过更新文件的部分,然后重新打开并读取它。 (请注意,这当然不是一种非常有效或过于优雅的方式,它只是尽可能地贴近你的实现)

#!/usr/bin/perl
use warnings;
use Cwd;
# use Tie::File;
# use Tie::Array;
my $cwd = getcwd();
my $buff = '';

# Get all files in cwd.
my @files = grep ( -f ,<*.txt>);

#  Cut off header and footer of $files [1] to $files[$#files-1], 
#  but only footer of $files[0] and header of $#files[$#files]
for (my $i = 0; $i <= $#files; $i++) {

    print 'Opening ' . $files[$i] . "\n";

    open (my $fh, "<", $files[$i]) or die "can't open $file for reading: $!";
    my @lines = <$fh>;
    splice @lines, 0, 1 unless $i == 0;
    splice @lines, -1, 1 unless $i == $#files;

    foreach my $line (@lines) {
        $buff .= $line;
    }
}

# Write the buffer to a new file.
my $allfilename = $cwd.'/Trace.txt';
print 'Writing all files into new file: ' . $allfilename . "\n";

open $outputfile, ">".$allfilename or die "can't write to new file $outputfile: $!";
# Write the buffer into the output file.
print $outputfile $buff;

close $outputfile;

答案 3 :(得分:0)

基于米勒的答案,但最适合大文件。

#!/usr/bin/env perl

use strict;
use warnings;
use autodie;

my $outfile = 'Trace.txt';

# Get all files in cwd.
my @files = grep { -f && $_ ne $outfile } <*.txt>;

open my $outfh, '>', $outfile;

my $counter = 0;
for my $file (@files) {
        open my $fh, '<', $file;
        my ($line, $prev) = ('', '');
        my $l = 0;
        while ($line = <$fh>) {
                print $outfh $prev unless $l++ == 1 and $counter > 0;
                $prev = $line;
        }
        $counter++;
        print $outfh $prev if $counter == @files and $l > 0;
        close $fh;
}