2012-12-11 92 views
-2

我對自己的無知表示歉意,但是我對Perl非常陌生,需要一些即時幫助......使用Perl,修剪文件的前半部分的最佳方法是什麼?

我有一個包含「Historical」數據的文件,而且我知道這些記錄是用逗號分隔的。當然,這個文件隨着歷史的發展而不斷增長和增長。所以使用Perl,我想修剪數據的文件,因爲它是最古老的。這並不需要是一門精確的科學。我想我會做類似如下:

  • 計數的文件,並鴻溝逗號的數量除以2(找到中間點)
  • 因此,舉例來說,如果有100條記錄(和,因此,逗號計數爲99),逗號計數爲99
  • 然後我除以2得到近似的中間點(向上舍入),在本例中將爲46
  • 然後刪除所有記錄第46個逗號(包括逗號,以便該文件不會以逗號開頭)。
  • 然後保存我新修剪的歷史數據文件。

這裏是一個非常小的樣本文件佈局逗號定界符:

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) 

我希望這是有道理的。

謝謝!

+2

所有記錄都在同一行嗎? – TLP

+0

你甚至還搜索過谷歌,我知道有很多話題涉及如何閱讀文件? – 8bitcat

+0

不知道爲什麼羽絨服? – Kimi

回答

0

從文件的開頭刪除是不可能的。這只是從文件結尾。爲了有效地從文件的開頭刪除,必須重寫整個文件(例如,通過創建一個新文件並保留該部分,然後將新文件重命名爲舊文件)。

+0

那麼最快,最有效的方法是什麼? – user1895607

+0

什麼,打印到文件? – ikegami

+0

是的,它聽起來像我需要使用WHILE循環來獲取逗號數,然後將該數除以2(舍入)以找到近似的中點。然後使用另一個WHILE循環來寫出其餘的記錄。但是我希望有一個非常快捷的方式來找到這個中間點,然後把文件的後半部分轉儲到另一個文件中。然後,我可以按照你所提到的重新命名它。 – user1895607

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>更改爲<>以使其使用文件參數。

由於文件被讀入內存,並且會消耗內存,這對於大文件而言可能代價高昂,因此效率稍差。另一種方法是簡單地運行文件並對記錄進行計數,然後重新打開文件以進行打印。例如:

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模塊。例如:

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; 

請注意,這樣做的影響是不可逆的,因此請在嘗試之前進行備份。即使對於大文件,它也是有效的,並且不會將文件讀入內存。

+0

這些文件可能會變得相當大,這就是爲什麼我正在尋找最有效的修剪方法。如果我安排這個新的Perl腳本每天運行,那麼這會使文件的大小有所下降。我將開始在一個小檔案中爲初學者玩這個遊戲。 – user1895607

+0

也許你應該看看像日誌旋轉模塊。我相信* nix會自動執行此類操作。 – TLP

0

很大程度上取決於數據添加到文件的方式和時間。數據每天添加一次嗎?每小時一次?持續?在手動的基礎上?您可以防止在重新構建數據文件時將新數據添加到文件中嗎?文件是由寫入過程持續打開還是每次添加新數據時都重新打開?

更好的方法是將新數據寫入新文件。例如,如果您想要每天管理數據,請讓寫入程序根據當前日期將新數據寫入文件。例如。寫在2012年12月11日的數據寫入文件data-2012-12-11

然後,您可以通過簡單地刪除文件來管理您的數據。遍歷所有你的數據,你可以使用Perl的通配符能力:

@ARGV = glob("data-*"); 
while (<>) { 
    ... 
} 
+0

這將是一個很好的方式來處理它 - 不幸的是,我對作者的控制權是零。 – user1895607

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; 

如果您的數據實際上是在一個表,你會想使用類似文字:: CSV和以前只是刪除行陣列的上半年輸出數據。您可能需要考慮保留第一行,因爲它可能包含標題數據......在沒有看到您的輸入的情況下,很難說什麼是最好的。

相關問題