我有一个复杂的正则表达式,我想将它与整个大文件的内容匹配。主要关注点是效率,因为文件确实很大,并且内存不足的可能性很明显。
有什么办法可以在通过正则表达式匹配器泵送内容时以某种方式“缓冲”内容吗?
最佳答案
是的,Pattern.match()
将采用CharSequence
。
如果您的输入已经在一个字符集中,该字符集恰好使用2个字节来表示一个没有任何“序言”的字符,则只需要:
ByteBuffer bb = ...; // acquire memory mapped byte buffer
CharBuffer cb = bb.asCharBuffer(); // get a char[] 'view' of the bytes
...并且由于
CharBuffer
实现了CharSequence
,您就完成了。另一方面,如果您需要将字节解码为其他字符集,则由于
CharBuffer
不区分字符集,并且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
包装器中,并记录在开发箱上以大堆运行时实际如何调用给定输入的方法,这可能是有启发性的。如果这种方法适用于您的特定情况,那将为您提供一个想法。