简体   繁体   中英

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM