我有一个30 GB的xml文件,我想把它拆分成较小的文件。
文件中的数据如下:
<film>.....</film>
.
.
.
.
.
.
<film>.....</film>
我可以使用“split -l”,但问题是某些电影元素包含带换行符的文本数据。因此,一个电影元素可能需要不止一行。
我想要做的是拆分它,以便每个新的较小文件包含例如3000个电影元素。所以它应该在每3000个电影标签之后拆分......
我正在使用Mac OS X,我想要一个awk解决方案。
我尝试使用此split file on Nth occurrence of delimiter但未成功...在结束电影标签后没有拆分文件......
答案 0 :(得分:3)
流式传输XSLT 3.0的工作:
<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode streamable="true" on-no-match="shallow-copy"/>
<xsl:template match="/*">
<xsl:for-each-group select="*" group-adjacent="(position()-1) idiv 3000">
<xsl:result-document href="chunk{position()}.xml">
<xsl:copy>
<xsl:copy-of select="."/>
</xsl:copy>
</xsl:result-document>
</xsl:for-each-group>
</xsl:template>
</xsl:transform>
这比awk解决方案更强大,因为它实际上解析了XML,因此它保证了良好的输入和良好的输出。当您处理30Gb时,您无法手动检查输出,因此如果您未能预测输入中可能出现的所有内容(例如标题中带有“电影”的电影),则存在未检测到的垃圾的严重危险。因此,正确处理标记的结构会更加安全。
另一件事是,如果你的输入是格式良好的XML,它在<film>
元素周围有一个包装元素,如果要将输出作为XML处理,它将需要一个类似的包装元素。 XSLT解决方案免费处理。
您可能已经注意到,此样式表可以将任何xml文件拆分为块,当然块大小可以很容易地作为参数提供。
答案 1 :(得分:2)
这可能是你正在寻找的东西:
awk '{ gsub(/@/,"@A"); gsub(/}/,"@B"); gsub(/<\/film>\n?/,"}") } 1' file |
awk -v RS='}' -v ORS='</film>' '
(NR%3000)==1 { close(out); out="out"++cnt }
{ gsub(/@B/,"}"); gsub(/@A/,"@"); print > out }
'
但没有样本输入/输出,这是一个猜测,当然,未经测试。
答案 2 :(得分:0)
当Ed Morton发布awk解决方案时,它通常是像我这样的低级用户的小教程......
但无论如何,因为我在过去的一个半小时里一直在做这个练习,所以我想冒风险发布这个解决方案,这是一个转变by the link you already found
$ awk '$0 ~/<film.*>/{++delim} {file = sprintf("chunk%s", int(delim/7)); print >file; }' file4
<强>测试强>
我使用一个小的bash循环来创建一个包含50条记录的小电影文件,然后将这些电影拆分为7进行测试:
$ for ((i=1;i<50;i++));do echo -e "<film$i>..............</film$i>" >>file4;done
$ head file4
<film1>..............</film1>
<film2>..............</film2>
<film3>..............</film3>
<film4>..............</film4>
<film5>..............</film5>
<film6>..............</film6>
<film7>..............</film7>
<film8>..............</film8>
<film9>..............</film9>
<film10>..............</film10>
$ awk '$0 ~/<film.*>/{++delim} {file = sprintf("chunk%s", int(delim/7)); print >file; }' file4
$ cat chunk0
<film1>..............</film1>
<film2>..............</film2>
<film3>..............</film3>
<film4>..............</film4>
<film5>..............</film5>
<film6>..............</film6>
另一个测试,每部电影都有一些换行符:
$ for ((i=1;i<50;i++));do echo -e "<film$i>...\n...\n...\n.....</film$i>" >>file4;done
$ head -n20 file4
<film1>...
...
...
.....</film1>
<film2>...
...
...
.....</film2>
<film3>...
...
...
.....</film3>
<film4>...
...
...
.....</film4>
<film5>...
...
...
.....</film5>
$ awk '$0 ~/<film.*>/{++delim} {file = sprintf("chunk%s", int(delim/7)); print >file; }' file4
$ ls chunk*
chunk0 chunk1 chunk2 chunk3 chunk4 chunk5 chunk6 chunk7
$ cat chunk1
<film7>...
...
...
.....</film7>
<film8>...
...
...
.....</film8>
<film9>...
...
...
.....</film9>
<film10>...
...
...
.....</film10>
<film11>...
...
...
.....</film11>
<film12>...
...
...
.....</film12>
<film13>...
...
...
.....</film13>
嗯,在这两种情况下似乎都能正常工作。请注意,在此配置中,输入文件每7部分分割一次 - 而不是每7行。您可以将此数字更改为任何内容。