Search code examples
javafile-iobufferedinputstream

BufferedInputStream not working with random seeks in file


The write procedure to my file was as follows (in the mode which I call non-clustered)

  1. Write an object to the current position of the file. Note the position of write in another file (called the index file) so I know where have I placed the objects.
  2. Leave some space (Randomly 1/2/3/4 KB of space) by writing zero bytes
  3. Repeat steps 1 and 2

Now I decided to read the objects back from the file. But I wanted to use BufferedInputStream. However when I encapsulate a BufferedInputStream inside an ObjectInputStream I get errors after reading some of the objects. I am guessing this happens after One buffered Read (i.e. as many objects as can fit in the buffer are read once, the next time I get an error).

On the Other hand encapsulating a FileInputStream directly inside a ObjectInputStream works without any problem.

If needed, I will provide the file writing code too. Feel free to ask anything about the code below.

public class RecordsFileReader {
    RecordsFile rFile;
    Iterator itr;
    FileInputStream fis;
    ObjectInputStream ois;

// The constructor
public RecordsFileReader(RecordsFile rFile) throws IOException, ClassNotFoundException {
    this.rFile = rFile;
    fis = new FileInputStream(rFile.getFileName());


    ObjectInputStream ois2 = new ObjectInputStream(new FileInputStream(rFile.getFileName() + ".index"));



    rFile.recordsLocationList =  (ArrayList <Long>) ois2.readObject();
    itr = rFile.recordsLocationList.iterator();
   /**********************************************************/
   /*          HERE IS THE PROBLEM.                          */
   /* Doesnt work when I additionally use BufferedInputStream*/
   /**********************************************************/

    ois = new ObjectInputStream(fis);

   /**********************************************************/     
}

public Tuple readNext() throws IOException, ClassNotFoundException {
    if(!itr.hasNext())
        return null;
    Long nextRecordPosition = itr.next();
    fis.getChannel().position(nextRecordPosition);
    //System.out.println((Tuple) ois.readObject());
    return ((Tuple) ois.readObject());
}

public void close() throws IOException {
    ois.close();
    fis.close();



}

public boolean hasNext() {
    return itr.hasNext();

}

}

public class RecordsFile {

boolean clustered;
private String fileName;

public RecordsFile(String fileName, boolean clustered) throws IOException {
    this.fileName = fileName;
    this.clustered = clustered;
}

/*
The byte positions at which the records are located in the file.
*/
ArrayList<Long> recordsLocationList= new ArrayList<Long>();

public String getFileName() {
    return fileName;
}

}

This is the change that is causing the error : ois = new ObjectInputStream(new BufferedInputStream(fis, 4096)); instead of ois = new ObjectInputStream(fis);

The error is java.io.StreamCorruptionException: invalid type code : 00

EDIT :

I have now figured out the problem. While my fis was being positioned to a new position, my bis was not being skipped to that new position. Instead bis was trying to read from the old position only and hence the exception


Solution

  • This is indicative of a case where the bytes being read back from the stream ( and from the file ) are being interpreted as an object ( by the OIS ) but actually these bytes are something else ( not a byte representation of an actual object ). This may be because of the buffer size being specified explicitly ( combined with the fact that you are setting the position manually ).

    I would suggest to try without specifying the buffer size explicitly.

    ois = new ObjectInputStream(new BufferedInputStream(fis))