我需要使用Powershell或Perl(公司要求)对一些巨大(大于2GB)的CSV文件进行排序。 我需要根据文件从任何列对它们进行排序。
对于某些人,我的CSV文件看起来像这样,使用双引号:
Column1;Column2;Column3;Column4
1234;1234;ABCD;"1234;ABCD"
5678;5678;ABCD;"5678;ABCD"
9012;5678;ABCD;"9012;ABCD"
...
在Powershell中,我已经测试了解决方案导入CSV ,但是遇到了 OutOfMemory Exception 问题。 我还尝试使用 OleDb Connection 通过以下代码在SQL表中加载CSV文件:
$provider = (New-Object System.Data.OleDb.OleDbEnumerator).GetElements() | Where-Object { $_.SOURCES_NAME -like "Microsoft.ACE.OLEDB.*" }
if ($provider -is [system.array]) { $provider = $provider[0].SOURCES_NAME } else { $provider = $provider.SOURCES_NAME }
$csv = "PathToCSV\file.csv"
$firstRowColumnNames = "Yes"
$connstring = "Provider=$provider;Data Source=$(Split-Path $csv);Extended Properties='text;HDR=$firstRowColumnNames;';"
$tablename = (Split-Path $csv -leaf).Replace(".","#")
$sql = "SELECT * from [$tablename] ORDER BY Column3"
# Setup connection and command
$conn = New-Object System.Data.OleDb.OleDbconnection
$conn.ConnectionString = $connstring
$conn.Open()
$cmd = New-Object System.Data.OleDB.OleDBCommand
$cmd.Connection = $conn
$cmd.CommandText = $sql
$cmd.ExecuteReader()
# Clean up
$cmd.dispose
$conn.dispose
但这会返回错误:
Exception calling "ExecuteReader" with "1" argument(s): "No value given for one or more required parameters."
,但我不明白为什么。我试图修改代码,SQL代码,但仍然无法正常工作。
我认为这是实现此目的的最佳解决方案,但我暂时还没有实现它,并且我对所有其他可行的解决方案持开放态度...
我是Perl的初学者,所以我只是想了解它的工作原理和用法,但是暂时没有编写任何代码。
编辑
我刚刚测试了您提出的所有解决方案,非常感谢您的帮助。
这两个解决方案均无法使用,因为您要我使用的模块(文本:: CSV,文件::排序或数据:: Dumper)未安装在我正在使用的Perl版本中,并且我无法安装他们(公司限制...)。
我所尝试的是在列上尝试简单排序,而无需解决双引号问题:
use CGI qw(:standard);
use strict;
use warnings;
my $file = 'path\to\my\file.csv';
open (my $csv, '<', $file) || die "cant open";
foreach (<$csv>) {
chomp;
my @fields = split(/\;/);
}
@sorted = sort { $a->[1] cmp $b->[1] } @fields;
我以为这应该起作用,将数组中的数据按第二列进行排序,但不起作用,而且我不明白为什么...
答案 0 :(得分:0)
使用带分隔符选项的* NIX sort
(或在您使用的操作系统中的等效版本)(例如,-t';'
-确保引用分号)对文件进行排序。如果公司要求使用Perl,则将系统调用包装到Perl中的sort
,如下所示:
system "sort -t';' [options] in_file > out_file" and die "cannot sort: $?"
示例:
按第1列按数字排序:
sort -k1,1g -t';' in_file.txt > out_file.txt
请注意,需要( head -n1 in_file.txt ; tail -n+2 in_file.txt | sort ... )
才能使标题保持在顶部并仅对数据行进行排序。
按第1列排序,数字降序:
( head -n1 in_file.txt ; tail -n+2 in_file.txt | sort -k1,1gr -t';' ) > out_file.txt
按字母顺序依次按第4列和第1列按数字降序排列:
( head -n1 in_file.txt ; tail -n+2 in_file.txt | sort -k4,4 -k1,1gr -t';' ) > out_file.txt
答案 1 :(得分:0)
一个人可以使用DBD :: CSV,在这种情况下,可以完成以下工作:
use Data::Dumper;
$Data::Dumper::Deepcopy=1;
$Data::Dumper::Indent=1;
$Data::Dumper::Sortkeys=1;
use DBI;
use Getopt::Long::Descriptive ('describe_options');
use Text::CSV_XS ('csv');
use Try::Tiny;
use 5.01800;
use warnings;
try {
push @ARGV,'--help'
unless (@ARGV);
my ($opts,$usage)=describe_options(
'my-program %o <some-arg>',
,['field|f=s' ,'the order by field']
,['table|t=s' ,'The table (file) to be sorted']
,['new|n=s' ,'The sorted table (file)']
,[]
,['verbose|v' ,'print extra stuff' ,{ default => !!0 }]
,['help' ,'print usage message and exit' ,{ shortcircuit => !1 }]
);
if ($opts->help()) { # MAN! MAN!
say <<"_HELP_";
@{[$usage->text]}
_HELP_
exit;
}
else { # No MAN required.
};
my $dbh=DBI->connect("dbi:CSV:",undef,undef,{
f_ext => ".csv/r",
csv_sep_char => ";",
RaiseError => 1,
}) or die "Cannot connect: $DBI::errstr";
my $sth=$dbh->prepare(
"select * from @{[$opts->table()]} order by @{[$opts->field()]}"
);
# New table
my $csv=Text::CSV_XS->new({ sep_char => ";" });
open my $fh,">:encoding(utf8)","@{[$opts->new()]}.csv"
or die "@{[$opts->new()]}.csv: $!";
# fields
$sth->execute();
my $fields_aref=$sth->{NAME};
$csv->say($fh,$fields_aref);
# the sorted rows
my $max_rows=5_000;
while (my $aref=$sth->fetchall_arrayref(undef,$max_rows)) {
$csv->say($fh,$_)
for (@$aref);
};
close $fh
or die "@{[$opts->new()]}.csv: $!";
$dbh->disconnect();
}
catch {
Carp::confess $_;
};
__END__
(在窗口下方)将其调用为
perl CSV_01.t -t data -f "column2 DESC" -n newest
在没有参数的情况下调用会获得帮助或
my-program [-fntv] [long options...] <some-arg>
-f STR --field STR the order by field
-t STR --table STR The table (file) to be sorted
-n STR --new STR The sorted table (file)
-v --verbose print extra stuff
--help print usage message and exit
(可悲的是,冗长的操作没有任何额外的作用。)