2010-10-18 33 views
13

Tôi đang viết một tiện ích dòng lệnh nhỏ với mục đích là phân tích đầu ra của một tiện ích khác. Tôi muốn nó được invokable theo hai cách:Kiểm tra đầu vào tiêu chuẩn trong C#

c:\> myutility filewithoutput.txt 

Hoặc,

c:\> otherutility -args | myutility 

Vì vậy, về cơ bản, tiêu chuẩn trong hoặc một đối số tập tin. Nỗ lực đầu tiên của tôi tại này trông như thế này:

TextReader reader; 

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

Process(reader); 

Đối số tập tin hoạt động tốt, và đường ống đầu ra từ các tiện ích để tiện ích của tôi hoạt động tốt, nhưng nếu bạn chỉ cần gọi nó bình thường (không có đối số và không có dữ liệu bằng đường ống) nó bị treo. Hay nói đúng hơn, nó ngăn chặn trên chờ đợi để đọc từ tiêu chuẩn trong

dự thảo thứ hai của tôi trông như thế này:.

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

Trong khi KeyAvailable sửa các "không có đầu vào" vấn đề, nó ném một ngoại lệ nếu bạn cố gắng ống trong dữ liệu> _ <

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 

Trường hợp ngoại lệ cho tôi sử dụng Console.In.Peek, vì vậy dự thảo tiếp theo của tôi là như vậy:

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

Tuy nhiên, điều này có cùng một vấn đề như lần thử đầu tiên: Nó chặn, tìm đầu vào. Argh!

Tôi đang thiếu cái gì?

Sidenote: Tôi biết quy ước của đối số "-" có nghĩa là "sử dụng đầu vào tiêu chuẩn". Tôi sẽ sử dụng nó nếu không có cách nào khác. Nhưng, chắc chắn phải có một số cách để phát hiện nếu tiêu chuẩn trong là giao diện điều khiển hay không!

Edit: Đây là phiên bản cuối cùng mà dường như làm những gì tôi cần:

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

Không phải là một fan hâm mộ lớn của việc sử dụng ngoại lệ đối với dòng chảy như vậy, nhưng ... eh.

+0

Đây có phải là có liên quan? http: // efreedom.com/Question/1-3453220/Detect-ConsoleIn-Stdin-Redirected – bzlm

+2

@bzlm - tại sao không liên kết trực tiếp đến nguồn (xảy ra là Stack Overflow): http://stackoverflow.com/questions/3453220 –

+0

@ John Oh , do đó, lỗi * của tôi * mà SO không xếp hạng cao nhất cho các cụm từ tìm kiếm mà tôi đã nhập. :) – bzlm

Trả lời

5

Tôi đã sử dụng giải pháp của Pieter trong một thời gian cho đến khi tôi nhận ra nó không hoạt động trong Mono. Mono không ném ngoại lệ khi truy xuất Console.KeyAvailable với đầu vào đường ống, do đó cách tiếp cận đó không giúp ích gì.

Tuy nhiên, tính đến .NET 4.5, Console thực sự cung cấp một lĩnh vực mới IsInputRedirected mà làm này rất nhiều đơn giản hơn, loại bỏ tối tăm và không cần thiết 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

Xem lại điều này chỉ 5 năm sau, điều này nghe có vẻ như câu trả lời đúng mới. Mát mẻ! –

10

Cách nhanh chóng và bẩn là bao bọc Console.KeyAvailable trong try/catch và nếu điều đó ném, bạn biết rằng đầu vào được chuyển hướng từ một tệp. Nó không phải là rất bất thường để sử dụng try/catch để phát hiện một nhà nước khi bạn không thể tìm thấy một phương pháp thích hợp để làm việc kiểm tra cho bạn.

+0

... Tôi thực sự ghét nó khi câu trả lời rất rõ ràng, họ bay ngay bên cạnh tôi. Mặc dù, tôi vẫn không thích thực tế là không có cách nào được xây dựng để làm điều này ... –

+0

Thật không may, điều này dường như không hoạt động trong Mono, [nhưng kể từ .NET 4.5 có một giải pháp đơn giản hơn] (http : //stackoverflow.com/a/34253814/1633117). –

1

Có vẻ như bạn sẽ có thể sử dụng một số cuộc gọi API Windows để xác định điều đó. Hans Passant's answer thậm chí có một lớp trợ giúp để bọc tất cả lên.

Các vấn đề liên quan