views:

39

answers:

1

Hi,

The good:

so, I have this binary data file (size - exactly 640631 bytes), and I'm trying to make Java read it.

I have two interchangeable classes implemented as layers for reading that data. One of them uses RandomAccessFile, which works great and all.

The bad:

Another one (the one this question is mostly about) tries to use FileInputStream and DataInputStream so that the very same data could be (at least theoretically) be read on MIDP 2.0 (CLDC 1.1) Java configuration (which doesn't have RandomAccessFile).

In that class, I open the data file like this:

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

...and implement seek()/skip() like this (position is a long that takes note of a current position in a file):

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);
    }
}

and

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;
}

The ugly:

The problem with the second class (the FileInputStream/DataInputStream one) is that sometimes it decides to reset the file position to some strange place in a file :) This happens both when I run this on J2SE (a computer) and J2ME (a mobile phone). Here's an example of the actual usage of that reader class and a bug that occurs:

// 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

I was able to determine that when asked to skip another 37 bytes, Java positioned the file pointer to byte 477 from the very start or file instead.

"Freshly" (just after opening a file) seeking to a position 189710 (and beyond that) works OK. However, reopening a file every time I need a seek() is just painfully slow, especially on a mobile phone.

What has happened?

A: 

I can see nothing wrong with this. Are you positive of the r.position value before the last skip? Unless there's an underlying bug in the JDK streams or if you have multiple multiple threads using the Reader, then the only possibility I can guess at is that something is modifying the position value incorrectly when you read your fields.

kaliatech
Hi, thanks for your answer. `r.position` value is just fine, the problem is with the *actual* position in a data file - Java somehow decides to move *backwards* in a file to an arbitrary position.
Linas
I understand. But since you did not provide the code for your readID, readName, etc. methods, the only remaining location for error (besides a low level stream bug) seems to be in those methods or the value of r.position. Consider the consequence if one of the readXXX methods inadvertently set the r.position value incorrectly by some sort of overflow error, or if they triggered an incorrect seek themselves. The last call to skip then could possibly be wrong whereas the first one was not. This is just a guess because I can think of nothing else that it could be.
kaliatech