Search code examples
javausbbufferedreaderbufferedinputstream

Java available bytes for BufferedInputStream isn't working


I've got a simple test application which connects to a USB device (as a local file), transmits a start transmission character, and then reads the input from the device. This all works fine, but infrequently it would block on the read() call. To prevent this I attempted to check whether there are at least 1 available bytes before proceeding with the read() operation. However when I run this I get an IOException from the available() call.

My code is:

public static void testRecord() {
    // Records data for a second
    String portName = "\\\\.\\<DEVICE_FILE>";
    FileWriter out = null;
    byte singleByte;
    long startTime = System.currentTimeMillis();
    try {

        out = new FileWriter(portName);
        out.write('c');     // start data transmission
        out.write(0x0d);    // carriage return required
        out.flush();
        if (out != null)
            out.close();

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(portName), 512);
        System.out.println("Connected to device");

        while(System.currentTimeMillis() < startTime+1000) {
            avail = bis.available();
            if (!(avail > 0)) {
                System.out.println("Available: " + avail);
                continue;
            }

            singleByte = (byte) bis.read();
            // Do stuff with data    
        }
        if (bis != null)
            bis.close();              
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        System.out.println("ERROR");
    }

}

The Error trace is:

Connected to device
java.io.IOException
    at java.io.FileInputStream.available(Native Method)
    at java.io.BufferedInputStream.available(Unknown Source)
    at test.Test.testRecord(Test.java:58)
    at test.Test.main(Test.java:135)
ERROR

Am I doing something wrong? If I comment out the available() call it works perfectly aside from the issue that it blocks on read() approximately once every 50 runs. I've also tried implementing the reader as a BufferedReader over a InputStreamReader (as the data is ASCII) and using the ready() method of BufferedReader but that always returns false.

EDIT: I'm looking at alternatives to checking if there is data available before reading, most of which involve handling a blocking read() call. I've got an outer thread checking for a timeout, but if there is a timeout, trying to stop the thread with thread.interrupt() still won't interrupt the blocking read() call. Likewise closing the InputStream from the outer thread doesn't work either as the call is still blocked. I also tried the solution here https://stackoverflow.com/a/9832633/1020006 but executor.shutdownNow() is just a wrapper for Thread.interrupt() and so has the same issue. I want to avoid using Thread.stop() as it's deprecated.

The only other choice I can see is rewriting the reading using a FileChannel which are asynchronously interruptible.

EDIT 2: I tried using Thread.stop() but this also didn't work, as pointed out by Peter Lawrey in the comments this is indicative behaviour of a system fault. I managed to get it all working by refactoring the reading into an AsynchronousFileChannel object, which returns a Future object from its read call. The data can be obtained from the Future with a timeout in the get() method. This then throws a TimeoutException which can be caught to close up the channel.


Solution

  • Read the edits for the different methods I tried, but I managed to get it all working by refactoring the reading into an AsynchronousFileChannel object, which returns a Future object from its read call. The data can be obtained from the Future with a timeout in the get() method. This then throws a TimeoutException which can be caught to close up the channel.