【问题标题】:Strange FileInputStream/DataFileInputStream behaviour: seek()ing to odd positions奇怪的 FileInputStream/DataFileInputStream 行为:seek()ing 到奇数位置
【发布时间】:2026-01-11 00:15:02
【问题描述】:

好的:

所以,我有这个二进制数据文件(大小 - 正好 640631 字节),我正在尝试让 Java 读取它。

我有两个可互换的类实现为用于读取该数据的层。其中一个使用RandomAccessFile,效果很好。

坏处:

另一个(这个问题主要是关于)尝试使用FileInputStreamDataInputStream,以便可以(至少在理论上)在 MIDP 2.0 (CLDC 1.1) Java 配置(其中没有RandomAccessFile)。

在那个类中,我这样打开数据文件:

FileInputStream res = new FileInputStream(new File(filename));
h = new DataInputStream(res);

...并像这样实现seek()/skip()position 是一个long,它记录了文件中的当前位置):

public void seek(long pos) throws java.io.IOException {

    if (! this.isOpen()) {
        throw new java.io.IOException("No file is open");
    }

    if (pos < position) {
        // Seek to the start, then skip some bytes
        this.reset();
        this.skip(pos);
    } else if (pos > position) {
        // skip the remaining bytes until the position
        this.skip(pos - position);
    }
}

public void skip(long bytes) throws java.io.IOException {

    if (! this.isOpen()) {
        throw new java.io.IOException("No file is open");
    }

    long skipped = 0, step = 0;

    do {
        step = h.skipBytes((int)(bytes - skipped));
        if (step < 0) {
            throw new java.io.IOException("skip() failed");
        }
        skipped += step;
    } while (skipped < bytes);

    position += bytes;
}

丑陋的:

第二类(FileInputStream/DataInputStream)的问题是有时它决定将文件位置重置到文件中的某个奇怪位置:) 当我在 J2SE 上运行它时都会发生这种情况(a电脑)和 J2ME(手机)。以下是该阅读器类的实际使用示例和发生的错误:

// Open the data file
Reader r = new Reader(filename);

// r.position = 0, actual position in a file = 0

// Skip to where the data block that is needed starts
// (determined by some other code)
r.seek(189248);

// r.position = 189248, actual position in a file = 189248

// Do some reading...
r.readID(); r.readName(); r.readSurname();

// r.position = 189332, actual position in a file = 189332

// Skip some bytes (an unneeded record)
r.skip(288);

// r.position = 189620, actual position in a file = 189620

// Do some more reading...
r.readID(); r.readName(); r.readSurname();

// r.position = 189673, actual position in a file = 189673

// Skip some bytes (an unneeded record)
r.skip(37);

// AAAAND HERE WE GO:
// r.position = 189710, actual position in a file = 477

我能够确定,当被要求跳过另外 37 个字节时,Java 将文件指针从一开始就定位到第 477 个字节或文件。

“新鲜”(刚打开文件后)寻找位置 189710(及以上)工作正常。但是,每次我需要 seek() 时重新打开文件实在是太慢了,尤其是在手机上。

发生了什么事?

【问题讨论】:

  • 看起来你的记忆已经结束了。

标签: java java-me java-io


【解决方案1】:

我看不出这有什么问题。您对最后一次跳过之前的 r.position 值持肯定态度吗?除非 JDK 流中存在潜在错误,或者如果您有多个使用 Reader 的线程,那么我能猜到的唯一可能性是,当您读取字段时,某些东西会错误地修改位置值。

【讨论】:

  • 您好,感谢您的回答。 r.position 值很好,问题在于数据文件中的 实际 位置 - Java 以某种方式决定将文件中的 向后 移动到任意位置。跨度>
  • 我明白了。但是由于您没有为您的 readID、readName 等方法提供代码,因此唯一剩余的错误位置(除了低级流错误)似乎在这些方法或 r.position 的值中。考虑一下如果其中一个 readXXX 方法由于某种溢出错误而无意中错误地设置了 r.position 值,或者它们自己触发了不正确的搜索,会产生什么后果。最后一次跳过然后可能是错误的,而第一个不是。这只是一个猜测,因为我想不出还有什么可能。