Issue with stdin after piped input

I'm having difficulty accessing Standard In after reading data piped in at run-time. The data file is loaded into my app by piping it in to stdin at runtime via:

java -jar ./myapp.jar < data.txt

I'm able to capture the piped data, however, if I attempt to have the user interact with the console via keyboard after the piped data has been read, the system blocks indefinitely.

Step-by-step, what I've done is when the program starts, I use a BufferedReader(InputStreamReader(System.in)) and while loop through the contents of the BufferedReader until I hit null: while( (line = in.readLine()) != null ). This is the end of the file that was piped in, so I move on to processing the file.

After processing the data, I prompt the user for a course of action. The user's response is read by another BufferedReader(InputStreamReader(System.in)) and the program is supposed to continue on. However, at this step, during this second access to standard in via readLine(), the program hangs. No matter what I enter, the program won't go anywhere.

I've attempted to use BufferedReader's "close()" method, but that closes the underlying stream (and throws an error the next time I create a BufferedReader to it and try to access the same underlying stream). I've tried using the same BufferedReader for both accesses to stdin, however, it seems that once I hit "null" from reading the piped data file, adding more to stdin via the keyboard doesn't refresh the buffer. It doesn't seem like "readLine()" closes the stream when you hit null (otherwise I'd get an IOException next time I try to access it), it simply just doesn't recognize when new data has arrived.

Any suggestions on the best course of action to read piped data via stdin, and still have access to the stream to allow me to read keyboard inputs after the data file has been loaded? I thought about putting a string terminator at the end of the file so I'd catch the input before I hit the null, but I don't control the data file, so someone would have to manually touch the file before it's processed.

Thanks!

[2131 byte] By [Halcyon3742a] at [2007-11-26 16:21:22]
# 1
What does the user input?
levshow20a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 2

A simple "y" or "n" to continue.

After the data is loaded and processed, the user is presented some details on the data and they are asked if they want to continue.

Previously, this code read the data from a file that was identified within a configuration file. So it would read the data in via file and then prompt the user. It worked fine in this capacity. Only when the requirement came up that we be able to receive piped input did this stop working.

Halcyon3742a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 3
Have you read about the SequenceInputStream class? The firstInputStream of that stream could be that FileInputStream whilethe second one could be System.in itself.kind regards,Jos
JosAHa at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 4
I haven't. I'll take a look right now. Thanks for the reference...
Halcyon3742a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 5

The problem I see with SequenceInputStream is that when the data is piped in, it's coming from an InputStream via Standard In, and when the user is prompted, that comes from an InputStream via Standard In again. Only when the file is read via configuration file am I using a FileInputStream and then an InputStream from Standard In (for the prompt).

Can you using SequenceInputStream to stream System.in twice, and in doing so, still leave the second stream intact after the first is closed?

Halcyon3742a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 6

Maybe I just don't understand your problem but my idea was to open

a FileInputStream and do this:FileInputStream fis= new FileInputStream(args[1]);

SequenceInputStream sis= new SequenceInputStream(fis, System.in);

System.setIn(sis);

... and forget about all input redirection on the command line.

kind regards,

Jos

JosAHa at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 7

Let me try to clarify.

There are two scenarios for loading the data file. 1) Enter the filename in a configuration file. 2) Pipe the contents of a file from the command-line.

They are mutually exclusive. You will either do one, or the other. The piped file takes priority. So if the user doesn't pipe data from the command-line, my program loads the data from a flat-file as defined in the configuration. If the data is piped at the command-line, the configuration file is ignored and the data is loaded via stdin.

Once the data is loaded from one of the two sources, I process the data, and generate some info. That info is presented to the user so they can decide how to proceed. The user is expected to enter either "y" or "n" at the keyboard to continue or end the process. This is where it fails (or, more accurately, hangs when the data was read via pipe). If the data is read via FileReader, not a problem. Everything works. Only when I use an InputStreamReader to grab the contents of the data via input redirection, does it hang the next time I try to read something from stdin.

Halcyon3742a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 8

Look body

> java -jar ./myapp.jar < data.txt

You just redirected standard input to data.txt and have read everything from there.

Now, what do You expect? Of cause any attempt to read from stdin will block forever

or until something will drop into data.txt. Perhaps You can close and reopen the stream. But I would recommend You to open separate stream to read the data.txt.

_Dima_a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 9
Well, Halcyon, that isn't going to work. Your best bet is to get the requirements fixed. You can have piped input, or you can prompt the user, but you can't have both.
DrClapa at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 10

Here's a trimmed down version of what I'm trying...

BufferedReader in;

if(loadDataSrcStream){

in = new BufferedReader(new InputStreamReader(System.in));

} else{

in = new BufferedReader(new FileReader(dataSource));

}

String line;

while((line = in.readLine()) != null){

// Do something to load the data

}

// Do something to process the loaded data

if(skipCount > 0){

System.out.print("Entries in the source file have been skipped. Continue? (y/n): ");

BufferedReader prompt = new BufferedReader(new InputStreamReader(System.in));

while((line = prompt.readLine()) != null){

if("n".equalsIgnoreCase(line)){

return;

} else

break;

}

}

}

I've tried re-using "in" instead of "prompt" if the data was loaded via input redirection, however, I get the same result, so I tried something else.

In this example, after loading the data via stdin, when I get to the prompt, I've seem it to either hang or output garbage. If I load the data via the FileReader, it works fine.

Halcyon3742a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 11

> Well, Halcyon, that isn't going to work. Your best

> bet is to get the requirements fixed. You can have

> piped input, or you can prompt the user, but you

> can't have both.

Well ****.. that makes too much sense.. it seemed too obvious to be true, so I was hoping there was a possibility :)

Halcyon3742a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 12

I'm afraid you're overcomplicating things; when you allow a user to

redirect stdin to read a configuration file, how's you program to know

what it is reading? The keyboard? The config file? When is your program

ready to read that config file and how is it going to 'switch back' to

keyboard input?

Why don't you allow for an optional command line argument that

specifies the name of your config file? If the argument is supplied, use

it, if it isn't, read from a default config file and only then, read from a

non redirected stdin where your program will find the interactive user

input.

kind regards,

Jos

JosAHa at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 13
> Why don't you allow for an optional command line argumentYeh, I would do that way. If the last argument is present (You can check it with length) doread that file.
_Dima_a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...
# 14

I do have a command-line argument. They supply one to tell it what configuration file to load, and within that configuration file they can supply the path to the data source. Piping data in to override the config file's data source was something that was discussed. The thought was that if this was part of a script, the data source file might change, and could be dynamically supplied by the script, however, it's obvious now that any script would need to run silently anyway, so it becomes a non-issue the more I think about it.

Halcyon3742a at 2007-7-8 22:45:02 > top of Java-index,Java Essentials,Java Programming...