Java 将正则表达式应用于从缓冲大文件的小字节数组缓冲区创建的字符串

Java 将正则表达式应用于从缓冲大文件的小字节数组缓冲区创建的字符串,java,regex,arrays,Java,Regex,Arrays,我正在读取一个不能同时缓冲的文件,因为它的大小从256MB到2GB不等 打开文件后,我将其中的一块读取到字节数组中,比如512字节,将其转换为字符串并在其上运行正则表达式,如果检测到该模式,我的程序会记录下来 我遇到的问题是,我的程序在文件中丢失了很多应该检测模式的位置 我90%确定问题在于,虽然模式存在,但它并不完整,因为它超出了缓冲区的长度。我要查找的模式长度为8个字节,例如,模式的前四个字节位于数组中的最后四个位置;因此,当再次填充时,数组的前四个字节就是模式的最后四个字节。因此,我的正则

我正在读取一个不能同时缓冲的文件,因为它的大小从256MB到2GB不等

打开文件后,我将其中的一块读取到字节数组中,比如512字节,将其转换为字符串并在其上运行正则表达式,如果检测到该模式,我的程序会记录下来

我遇到的问题是,我的程序在文件中丢失了很多应该检测模式的位置

我90%确定问题在于,虽然模式存在,但它并不完整,因为它超出了缓冲区的长度。我要查找的模式长度为8个字节,例如,模式的前四个字节位于数组中的最后四个位置;因此,当再次填充时,数组的前四个字节就是模式的最后四个字节。因此,我的正则表达式总是失败

我猜我需要做的是填充缓冲区,然后当它再次填充时,将最后20个左右的字节保留在那里,这样它就不会错过我正在寻找的任何模式

如有任何建议,将不胜感激。提前谢谢


Tony

您应该做什么的伪代码:

while true:
   read 512 bytes into new buffer
   if eof:
       break
   concatenate with previous buffer (and only previous buffer)
   run regex on concatenated buffer

您可以在中加载文件,不断检查该模式并删除选中的数据

首先,不能将Java正则表达式应用于字节数组。您必须将其应用于
字符串
。所以,您必须从<代码>字节[] /代码>转换为<代码>字符串< /代码>,并且可以(a)使用错误的编码,或者(b)在中间截断字符串。< /P> 一旦你克服了这一点,你需要使用流媒体规则来重新构建你所阅读的内容。我可以描述一个可能适用也可能不适用的例子:

  • 将一大块数据读入缓冲区
  • 在缓冲区中查找最后一个句子边界
  • 从起点到边界的过程
  • 将剩余部分移到缓冲区的前面
  • 从源重新填充剩余的缓冲区
  • 起泡,冲洗,重复
  • 如果这确实是一个普通的字符文件,请按如下方式修改:

    Reader r = new InputStreamReader(inputByteStream, Charset.forName("utf-8"));
    

    然后应用上述算法以避免缓冲区边界条件。

    如果您的模式长度为8字节,只需运行额外的正则表达式检查,将两个连续缓冲区的最后7个字节和前7个字节(总共14个)连接起来。这样,您就可以确保不会遗漏任何内容,并且它可以放在几乎相同的内存中。

    一个有趣的可能解决方案是注意,正则表达式方法将输入作为字符串,而不是
    字符串(据我所知,它们从不调用
    CharSequence.toString()


    因此,您可以实现一个
    CharSequence
    ,它从文件中获取字符,而无需将整个文件加载到内存中。如果您的文件具有字符采用恒定字节数的编码(ASCII,UTF-16),您几乎可以直接将
    RandomAccessFile
    改编为
    CharSequence
    (虽然我不确定这种情况下的性能,也许您需要一些缓冲)。

    有几种方法可以解决这个问题,但我觉得这两项最容易实现:

    • 加载下一个缓冲区时,保留上一个缓冲区中的最后七个字节。将这七个字节与新缓冲区的前七个字节连接起来,并在测试整个缓冲区之前对14字节的“seam”运行单独的测试
    • 在两个缓冲区之间放置一个7字节的重叠;i、 e.保持缓冲区大小为512字节,但从字节504加载第二个缓冲区(我在这里使用零索引,因此这将是文件中的第505个字节)

    第二个选项可能要快得多,但第一个选项应该是快速代码。选择适合您的情况。

    正则表达式在字符串上运行,而不是在字节数组上运行。对不起,一旦字节数组被填充,我将用文本文件中的数据创建一个字符串?你能一次读一行吗?这个文件本质上是一个二进制文件。它包含一整堆看似随机的字符。我正在使用ISO-8859-1字符编码。问题是,我只需要继续移动缓冲区,这样就不会将模式一分为二。只有当所有数据都放入内存时,缓冲区才起作用,但在这种情况下效果很好。@bmarguiles-我猜,如果他运行的是java,他就有足够的空间容纳两个512字节的缓冲区。对我来说,他应该只使用带有正确解码器的InputStreamReader。我就是不明白为什么人们在需要字符的时候总是试图处理编码字节数组。设置解码一次,然后忘记它。这正是我需要做的!我只是不知道如何做到这一点。我认为循环缓冲区听起来正是我所需要的。我会仔细阅读的。谢谢