use*_*171 10 csv text split large-data
我有CSV文件,其中有多列已排序.例如,我可能有这样的行:
19980102,,PLXS,10032,Q,A,,,15.12500,15.00000,15.12500,2
19980105,,PLXS,10032,Q,A,,,14.93750,14.75000,14.93750,2
19980106,,PLXS,10032,Q,A,,,14.56250,14.56250,14.87500,2
20111222,,PCP,63830,N,A,,,164.07001,164.09000,164.12000,1
20111223,,PCP,63830,N,A,,,164.53000,164.53000,164.55000,1
20111227,,PCP,63830,N,A,,,165.69000,165.61000,165.64000,1
Run Code Online (Sandbox Code Playgroud)
我想根据第3列分割文件,例如将PLXS和PCP条目放入他们自己的文件PLXS.csv和PCP.csv中.由于文件恰好是预先排序的,因此所有PLXS条目都在PCP条目之前,依此类推.
我通常最终在C++中做这样的事情,因为那是我最熟悉的语言,但在这种情况下,我的输入CSV文件是几千兆字节,太大而无法加载到C++的内存中.
有人可以说明如何实现这一目标吗?Perl/Python/php/bash解决方案都可以,他们只需要能够处理大文件而无需过多的内存使用.
Sea*_*ers 32
这里有一个老式的学校班轮(只需替换>>with >来截断每次运行的输出文件):
awk -F, '{print >> ($3".csv")}' input.csv
Run Code Online (Sandbox Code Playgroud)
由于受欢迎的需求(以及我刚才的痒),我还编写了一个版本,将标题行复制到所有文件:
awk -F, 'NR==1 {h=$0; next} {f=$3".csv"} !($3 in p) {p[$3]; print h > f} {print >> f}' input.csv
Run Code Online (Sandbox Code Playgroud)
但你可以从这开始,并完成第一个awk:
HDR=$(head -1 input.csv); for fn in $(tail -n+2 input.csv | cut -f3 -d, | sort -u); do echo $HDR > $fn.csv; done
Run Code Online (Sandbox Code Playgroud)
大多数现代系统都包含awk二进制文件,但是如果你没有它,你可以在Gawk for Windows上找到一个exe 文件
如果您最了解 C++,那就没问题。无论如何,您为什么要尝试将整个文件加载到内存中?
由于输出取决于正在读取的列,因此您可以轻松地存储输出文件的缓冲区,并在处理时将记录填充到适当的文件中,并进行清理以保持内存占用相对较小。
当需要从数据库中提取大量数据时,我会这样做(尽管是在java中)。这些记录被推送到文件缓冲流中,并且内存中的所有内容都被清除,因此程序的占用空间永远不会超出其最初开始时的大小。
凭我的感觉伪代码:
基本上继续这个处理,直到我们到达文件的末尾。
由于我们只存储指向流的指针,并且一旦写入流,我们就会刷新,除了输入文件中的一条记录之外,我们不会在应用程序的内存中保留任何驻留内容。因此,占地面积保持在可控范围内。