2010-10-18 22 views
13

Sto scrivendo una piccola utility da riga di comando il cui scopo è analizzare l'output di un'altra utility. Io voglio che sia richiamabile in due modi:Controllo input standard in C#

c:\> myutility filewithoutput.txt 

Oppure,

c:\> otherutility -args | myutility 

Quindi, in sostanza, di serie o un file come argomento. Il mio primo tentativo di questo si presentava così:

TextReader reader; 

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

Process(reader); 

L'argomento file funziona bene, e piping l'uscita dal programma di utilità per il mio programma di utilità funziona bene, ma solo se si richiama normalmente (senza argomenti e con nessun dato convogliato) , si blocca. O, piuttosto, si blocca su in attesa di leggere da standard

Il mio secondo progetto si presentava così:.

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

Mentre KeyAvailable correzioni del "nessun input" problema, viene generata un'eccezione se si tenta di pipe nei dati> _ <

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 

L'eccezione suggerisce che uso Console.In.Peek, quindi il mio prossimo progetto è in quanto tale:

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

Tuttavia, questo ha lo stesso problema del primo tentativo: blocca, cercando input. Argh!

C'è qualcosa che mi manca?

Sidenote: Sono a conoscenza della convenzione dell'argomento "-" che significa "utilizza input standard". Lo userò se non c'è altro modo. Ma, sicuramente, ci deve essere un modo per scoprire se lo standard è la console o no!

Edit: Ecco la versione finale che sembra fare quello che mi serve:

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

Non è un grande fan di utilizzare eccezioni per il flusso del genere, ma ... eh.

+0

È questo rilevante? http: // efreedom.it/Domanda/1-3453220/Rileva-ConsoleIn-Stdin-Redirected – bzlm

+2

@bzlm - perché non collegarsi direttamente alla fonte (che capita di essere Stack Overflow): http://stackoverflow.com/questions/3453220 –

+0

@John Oh , quindi è * mia * colpa che SO non abbia il punteggio più alto per i termini di ricerca inseriti. :) – bzlm

risposta

5

Ho usato la soluzione di Pieter per un po 'fino a quando ho realizzato che non funziona in Mono. Mono non lancia un'eccezione quando recupera Console.KeyAvailable con l'input con pipe, quindi questo approccio non aiuta.

Tuttavia, come di .NET 4.5, Console in realtà fornisce un nuovo campo IsInputRedirected che rende questo molto più semplice, rimuove l'oscurità e il superfluo 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

Rivisitando questo a soli 5 anni dopo, questa sembra la nuova risposta corretta. Freddo! –

10

Il modo rapido e sporco è quello di avvolgere Console.KeyAvailable in un try/catch e se questo genera, si sa che l'input viene reindirizzato da un file. Non è insolito utilizzare try/catch per rilevare uno stato quando non riesci a trovare un metodo appropriato per eseguire il controllo.

+0

... Odio davvero quando le risposte sono così ovvie, volano proprio vicino a me. Tuttavia, non mi piace il fatto che non ci sia un modo per farlo ... –

+0

Sfortunatamente, questo non sembra funzionare in Mono, [ma a partire da .NET 4.5 c'è una soluzione più semplice] (http : //stackoverflow.com/a/34253814/1633117). –

1

Sembra che dovresti essere in grado di utilizzare alcune chiamate API Windows per determinarlo. Hans Passant's answer ha persino una classe di supporto per concludere tutto.