我有一个复杂的正则表达式,我想将它与整个巨大文件的内容相匹配。主要关注的是效率,因为文件确实非常大并且内存不足是一种明显的可能性。
有没有办法在通过正则表达式匹配器抽取内容时以某种方式“缓冲”内容?
答案 0 :(得分:6)
是的,Pattern.match()
将采用CharSequence
。
如果你的输入已经在一个charset中,它只使用2个字节来表示没有任何'prologue'的字符,你只需要:
ByteBuffer bb = ...; // acquire memory mapped byte buffer
CharBuffer cb = bb.asCharBuffer(); // get a char[] 'view' of the bytes
...自CharBuffer
实施CharSequence
以来,您就完成了。
另一方面,如果你需要将字节解码为其他字符集,那么你的工作就会被删除,因为CharBuffer
是charset-anostic,而CharsetDecorder.decode(ByteBuffer)
在内部分配一个新的CharBuffer
大小与输入字节大小相同。
你是否能够使用较小的缓冲区取决于你的正则表达式以及你想对匹配结果做些什么。但基本方法是实现CharSequence
并包装内存映射ByteBuffer
,更小的CharBuffer
用于'工作空间'和CharsetDecoder
。您将使用Charset.decode(ByteBuffer,CharBuffer,boolean)
来解码“按需”字节,并希望正则表达式匹配器的大致方向是“前进”,并且您感兴趣的输入是相当小的块。
作为一个粗略的开始:
class MyCharSequence implements CharSequence {
public MyCharSequence(File file, Charset cs, int bufferSize) throws IOException {
FileInputStream input = new FileInputStream(file);
FileChannel channel = input.getChannel();
this.fileLength = (int) channel.size();
this.bytes = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileLength);
this.charBuffer = CharBuffer.allocate(bufferSize);
this.decoder = cs.newDecoder();
}
public int length() {
// ouch! have to decode the lot, even if you don't choose to keep it all handy
}
public char charAt(final int index) {
while ( /* not yet decoded target char[] */ ) {
this.decoder.decode(this.bytes, this.charBuffer, true);
}
// don't assume 2-bytes == a char unless that's true for your charset!
}
public CharSequence subSequence(final int start, final int end) {
// this'll be fun, too
}
private long fileLength;
private MappedByteBuffer bytes;
private CharBuffer charBuffer;
private CharsetDecoder decoder;
}
将完全解码的CharBuffer
包装在一个更简单的CharSequence
自己的包装器中,并记录如何为您的给定输入实际调用方法,当您运行它时,这可能是有益的你的开发盒上有一大堆。这将使您了解这种方法是否适用于您的特定方案。
答案 1 :(得分:0)
我不了解Java,但您是否期望匹配文件的全部内容,例如/^.+$/
?
或者根据你的正则表达式将文件分成几块但你不知道在哪里?
正则表达式引擎很有趣,如果它可以做内存映射文件,那么这将是一个好的开始。
让我们看看你的正则表达式。通常,您可以检查正则表达式并确定两个锚点,并将其用作浮动缓冲区的截止值,其中溢出(重叠)被转移,窗口在文件中向下移动。
我在Perl模块中已经多次这样做了。除了文件开头和结尾的锚之外的任何东西,它很容易做到。