我为自己的无知道歉,但我对Perl非常陌生,需要立即帮助....
我有一个包含“历史”数据的文件,我知道这些记录是逗号分隔的。当然,随着历史的发展,这个文件不断增长和发展。所以使用Perl,我想修剪数据文件,因为它是最老的。这不需要是一门精确的科学。我想我会做类似以下的事情:
以下是使用逗号分隔符的非常小的示例文件布局:
20121130092403000Server1::RedHat 1.2.3.4(1234),20121130092503000Server2::RedHat 5.6.7.8(1234),20121130092603000Server3::SUSE 9.8.7.6(9876),20121130092703000Server4::WindowsXP 5.6.7.8(6543)
我希望这是有道理的。
谢谢!
答案 0 :(得分:1)
“最快,最有效的方式”可能是一个不同的问题。这是做这样的事情的典型方式:
use strict;
use warnings;
local $/ = ",";
my @file = <DATA>;
say "Number of records: " . @file;
my $half = int((@file/2)+0.5);
say "Last half of records ($half):";
say @file[$half .. $#file];
__DATA__
20121130092403000Server1::RedHat 1.2.3.4(1234),20121130092503000Server2::RedHat 5.6.7.8(1234),20121130092603000Server3::SUSE 9.8.7.6(9876),20121130092703000Server4::WindowsXP 5.6.7.8(6543),
请注意,此处使用DATA文件句柄进行演示。您只需将<DATA>
更改为<>
即可使其使用文件参数。
这样效率会有所降低,因为文件被读入内存,并且会占用内存,这对于大文件来说可能是昂贵的。另一种方法是简单地浏览文件并计算记录,然后重新打开文件进行打印。 E.g:
my $file = shift;
local $/ = ",";
open my $fh, "<", $file or die $!;
my $count;
while (<$fh>) { $count++ }
$count = int(($count/2)+0.5);
open $fh, "<", $file or die $!;
while ($count-- > 0) { <$fh> };
while (<$fh>) { print }
当然,这些输出需要重定向,例如像这样:
perl script.pl oldfile > newfile
您可能也喜欢Tie::File
模块。 E.g:
use strict;
use warnings;
use Tie::File;
my $file = shift;
tie @array, 'Tie::File', $file or die $!;
my $half = int((@array/2)+0.5);
splice @array, 0, $half;
untie @array;
请注意,这种效果是不可逆转的,因此请在尝试之前进行备份。据推测,即使对于大文件也是如此,并且不会将文件读入内存。
答案 1 :(得分:0)
无法从文件的开头删除。它只来自文件的末尾。要从文件的开头有效删除,必须重写整个文件(例如,通过创建一个包含要保留的部分的新文件,然后在旧文件上重命名新文件)。
答案 2 :(得分:0)
很大程度上取决于数据添加到文件的方式和时间。数据是否每天添加一次?一小时一次?持续?在手动的基础上?在重新构建数据文件时,是否可以阻止将新数据添加到文件中?文件是否通过写入过程持续保持打开状态,或者每次添加新数据时是否重新打开文件?
更好的方法是将新数据写入新文件。例如,如果要基于每天管理数据,请让编写器进程根据当前日期将新数据写入文件。例如。写入2012-12-11的数据将写入文件data-2012-12-11
等
然后,您只需删除文件即可管理数据。要迭代所有数据,您可以使用perl的通配功能:
@ARGV = glob("data-*");
while (<>) {
...
}
答案 3 :(得分:0)
这取决于所有记录是在一行中(以便您的.csv类似于列表)还是多行(以便您的.csv类似于表)。
如果是前者,您概述的方法可以正常工作。这就是诀窍:
use strict;
use POSIX;
my $filename = "somecsvfilename.csv";
open (IN, "<", $filename);
my $fulltext;
while (<IN>) {
chomp;
$fulltext .= $_;
}
close IN;
my @data_segments = split(",", $fulltext);
my $num_commas = @data_segments;
my $num_to_delete = floor($num_commas/2);
open (OUT, ">", $filename);
my $i = $num_to_delete;
while ($i < $num_commas) {
print OUT $data_segments[$i];
if ($i != ($num_commas - 1)) {print OUT ","}
$i++;
}
close OUT;
如果您的数据实际上是一个表,您将需要使用Text :: CSV之类的东西,并在输出数据之前删除行数组的前半部分。您可能需要考虑保留第一行,因为它可能包含标题数据...没有看到您的输入,很难说什么是最好的。