2010-10-18 18 views
13

Estoy escribiendo una pequeña utilidad de línea de comandos cuyo propósito es analizar el resultado de otra utilidad. Yo quiero que sea invocable de dos maneras:Comprobación de entrada estándar en C#

c:\> myutility filewithoutput.txt 

O

c:\> otherutility -args | myutility 

Así que, básicamente, estándar o en un argumento de archivo. Mi primer intento en esta era la siguiente:

TextReader reader; 

if (args.Length > 1) { 
    reader = new StreamReader(new FileStream(args[1], FileMode.Open)); 
} else { 
    reader = Console.In; 
} 

Process(reader); 

El argumento de archivo funciona bien, y una tubería de la salida de la utilidad a mi utilidad funciona bien, pero si sólo invoca normalmente (sin argumentos ni datos por tubería) , se cuelga O, más bien, se bloquea en espera de leer desde la entrada estándar

Mi segundo proyecto era la siguiente:.

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); 

Mientras KeyAvailable fija el "sin entrada" problema, se produce una excepción si se intenta pipa en los datos> _ <

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 

La excepción sugiere que utilizo Console.In.Peek, por lo que mi próximo proyecto es como tal:

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); 

Sin embargo, esto tiene el mismo problema que el primer intento: bloquea, buscando entrada. Argh!

¿Hay algo que me falta?

Nota: Soy consciente de la convención del argumento "-" que significa "uso de entrada estándar". Lo usaré si no hay otra manera. Pero, seguramente, debe haber alguna manera de detectar si el estándar es la consola o no.

Editar: Aquí está la versión final que parece hacer lo que necesito:

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); 
No

un gran fan de la utilización de excepciones para el flujo de esa manera, pero ... eh.

+0

¿Es esto relevante? http: // efreedom.com/Question/1-3453220/Detect-ConsoleIn-Stdin-Redirected – bzlm

+2

@bzlm - por qué no enlazar directamente a la fuente (que pasa a ser Stack Overflow): http://stackoverflow.com/questions/3453220 –

+0

@John Oh , por lo que es * mi * culpa que SO no se clasifique como el más alto para los términos de búsqueda que ingresé. :) – bzlm

Respuesta

5

He estado usando la solución de Pieter por un tiempo hasta que me di cuenta de que no funciona en Mono. Mono no lanza una excepción al recuperar Console.KeyAvailable con entrada entonada, por lo que ese enfoque no ayuda.

Sin embargo, a partir de .NET 4.5, Console en realidad ofrece un nuevo campo IsInputRedirected que hace esto mucho más simple, elimina la oscuridad y la innecesaria try/catch:

TextReader reader; 

if (args.Length > 1) { 
    reader = new StreamReader(new FileStream(args[1], FileMode.Open)); 
} else { 
    if (Console.IsInputRedirected) { 
     reader = Console.In; 
    } else { 
     Console.WriteLine("Error, need data"); 
     return; 
    } 
} 

Process(reader); 
+0

Revisando esto apenas 5 años después, esta parece la nueva respuesta correcta. ¡Guay! –

10

La manera rápida y sucia es envolver Console.KeyAvailable en try/catch y si eso sucede, usted sabe que la entrada se redirige desde un archivo. No es muy inusual usar try/catch para detectar un estado cuando no puede encontrar un método apropiado para hacer la verificación por usted.

+0

... Realmente odio que las respuestas sean tan obvias, que pasen volando por mi cuenta. Sin embargo, todavía no me gusta el hecho de que no haya una forma de hacerlo ... –

+0

Desafortunadamente, esto no parece funcionar en Mono, [pero a partir de .NET 4.5 hay una solución más simple] (http : //stackoverflow.com/a/34253814/1633117). –

1

Parece que debería poder utilizar algunas llamadas a la API de Windows para determinarlo. Hans Passant's answer incluso tiene una clase de ayuda para envolverlo todo.

Cuestiones relacionadas