在我们的项目中,我们需要将csv文件导入postgres。 有多种类型的文件意味着文件的长度会发生变化,因为有些文件的列数较少,而有些文件的列数较少。
我们需要一种快速的方法将此文件导入postgres。我想使用postgres的COPY FROM,因为处理的速度要求非常高(每分钟大约150个文件,每个文件大小为20K)。
由于文件列号未修复,我需要在将文件传递给postgres过程之前对其进行预处理。预处理只是在csv中为列添加额外的逗号,这些列在文件中不存在。
我有两种方法可以预处理文件 - 使用python或使用Sed。
我的第一个问题是,预处理文件的最快方法是什么?
第二个问题是,如果我使用sed,如何在说出第4个,第5个逗号字段后插入逗号? 例如如果文件有像这样的条目 1,23,56,我们,89,2009-12-06 我需要编辑最终输出的文件,如: 1,23,56,we ,, 89 ,,, 2009-12-06
答案 0 :(得分:3)
您是否意识到COPY FROM
允许您指定要导入哪些列(以及它们的顺序)?
COPY tablename ( column1, column2, ... ) FROM ...
在Postgres级别直接指定要导入的列以及按什么顺序排列,通常是最快且最有效的导入方法。
有人说过,使用sed
(比其他帖子中提到的内容)更简单(和便携)的方式,replace an n th occurrence,例如用双逗号替换逗号的第4和第5次出现:
echo '1,23,56,we,89,2009-12-06' | sed -e 's/,/,,/5;s/,/,,/4'
产生
1,23,56,we,,89,,2009-12-06
请注意,我先替换了最右边的字段(#5)。
我发现您还将自己的问题标记为perl
- 虽然您未在问题正文中明确提及perl
;这将是一种可能的实现,它为您提供了重新排序或以其他方式处理字段的灵活性:
echo '1,23,56,we,89,2009-12-06' |
perl -F/,/ -nae 'print "$F[0],$F[1],$F[2],$F[3],,$F[4],,$F[5]"'
也会产生:
1,23,56,we,,89,,2009-12-06
与awk
非常相似,记录:
echo '1,23,56,we,89,2009-12-06' |
awk -F, '{print $1","$2","$3","$4",,"$5",,"$6}'
我会将Python留给其他人。 :)
关于Perl示例的小注释:我使用-a
和-F
选项进行autosplit,因此我有一个较短的命令字符串;但是,这会将换行符嵌入到最后一个字段($F[5]
)中,只要该字段不必在其他地方重新排序即可。如果出现这种情况,则需要稍微更多的输入才能通过chomp
,然后split
手动删除换行符,最后打印我们自己的换行符\n
({{1}上面的例子没有这个问题):
awk
perl -ne 'chomp;@F=split/,/;print "$F[0],$F[1],$F[2],$F[3],,$F[4],,$F[5]\n"'
抱歉,忍不住了。 :)
答案 1 :(得分:2)
要回答您的第一个问题,sed
会减少开销,但可能会很痛苦。 awk
会更好一点(它更强大)。 Perl或Python有更多的开销,但更容易使用(关于Perl,这可能有点主观;)。就个人而言,我会使用Perl)。
就第二个问题而言,我认为这个问题可能会更复杂一些。例如,您是否需要检查字符串以确定哪些字段实际丢失?还是保证它永远是第4和第5?如果是第一种情况,那么在Python或Perl中使用 way 更容易,而不是在sed
中。否则:
echo "1,23,56,we,89,2009-12-06" | sed -e 's/\([^,]\+\),\([^,]\+\),\([^,]\+\),\([^,]\+\),\([^,]\+\),/\1,\2,\3,\4,,\5,,/'
或(眼睛更容易):
echo "1,23,56,we,89,2009-12-06" | sed -e 's/\(\([^,]\+,\)\{3\}\)\([^,]\+\),\([^,]\+\),/\1,\3,,\4,,/'
这将在第5和第4列之后添加逗号,假设文本中没有其他逗号。
或者你可以使用两个sed
来做一些不那么丑陋的事情(虽然只是略微一点):
echo "1,23,56,we,89,2009-12-06" | sed -e 's/\(\([^,]*,\)\{4\}\)/\1,/' | sed -e 's/\(\([^,]*,\)\{6\}\)/\1,/'
答案 2 :(得分:2)
@OP,您正在处理csv文件,该文件具有不同的字段和分隔符。使用可以拆分分隔符的工具,并为您提供易于使用的字段。 sed不是其中之一,虽然它可以完成,正如一些答案所暗示的那样,但是当它变得复杂时你会得到难以阅读的sed正则表达式。使用像awk / Python / Perl这样的工具,它们可以轻松地使用字段和分隔符,最重要的是,可以使用专门为处理csv定制的模块。对于您的示例,一个简单的Python方法(不使用csv模块,理想情况下您应该尝试使用它)
for line in open("file"):
line=line.rstrip() #strip new lines
sline=line.split(",")
if len(sline) < 8: # you want exact 8 fields
sline.insert(4,"")
sline.insert(6,"")
line=','.join(sline)
print line
输出
$ more file
1,23,56,we,89,2009-12-06
$ ./python.py
1,23,56,we,,89,,2009-12-06
答案 3 :(得分:0)
sed 's/^([^,]*,){4}/&,/' <original.csv >output.csv
将在第4个逗号分隔字段后添加逗号(通过匹配4个重复的<anything>,
然后再添加逗号)。请注意,有一个问题;确保这些值中没有一个是带引号的带引号的字符串。
如果需要,您可以通过管道链接多个替换,或者修改正则表达式以同时添加任何所需的逗号(尽管这会变得更复杂;您需要在替换文本中使用子组捕获)。
答案 4 :(得分:0)
不知道关于速度,但这里是应该做的工作的sed expr:
sed -i 's/\(\([^,]*,\)\{4\}\)/\1,/' file_name
只需用精确的列数替换4
答案 5 :(得分:0)