1

I'm new to Java, and I wrote a parser that works on RandomAccessFile (the file format requires random positioning). For JUnit testing I feed different sample input files into the parser.

Now I thought I could write easier JUnit tests after having changed the parser to read from an InputStream instead (that would be created by a JUnit test).

But to be able to perform the non-testing use case, I'd have to create (or update) an InputStream to read where the RandomAccessFile currently points to. Is that possible? Of course the solution should be both, efficient and elegant.

U. Windl
  • 3,480
  • 26
  • 54
  • It might be easier to help you if you showed some code. – Andy Turner May 22 '18 at 07:46
  • @Andy Turner: The code to open a `RandomAcessFile`, the code to read from such a file, or the (not-yet-existing) code to read from an `InputStream`? Or what exactly are you looking for? – U. Windl May 22 '18 at 07:48
  • From https://stackoverflow.com/questions/9287664/why-cant-a-randomaccessfile-be-casted-to-inputstream I get the idea that a `SeekableByteChannel` with `Channels.newInputStream()` sounds like a possible solution, but unbuffered. – U. Windl May 22 '18 at 08:15
  • Reading the description of `InputStream` (`BufferedInputStream`) I wonder whether it would be easiest to implement a new class delegating to `RandomAccessFile`, adding `setPosition()` (and invalidating the buffer on position canges in case of `BufferedInputStream`). – U. Windl May 22 '18 at 08:31

1 Answers1

2

As nobody had a more clever idea, here is what I did. Unfortunately the very restricted nature of constructors and the use of super() and the lack of multiple inheritance in Java makes the implementation harder and uglier than necessary. Also the lack of a protected invalidate() for the buffer of BufferedInputStream caused me to guess how to do it (a test showed that it works):

package de.whatever.uw.utils;

import java.io.BufferedInputStream;

/**
 * @author U. Windl
 */
public class RandomAccessFileInputStream extends BufferedInputStream {

    private RandomAccessFile file;  // file to use

   /**
     * Constructor
     * @param fileName File to open for reading
     * @throws FileNotFoundException 
     */
    public RandomAccessFileInputStream(String fileName) throws FileNotFoundException {
        super(System.in);   // dummy to work around Java's inflexibility
        assert fileName != null;
        file = new RandomAccessFile(fileName, "r");
        FileChannel channel = file.getChannel();
        in = new BufferedInputStream(Channels.newInputStream(channel));
        assert file != null;
    }

    /**
     * Forbidden Constructor
     * @param in Input stream
     */
    private RandomAccessFileInputStream(InputStream in) {
        super(in);
    }

    /**
     * Forbidden Constructor
     * @param in
     * @param size
     */
    private RandomAccessFileInputStream(InputStream in, int size) {
        super(in, size);
    }

    /* (non-Javadoc)
     * @see java.io.BufferedInputStream#close()
     */
    public void close() throws IOException {
        super.close();
        file.close();
    }

    /**
     * @return Current offset in stream
     * @throws IOException
     */
    public long getFilePointer() throws IOException {
        return file.getFilePointer();
    }

    /**
     * @return
     * @throws IOException
     * @see java.io.RandomAccessFile#length()
     */
    public long length() throws IOException {
        return file.length();
    }

    /**
     * @param pos New stream position
     * @throws IOException
     */
    public void seek(long pos) throws IOException {
        file.seek(pos);
        pos = count = 0;    // invalidate stream buffer
    }

    // other methods are inherited without change (and I really use a very few of them actually)
}

(I had created a special test file of about 8kB size to test positioning and buffering: After a position change the correct data is read (invalidating the buffer seems to work), and more than the requested data size is read (i.e. buffering also works).)

U. Windl
  • 3,480
  • 26
  • 54