我有一组我要导入MySQL的文件。
每个CSV文件如下所示:
Header1;Header2;Header3;Header4;Header5
Data1;Data2;Data3;Data4;Data5;
Data1;Data2;Data3;Data4;Data5;
Data1;Data2;Data3;Data4;Data5;
Data1;Data2;Data3;Data4;Data5;
数据可能包含空格,句点或完整冒号。它们绝对不会包含分号,因此它是一个有效的分隔符。它们也不包含\ n或任何其他换行符。
2010.08.30 18:34:59
0.7508
String of characters with spaces in them
每个文件都有一个唯一的名称。名称均符合以下模式:
Token1_Token2_Token3.csv
我有兴趣将很多这些CSV文件(大约数百个)合并到一个CSV文件中。文件范围从10KB到400MB。最终,我想将它发送给MySQL。不要担心摆脱各个标题行;我可以很容易地在MySQL中做到这一点。
我希望最终的CSV文件看起来像这样:
Header1,Header2,Header3,Header4,Header5,FileName
Data1,Data2,Data3,Data4,Data5,Token1
Data1,Data2,Data3,Data4,Data5,Token1
Data1,Data2,Data3,Data4,Data5,Token1
Data1,Data2,Data3,Data4,Data5,Token1
Data1,Data2,Data3,Data4,Data5,Token1
我不关心任何其他令牌。如果解决方案只是将每个csv文件名转储到Token1字段中,我也可以生存,因为再次,我可以轻松地在MySQL中解析它。
请帮帮我!我已经花了10多个小时才能解决一个相对容易的问题。
可用技术:
AWK
windows批次
linux bash
PowerShell的
perl的
蟒蛇
PHP
MySQL的导入
这是一个服务器盒,所以我将无法编译任何东西,但如果你给我一个Java解决方案,我一定会尝试在盒子上运行它。
答案 0 :(得分:3)
使用Text::CSV
:
#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
use Text::CSV;
my $semi_colon_csv = Text::CSV->new( { 'sep_char' => ';', } );
my $comma_csv = Text::CSV->new( {
'sep_char' => ',',
'eol' => "\n",
} );
open my $fh_output, '>', 'output.csv' or die $!;
sub convert {
my $file_name = shift;
open my $fh_input, '<', $file_name or die $!;
# header
my $row = $semi_colon_csv->getline($fh_input);
$comma_csv->print( $fh_output, [ @$row, $file_name ] );
while ( $row = $semi_colon_csv->getline($fh_input) ) {
pop @$row unless $row->[-1]; # remove trailing semi-colon from input
my ($token) = ( $file_name =~ /^([^_]+)/ );
$comma_csv->print( $fh_output, [ @$row, $token ] );
}
}
sub wanted {
return unless -f;
convert($_);
}
my $path = 'csv'; # assuming that all your CSVs are in ./csv/
find( \&wanted, $path );
Header1,Header2,Header3,Header4,Header5,Token1_Token2_Token3.csv
Data1,Data2,Data3,Data4,Data5,Token1
Data1,Data2,Data3,Data4,Data5,Token1
Data1,Data2,Data3,Data4,Data5,Token1
Data1,Data2,Data3,Data4,Data5,Token1
答案 1 :(得分:2)
信不信由你,它可能很简单:
awk 'BEGIN{OFS = FS = ";"} {print $0, FILENAME}' *.csv > newfile.csv
如果要将字段分隔符从分号更改为逗号:
awk 'BEGIN{OFS = ","; FS = ";"} {$1 = $1; print $0, FILENAME}' *.csv > newfile.csv
仅包含第一个标记:
awk 'BEGIN{OFS = ","; FS = ";"} {$1 = $1; split(FILENAME, a, "_"); print $0, a[1]}' *.csv > newfile.csv
答案 2 :(得分:1)
你可能想试试这个快速&amp;脏Perl hack转换数据:
#!/usr/bin/perl
use strict;
use warnings;
# Open input file
my $inputfile = shift or die("Usage: $0 <filename>\n\n");
open F, $inputfile or die("Could not open input file ($!)\n\n");
# Split filename into an array
my @tokens = split("_", $inputfile);
my $isFirstline = 1;
# Iterate each line in the file
foreach my $line (<F>) {
my $addition;
chomp($line); # Remove newline
# Add the complete filename to the line at first line
if ($isFirstline) {
$isFirstline = 0;
$addition = ",$inputfile";
} else { # Add first token for the rest of the lines
$addition = ",$tokens[0]";
}
# Split the data into @elements array
my @elements = split(";", $line);
# Join it using comma and add filename/token & a new line
print join(",", @elements) . $addition . "\n";
}
close(F);
答案 3 :(得分:0)
Perl的DBI模块可以处理CSV文件(需要DBD :: CSV模块)和MySQL。只需将所有csv文件放在同一个目录中,然后像这样查询:
use DBI;
my $DBH = DBI->connect ("dbi:CSV:", "", "", { f_dir => "$DATABASEDIR", f_ext => ".csv", csv_sep_char => ";",});
my $sth = $dbh->prepare ("SELECT * FROM Token1_Token2_Token3");
$sth->execute;
while (my $hr = $sth->fetchrow_hashref) {
[...]
}
$sth->finish ();
Yo可以查询csv文件(包括JOIN语句!)并将数据直接插入MySQL。
答案 4 :(得分:0)
这是在PowerShell中执行此操作的一种方法:
$res = 'result.csv'
'Header1,Header2,Header3,Header4,Header5,FileName' > $res
foreach ($file in dir *.csv)
{
if ($file -notmatch '(\w+)_\w+_\w+\.csv') { continue }
$csv = Import-Csv $file -Delimiter ';'
$csv | Foreach {"{0},{1},{2},{3},{4},{5}" -f `
$_.Header1,$_.Header2,$_.Header3,$_.Header4,$_.Header5,$matches[1]} >> $res
}
如果文件的大小没有那么大,我建议走这条路:
$csvAll = @()
foreach ($file in dir *.csv)
{
if ($file -notmatch '(\w+)_\w+_\w+\.csv') { continue }
$csv = Import-Csv $file -Delimiter ';'
$csv | Add-Member NoteProperty FileName $matches[1]
$csvAll += $csv
}
$csvAll | Export-Csv result.csv -NoTypeInformation
但是,这会将所有CSV文件的完整内容保存在内存中,直到最后可以导出为止。除非您的64位Windows具有大量内存,否则不可行。 : - )