【问题标题】:Exception when split big XML file in small chunks with VTD-XML使用 VTD-XML 将大 XML 文件分成小块时出现异常
【发布时间】:2017-11-13 16:53:45
【问题描述】:

我正在开发一个小程序,它将一个非常大的 XML 文件(超过 2Gb)分成小块。

在研究了许多库之后,我选择了 VTD-XML(对大文件使用 VTDGenHuge)并开始开发一个小代码测试。但是当我读取文件的段字节时遇到问题。

我得到偏移和长度:

            long [] l = vn.getElementFragment();

然后我得到结果的信息:

            int offset = (int) (l[0] >> 64);
            int len = new Integer("" + l[1]);

最后我尝试提取字节段并将其写入另一个文件:

            b = new byte[len];
            fis.read(b, offset, len); **//<===== this is the exception problem**

但我得到 java.lang.IndexOutOfBoundsException

另外,当我为字节数组分配一个固定数字(例如 new byte[400])时,程序可以正常结束,但输出文件已损坏。

我的代码:

    File fo = new File("\\path\\post_people.xml");
    FileOutputStream fos = new FileOutputStream(fo);

    int count = 0;

    File f = new File("\\path\\people.xml");
    FileInputStream fis = new FileInputStream(f);
    byte[] b;

    VTDGenHuge vg = new VTDGenHuge();
    if (vg.parseFile("\\path\\people.xml", false, VTDGenHuge.MEM_MAPPED)){

        VTDNavHuge vn = vg.getNav();

        AutoPilotHuge ap = new AutoPilotHuge();
        ap.bind(vn);
        ap.selectXPath("/people/person"); //here it could be posible add another condition

        while (ap.evalXPath() != -1) {
            long [] l = vn.getElementFragment();
            int offset = (int) (l[0] >> 64);
            int len = new Integer("" + l[1]);
            b = new byte[len];
            fis.read(b, offset, len); //<===== this is the line problem

            fos.write(b); // writing the fragment out into other file

            count++;

            if (count == 3) { //this is just a test
                break;
            }

        }

    }

XML 文件示例:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<people>
    <person>
        <name>Nombre 0</name>
        <lastName>ApPaterno 1</lastName>
        <birthdate>2017-11-10T10:20:44.926-05:00</birthdate>
        <age>0</age>
        <address>
            <streetType>Tipo Calle 0</streetType>
            <streetName>Nombre de Calle 0</streetName>
            <number>0</number>
        </address>
    </person>
    <person>
        <name>Nombre 1</name>
        <lastName>ApPaterno 1</lastName>
        <birthdate>2017-11-10T10:20:44.926-05:00</birthdate>
        <age>1</age>
        <address>
            <streetType>Tipo Calle 1</streetType>
            <streetName>Nombre de Calle 1</streetName>
            <number>1</number>
        </address>
    </person>
</people>

拜托,你们能帮帮我吗,伙计们?

更新和解决方案:

最后,我应该修改的片段代码如下:

long [] l = vn.getElementFragment();
int offset = (int) (l[0] >> 64);
int len = new Integer("" + l[1]);
b = new byte[len];

fis.getChannel().position(0); //must return to position 0
fis.skip(offset); //must move to offset position
fis.read(b, 0, len);

【问题讨论】:

  • OOB 异常是否与此 issue 相关?
  • @RomanVottner 我不这么认为。我的问题与读取字节有关。但是对于您的其他评论,是的,它与偏移量有关。我的意思是这也是问题

标签: java xml split vtd-xml


【解决方案1】:

正如您所指出的,代码中的主要问题在于输入流的读取:

int offset = (int) (l[0] >> 64);
int len = new Integer("" + l[1]);
b = new byte[len];
fis.read(b, offset, len);

根据InputStream.read()的JavaDoc:

读取的第一个字节存储在元素 b[off] 中,下一个字节存储在 b[off+1] 中,依此类推。

这意味着您的实际缓冲区必须是长度偏移量 + len,这使字节 0 到偏移量为 0,或者您跳过输入流的第一个偏移量字节并通过填充 len 字节到缓冲区中从位置 0 开始缓冲。

如果将上面的代码替换为

int offset = (int) (l[0] >> 64);
int len = new Integer("" + l[1]);
b = new byte[len];
fis.skip(offset);
fis.read(b, 0, len);

缓冲区应该填充实际字符串表示的字节

<person>
    <name>Nombre 0</name>
    <lastName>ApPaterno 1</lastName>
    <birthdate>2017-11-10T10:20:44.926-05:00</birthdate>
    <age>0</age>
    <address>
        <streetType>Tipo Calle 0</streetType>
        <streetName>Nombre de Calle 0</streetName>
        <number>0</number>
    </address>
</person>

【讨论】:

  • 非常感谢罗曼!是的,我的问题是偏移量。跳过方法对我帮助很大。我也不得不重新设置位置。我的最终代码是: long [] l = vn.getElementFragment(); int offset = (int) (l[0] >> 64); int len = new Integer("" + l[1]); b = 新字节[len]; fis.getChannel().position(0); fis.skip(偏移量); fis.read(b, 0, len);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多