I'm writing a small command line utility whose purpose is to parse the output of another utility. I want it to be invokable in two ways:
c:\> myutility filewithoutput.txt
Or,
c:\> otherutility -args | myutility
So, basically, standard in or a file argument. My first attempt at this looked like this:
TextReader reader;
if (args.Length > 1) {
reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
reader = Console.In;
}
Process(reader);
The file argument works fine, and piping the output from the utility to my utility works fine, but if you just invoke it normally (no arguments and no piped data), it hangs. Or, rather, it blocks on waiting to read from standard in.
My second draft looked like this:
TextReader reader;
if (args.Length > 1) {
reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
if(Console.KeyAvailable) {
reader = Console.In;
} else {
Console.WriteLine("Error, need data");
return;
}
}
Process(reader);
While KeyAvailable
fixes the "no input" problem, it throws an exception if you try to pipe in data >_<
Unhandled Exception: System.InvalidOperationException: Cannot see if a key
has been pressed when either application does not have a console or when
console input has been redirected from a file. Try Console.In.Peek.
at System.Console.get_KeyAvailable()
at MyUtility.Program.Main(String[] args) in Program.cs:line 39
The exception suggests I use Console.In.Peek
, so my next draft is as such:
TextReader reader;
if (args.Length > 1) {
reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
if(Console.In.Peek() != 0) {
reader = Console.In;
} else {
Console.WriteLine("Error, need data");
return;
}
}
Process(reader);
However, this has the same problem as the first try: It blocks, looking for input. Argh!
Is there something I'm missing?
Sidenote: I am aware of the convention of the argument "-" meaning "use standard input". I will use that if there's no other way. But, surely there's got to be some way of detecting if standard in is the console or not!
Edit: Here's the final version that seems to do what I need:
TextReader reader;
if (args.Length > 1) {
reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
try {
bool tmp = Console.KeyAvailable;
Console.WriteLine("Error, need data");
return;
} catch(InvalidOperationException) {
reader = Console.In;
}
}
Process(reader);
Not a big fan of using Exceptions for flow like that, but... eh.