拆分文件 - Java/Linux

3
我有一个包含近2.5亿个字符的大文件。现在,我想将其分割成每个部分包含3000万个字符(因此前8个部分将包含3000万个字符,最后一个部分将包含1000万个字符)。另一个问题是,我想在下一个部分的开头包括每个文件的最后1000个字符(意味着第1个部分的最后1000个字符附加在第2个部分的开头——因此第2个部分包含3000万1000个字符,依此类推)。有人能帮助我如何以编程方式(使用Java)或使用Linux命令(以快速的方式)完成这个操作吗?

1
为什么需要重叠?如果不需要,您可以使用split和cat命令。 - Roger Lindsjö
我想把它分成每个部分包含3000万个字符。这是一个令人惊讶的愿望,你确定你不是为了某些原因而这样做,或者这已经足够了? - Peter Lawrey
@PeterLawrey,我想要分割数据,因为2.5亿条数据我无法在内存中处理。 - Arpssss
如果你将其作为字节数组加载,那么它将占用 250 MB 的空间,但如果你使用内存映射文件,则不会使用任何堆空间(<1 KB)。 - Peter Lawrey
@BasileStarynkevitch,我使用上面的案例来说明我的问题。实际上,我的文件要大得多,大约3.2 GB。并且是.txt文件。我正在使用4 GB RAM。 - Arpssss
显示剩余6条评论
4个回答

2

一种方法是使用常规的Unix命令来拆分文件,并在前一个文件中添加上一个文件的最后1000个字节。

首先,将文件拆分:

split -b 30000000 inputfile part.

然后,对于每个部分(忽略第一个),从前一个文件的最后1000个字节开始创建一个新文件:

unset prev
for i in part.*
do if [ -n "${prev}" ]
  then 
    tail -c 1000 ${prev} > part.temp
    cat ${i} >> part.temp
    mv part.temp ${i}
  fi
  prev=${i}
done

在组装之前,我们再次遍历这些文件,忽略第一个并且抛弃掉前1000字节:
unset prev
for i in part.*
do if [ -n "${prev}" ]
  then 
    tail -c +1001 ${i} > part.temp
    mv part.temp ${i}
  fi
  prev=${i}
done

最后一步是重新组装文件:
cat part.* >> newfile

由于没有解释为什么需要重叠,所以我只是创建了它,然后将其丢弃。


2
您可以尝试这个。我第一次使用了read/mode,因为文件起初不存在。您可以仅使用读取模式,就像此代码建议的那样。
long start = System.nanoTime();
long fileSize = 3200 * 1024 * 1024L;
FileChannel raf = new RandomAccessFile("deleteme.txt", "r").getChannel();
long midPoint = fileSize / 2 / 4096 * 4096;
MappedByteBuffer buffer1 = raf.map(FileChannel.MapMode.READ_ONLY, 0, midPoint + 4096);
MappedByteBuffer buffer2 = raf.map(FileChannel.MapMode.READ_ONLY, midPoint, fileSize - midPoint);
long time = System.nanoTime() - start;
System.out.printf("Took %.3f ms to map a file of %,d bytes long%n", time / 1e6, raf.size());

这是在一台安装有Windows 7 x64操作系统,内存为4 GB的计算机上运行。

Took 3.302 ms to map a file of 3,355,443,200 bytes long

2
只需使用适当的选项,即可使用splitcsplit命令。
您可能希望使用更复杂的shell脚本或其他脚本语言来驱动这些程序,以给它们提供适当的参数(特别是处理重叠要求)。也许您可以将它们与其他实用程序(如grepheadtailsedawk等)结合使用。

这两个是否有重叠的部分,就像 OP 想要的那样? - Miserable Variable
谢谢。但是,关于字符数量的分割和追加最后1000个字符的内容没有提到。 - Arpssss

1

您可以使用BreakIterator类及其静态方法getCharacterInstance()来实现。它会返回一个新的BreakIterator实例,用于默认语言环境下的字符分隔。

您还可以使用getWordInstance()、getLineInstance()等方法来分隔单词、行等。

例如:

BreakIterator boundary = BreakIterator.getCharacterInstance();

boundary.setText("Your_Sentence");

int start = boundary.first();

int end = boundary.next();

迭代它...以获取字符....

更多细节请查看此链接:

http://docs.oracle.com/javase/6/docs/api/java/text/BreakIterator.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接