【问题标题】:BufferedInputStream Mark/Reset invalid markBufferedInputStream 标记/重置无效标记
【发布时间】:2014-09-04 15:14:05
【问题描述】:

我有 2 个 BufferedInputStreams,它们都包含一个 xml 字符串:一个很小,一个很大。

每个 xml 字符串的开头如下所示:

<RootElement success="true">

我创建了一个方法:

  1. 在输入流的开头设置标记
  2. 读取 xml 的前几个字节以检查根元素是否具有特定属性。
  3. 将输入流重置到标记位置,这样其他方法就可以享受完整的完整流了。

我的印象是缓冲输入流的缓冲区(默认为 8012 字节)和标记 readlimit 的大小实际上都无关紧要,因为无论我有多大,我都只会在重置前读取前 50 个字节输入流是。

不幸的是,我收到“IOException: resseting to invalid mark”异常。以下是相关代码:

private boolean checkXMLForSuccess(BufferedInputStream responseStream) throws XMLStreamException, FactoryConfigurationError
{
    //Normally, this should be set to the amount of bytes that can be read before invalidating.
    //the mark. Because we use a default buffer size (1024 or 2048 bytes) that is much greater
    //than the amount of bytes we will read here (less than 100 bytes) this is not a concern.
    responseStream.mark(100);

    XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(responseStream);
    xmlReader.next(); //Go to the root element

    //This is for loop, but the root element can only have 1 attribute.
    for (int i=0; i < xmlReader.getAttributeCount(); i++)
    {
        if(xmlReader.getAttributeLocalName(i).equals(SUCCES_ATTRIBUTE))
        {
            Boolean isSuccess = Boolean.parseBoolean(xmlReader.getAttributeValue(i));

            if (isSuccess)
            {
                try
                {
                    responseStream.reset();
                }
                catch (IOException e)
                {
                    //Oh oh... reset mark problem??
                }

                return true; 
            }
        }
    }

    return false;
}

现在,我当然尝试将标记读取限制设置为更高的数字。在它最终起作用之前,我必须将其设置为 10000 的值。我无法想象我下面的代码需要读取 10000 个字节!还有哪些其他因素可能导致这种行为?

【问题讨论】:

    标签: java bufferedinputstream


    【解决方案1】:

    根据 InputStream 类的文档 - reset() 方法:

    公共无效重置() 抛出 IOException

    reset 的一般约定是: 如果方法 markSupported 返回 true,则: 如果自标记以来从流中读取的字节数为 最后一次调用大于最后一次调用时要标记的参数, 那么可能会抛出 IOException。

    在您的代码中,

    您已超过 100 作为字节读取限制。

    responseStream.mark(100);
    

    而且很有可能是代码部分:

    xmlReader.next();
    

    读取超过 100 个字节,标记失效,调用 reset() 方法抛出 IOException。

    XMLStreamReader.next():

    获取下一个解析事件 - 处理器可能会返回所有连续的 单个块中的字符数据,或者可以将其拆分为多个 块

    因此,阅读器可能会一直读取超过读取限制字节数,从而导致标记无效。 (无论文件大小以及连续字符是否很大,都会发生这种情况。

    第二个实例,

    如果方法 markSupported 返回 false,则: 调用 reset 可能会抛出 IOException

    但 BufferedInputStream 支持标记,

    公共布尔标记支持()

    测试此输入流是否支持标记和重置方法。这 BufferedInputStream 的markSupported 方法返回true。

    所以可以减少第二种情况。

    【讨论】:

    • 如果 xmlReader.next() 读取超过 100 字节,为什么大小为 500 字节的小 xml 文件可以工作,但大小为 5000 的大 xml 文件不起作用?两者都具有相同的根元素和相同的属性,并且都大于 100 字节。
    • @user1884155 在这一点上,如果没有真正查看 XMLReader 在 OpenJDK 代码中做了什么,这一切都是猜测。
    • @user1884155,@Powerlord - 已更新我的答案 wrt 你的 cmets
    • @user1884155 你能检查你的文件中是否有连续的字符占用> 100字节
    • 我发现了一些奇怪的东西。当我将 xml 输出到我的 Eclipse 控制台时,我看到大量的空白突然出现。如果我修剪我的字符串,空格仍然存在。如果我按字符打印字符串 char,则任何地方都没有空格。我不知道是什么奇怪的角色导致了这种行为。 1000 个空格长的不可修剪的空白间隙?!
    【解决方案2】:

    这是一个猜测,但XMLStreamReader 可能会在getAttributeCountgetAttributeLocalName 方法期间读取大部分InputStream,尽管它可能在创建XMLStreamReader 时完成...

    不过,我还没有查看 OpenJDK 代码来确认这一点。

    【讨论】:

      猜你喜欢
      • 2016-02-18
      • 1970-01-01
      • 1970-01-01
      • 2015-04-06
      • 2013-09-05
      • 2015-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多