1

Here is a section of code in my Java program (in the main thread) :

int bufSize = 4096; // 4k buffer.
byte[] buffer = new byte[bufSize]; 
int bytesAvailable, bytesRead;
try {
    while ( true ) {
        bytesAvailable = System.in.available(); // seems may throw IOException if InputStream is closed.
        if ( bytesAvailable > 0 ) {
            if ( bytesAvailable > bufSize ) {
                bytesAvailable = bufSize;
            }
            // The following statement seems should not block. 
            bytesRead = System.in.read(buffer, 0, bytesAvailable);
            if ( bytesRead == -1 ) {
                myOutputStream.close();
                System.out.println("NonBlockingReadTest : return by EOF.");
                return;
            }
            myOutputStream.write(buffer, 0, bytesRead);
            myOutputStream.flush();
        } else if ( bytesAvailable == 0 ) {
            // Nothing to do, just loop over.
        } else { 
            // Error ! Should not be here !
        }
    }
} catch (IOException e) {
.....

The program runs OK. It just reads (in a non-blocking way) some input from stdin and then write the input to a file. I have used "System.in.available()" so that the "System.in.read(buffer, 0, bytesAvailable)" statement would not block.

However, I could not terminate the program by typing "ctrl-D" in the keyboard. I could only terminate it by "ctrl-C" and I think that's not a graceful way. It seems that the "bytesRead == -1" condition is never true.

Is that any modification I could do so that the program could be terminated by "ctrl-D". Any idea, thanks.

user1129812
  • 2,859
  • 8
  • 32
  • 45
  • System.in.read(buffer, 0, bytesAvailable); does not block because there are bytesAvailable as you checked in System.in.available(). – pringi Dec 15 '16 at 13:16
  • Also please check this http://stackoverflow.com/questions/5837823/read-input-until-controld. I think it is what you are asking for. – pringi Dec 15 '16 at 13:19
  • @pringi I know that solution, but what I concern here is to keep my while loop in a non-block mode. I may check other flags in the while loop, so if the while loop blocks in a read statement, I may not have a chance to check other flags/conditions to make further decisions. – user1129812 Dec 15 '16 at 13:58
  • I think the main point is that I am using `System.in.available()` which allows me a non-blocking read. The `System.in.read` statement would not be reached if `System.in.available()` doesn't give any >0 result. But typing ctrl-D in the keyboard seems don't let `System.in.available()` to give any >0 result. That's the point. – user1129812 Dec 15 '16 at 23:26

2 Answers2

1

Based on Read Input until control+d

You can use ByteBuffer to read ints from your buffer. Then you can compare that int to 4. If it is then it's a CTRL+D.

If you see Aleadam response you can see how to check for CTRL+D:

public class InputTest {
  public static void main(String[] args) throws IOException {
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    StringBuilder out = new StringBuilder();
    while (true) {
      try {
        int c = in.read();
        if (c != 4)  // ASCII 4 04 EOT (end of transmission) ctrl D, I may be wrong here
            out.append (c);
        else
            break;
      } catch (IOException e) {
        System.err.println ("Error reading input");
      }
    }
    System.out.println(out.toString());
  }
}

If you see this Convert a byte array to integer in java and vice versa

and Jeff Mercado response you can do the following:

byte[] arr = { 0x00, 0x01 };
ByteBuffer wrapped = ByteBuffer.wrap(arr); // big-endian by default
short num = wrapped.getShort(); // 1

ByteBuffer dbuf = ByteBuffer.allocate(2);
dbuf.putShort(num);
byte[] bytes = dbuf.array(); // { 0, 1 }
Community
  • 1
  • 1
pringi
  • 3,987
  • 5
  • 35
  • 45
  • Thanks, but I need to use `System.in.available()` for non-blocking read and this seems cause me trouble for terminating through ctrl-D. – user1129812 Dec 15 '16 at 23:20
0

give this code a try. it worked for me:

try {
    while ((bytesAvailable = System.in.read(buffer)) != -1) {
        myOutputStream.write(buffer, 0, bytesAvailable);
        myOutputStream.flush();
} catch (IOException e) {}

CTRL-D will causes the terminal to make the buffered input available. If there is nothing on a line of its own, CTRL+D sends an EOF signal to the System.in InputStream which is -1.

Quintin Balsdon
  • 5,484
  • 10
  • 54
  • 95
Tyorofurin
  • 11
  • 3
  • I know this approach. My point is that I need to use `System.in.available()` so that the while loop would not block. However, `System.in.available()` seems do not give any >0 result when we type ctrl-D in the keyboard. – user1129812 Dec 15 '16 at 23:16