Process StandartOutput.ReadLine() Hangs - c#

Hey i'm trying to read the output stream from cmd.exe
here is the code used
string r = string.Empty;
while(!cmd.StandardOutput.EndOfStream)
{
r = cmd.StandardOutput.ReadLine(); /*the app hangs here after trying to read the last line*/
MessageBox.Show(r);
}
tried also that :
StreamReader reader = cmd.StandardOutput;
cmd.Close();
while(!reader.EndOfStream)
{
r = reader.ReadLine(); /*the app hangs here after trying to read the last line*/
MessageBox.Show(r);
}
same problem again.
i've replaced EndOfStream with peek()>=0 didn't work
tried to copy the base stream of cmd.StandardOutput into another stream using the method CopyTo() and it didn't work for me
SOLUTION
should add
cmd.StandardInput.WriteLine("exit");
before reading from the output stream
thanks to Hans Passant
That's expected, it is not going to exit that loop until you send it
the EXIT command so it closes its output stream. Not reading
StandardError is also a pretty good way to deadlock it. This only ever
works well when you use BeginOutput/ErrorReadLine().
– Hans Passant

ReadLine() returns the next line from the input stream, or null if the end of the input stream is reached. So you can do this:
var line = reader.ReadLine();
while(line != null)
{
MessageBox.Show(line);
line = reader.ReadLine();
}

Related

Strange question mark, when setting StreamReader to beginning

I am writing a program about job interview. Everything is working properly, except one thing. When I use an outside method TotalLines (where I have seperate StreamReader), it is working properly, but when I am calculating a number of totalLines in the program, I am receiving one question mark on the beginning of the first question. So it is like that:
?What is your name?
but in the text file from which I am reading, I have just - What is your name?
I have no idea why is that. Maybe it is problem with that I am returning StreamReader to beginning? I checked my encoding, everything, but nothing worked. Thanks for your help :)
PotentialEmployee potentialEmployee = new PotentialEmployee();
using (StreamReader InterviewQuestions = new StreamReader(text, Encoding.Unicode))
{
int totalLines = 0;
while (InterviewQuestions.ReadLine() != null)
{
totalLines++;
}
InterviewQuestions.DiscardBufferedData();
InterviewQuestions.BaseStream.Seek(0, SeekOrigin.Begin);
for (int numberOfQuestions = 0; numberOfQuestions < totalLines; numberOfQuestions++)
{
string question = InterviewQuestions.ReadLine();
Console.WriteLine(question);
string response = Console.ReadLine();
potentialEmployee.Responses.Add(question, response);
}
}
But when I have a TotalLines calculation in the outside method, the question mark does not show. Any ideas plase?
It's very likely that the file starts with a byte order mark (BOM) which is being ignored by the reader initially, but then not when you "rewind" the stream.
While you could create a new reader, or even just replace it after reading it, I think it would be better to just avoid reading the file twice to start with:
foreach (var question in File.ReadLines(text, Encoding.Unicode))
{
Console.WriteLine(question);
string response = Console.ReadLine();
potentialEmployee.Responses.Add(question, response);
}
That's shorter, simpler, more efficient code that also won't display the problem you asked about.
If you want to make sure you can read the whole file before asking any questions, that's easy too:
string[] questions = File.ReadAllLines(text, Encoding.Unicode);
foreach (var question in questions)
{
Console.WriteLine(question);
string response = Console.ReadLine();
potentialEmployee.Responses.Add(question, response);
}
Whenever you seek your stream to the beginning, the Byte Order Mark (BOM) is not read again, it's only done the first time after you create a stream reader with Encoding specified.
In order for the BOM to be read correctly again, you need to create a new stream reader. However, you can reuse the stream if you instruct the stream reader to keep the stream open after the reader is disposed, but be sure to seek before you create a new reader.
String s="aasddd??dsfas?df";
s.replace('?','\0');

Read many of the StreamReader

I have little problem. My code in visual studio:
file = new StreamReader("D:\\BaseList.txt");
string line;
while ((line = file.ReadLine()) != null)
{
listBox1.Items.Add(line);
}
file.Close(); // 1
file = new StreamReader("D:\\Baza3.txt"); //2
I read all lines in file and I would like once more to read from the beginning. Do I have to close the stream and reload the file to stream( line numbered 1 and 2)?
Is there a method, which allows to set the stream at the beginning of my file without using this numbered line?
You can reset the position of the base stream like this
streamReader.BaseStream.Position = 0;
You can do that only if the base stream is seekable. (myStream.CanSeek == true). The is true in your case when you create a new StreamReader with a path string.
Try setting the BaseStream Position to 0, or copying the contents to a MemoryStream before actually start reading it.
Check out this thread:
Return StreamReader to Beginning

The process cannot access file due to opened already

The code running on wince 5.0 / .net framework compact 2.0
Always get a exception says:
the process cannot access the file because it is being used by another process.
Really confused as i already encolse the stream in the using statement,so the filestream should be closed automaticly once leave the using block .
//read text
using (StreamReader sr = File.OpenText(fname))
{
string line;
while ((line = sr.ReadLine()) != null)
{
// append into stringbuilder
sb.Append(line);
sb.Append("\n");
}
}
//write text, below code raise the exception.
//if i comment it and re-run the code,exception disappear
using (StreamWriter sw = File.CreateText(fname))
{
sw.Write(sb.ToString());
}
addition:i just want to update the file, read and write. any better way?
sorry guys, the issue is in my code and i confused you here as i dont share that code.
actually because i wrote this in the very beginning of the program
// f is the fileinfo which point to fname as well
string text = f.OpenText().ReadToEnd();
this created a streamreader, not being assigned to any varible, but it's in the heap.so i ignored.
thanks people helpping here. BTW changed code to this then issue gone
using (StreamReader sr = f.OpenText())
{
string text = sr.ReadToEnd();
}
I tested this code on my computer. There is no problem.
Better way. For read and write full file, you can use File.ReadAllText(fname) and File.WriteAllText(fname). And instead of using \n use Environment.NewLine

C#: Using StreamReader to read line from txt file, but Peek() return -1 even there are a lot of lines left

I use Peek() method of StreamReader to check whether there are more lines need to be processed. There are more than 1000 lines in my file, but Peek() suddenly return -1 when it reachs line#750. I checked but seems no differences between line#750 and #751. Even I deleted line#750 and 751, it will still break up at other line.
Below are my codes for your information:
try
{
String ftpserver = ftp + filename;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpserver));
reqFTP.UsePassive = false;
reqFTP.UseBinary = true;
reqFTP.Proxy = null;
reqFTP.Credentials = new NetworkCredential(username, password);
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
response = (FtpWebResponse)reqFTP.GetResponse();
stream = response.GetResponseStream();
reader = new StreamReader(stream, ConfigHelper.MyEncoding);
while (reader.Peek() > -1)
{
string x = reader.ReadLine();
if (x != null)
{
//.......
}
}
}
catch (Exception ex)
{
}
finally
{
if (reader != null)
reader.Close();
if (response != null)
response.Close();
}
I tried while ((x = reader.ReadLine()) != null), but an exception of "Cannot access a disposed object" was thrown out.
Finally I figured it out by using:
while (stream.CanRead && (x = reader.ReadLine()) != null)
While it doesn't explain what's going on, I'd personally avoid using Peek. I'd use:
string line;
while ((line = reader.ReadLine()) != null)
{
// Use the line
}
That way you're only reading in one place. It somehow feels more sane than checking whether or not you can read, and then reading.
You can also write a method to create an IEnumerable<string> from a TextReader (or from a Func<TextReader>, or a filename) which can make all of this more pleasant. If you're just reading a file and you're using .NET 4, then File.ReadLines is already built-in.
EDIT: Here's one reason you may be getting -1, from the docs of StreamReader.Peek:
An integer representing the next character to be read, or -1 if there are no characters to be read or if the stream does not support seeking.
Does your stream support seeking?
I'm not sure why Peek Method returns -1 in your case, but the usual way to read lines with the StreamReader Class to the end of the file is to repeatedly call the ReadLine Method until null is returned:
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
Do you need to use peek? Are you skipping certain lines? If you want to read all lines use this.
while(!sr.EndOfStream)
{
//Do stuff
}
As stated in MSDN, Peek Method not only returns -1 when you reach the end of the stream, but also in case of internal errors:
The Peek method returns an integer value in order to determine whether the end of the file, or another error has occurred. This allows a user to first check if the returned value is -1 before casting it to a Char type.
Maybe check for wrong data conversions in your SQL command, I think this method should work too!
I ran into a similar problem when trying to interact with an application that required authentication. Peek() would return -1 when encountering funky characters (unicode characters?) and ReadLine() was also unreliable and would eventually lockup my application since it seems the process' Standard stream was not closed.
Using the Read() method was the only way I could assure I got ALL lines and characters. Additionally, using the Process' ErrorDataReceived or OutputDataReceived event handlers also proved UNRELIABLE (missing lines). Below is how I solved my problem and insured all lines, and characters, were received:
process.Start();
var stdOutput = process.StandardOutput;
StringBuilder fullMessage = new StringBuilder();
while (true)
{
var character = (char)stdOutput.Read();
fullMessage.Append(character);
//Print Out All Characters
Console.Write(character);
if (fullMessage.ToString().EndsWith("Enter Password: "))
{
//Submit Password To Application
using(StreamWriter writer = process.StandardInput){
writer.Write("somepassword");
writer.Flush();
}
break;
}
}

Sending a multiline string over NamedPipe?

How can I send a multiline string with blank lines over a NamedPipe?
If I send a string
string text= #"line 1
line2
line four
";
StreamWriter sw = new StreamWriter(client);
sw.Write(text);
I get on the server side only "line 1":
StreamReader sr = new StreamReader(server);
string message = sr.ReadLine();
When I try something like this
StringBuilder message = new StringBuilder();
string line;
while ((line = sr.ReadLine()) != null)
{
message.Append(line + Environment.NewLine);
}
It hangs in the loop while the client is connected and only releases when the client disconnects.
Any ideas how I can get the whole string without hanging in this loop?
I need to to process the string and return it on the same way to the client.
It's important that I keep the original formatting of the string including blank lines and whitespace.
StreamReader is a line-oriented reader. It will read the first line (terminated by a newline). If you want the rest of the text, you have to issue multiple readlines. That is:
StreamReader sr = new StreamReader(server);
string message = sr.ReadLine(); // will get "line1"
string message2 = sr.ReadLine(); // will get "line2"
You don't want to "read to end" on a network stream, because that's going to hang the reader until the server closes the connection. That might be a very long time and could overflow a buffer.
Typically, you'll see this:
NetworkStream stream = CreateNetworkStream(); // however you're creating the stream
using (StreamReader reader = new StreamReader(stream))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// process line received from stream
}
}
That gives you each line as it's received, and will terminate when the server closes the stream.
If you want the reader to process the entire multi-line string as a single entity, you can't reliably do it with StreamReader. You'll probably want to use a BinaryWriter on the server and a BinaryReader on the client.
Why not just call ReadToEnd() on StreamReader?
StreamReader sr = new StreamReader(server);
string message = sr.ReadToEnd();
I accomplished sending multiple line messages over a named pipe by using token substitution to replace all \r and \n in the message with tokens like {cr} and {lf} thus converting multiple lines messages into 1 line.
Of course, I needed to do the reverse conversion of the receiver side.
The assumption is that the substituted tokens will never be found in the source text.
You can make sure that this happens by also substituting all "{" with {lp}. That way the "{" becomes your escape character.
You can use Regex to make these Replacements.
That worked great and allowed me to use StreamReader.

Categories