C#: использование StreamReader для чтения строки из txt файла, но Peek() возвращает -1, даже если осталось много строк

Я использую метод Peek() StreamReader, чтобы проверить, нужно ли обрабатывать больше строк. В моем файле более 1000 строк, но Peek() неожиданно возвращает -1, когда достигает строки #750. Я проверил, но, кажется, нет различий между строкой № 750 и № 751. Даже если я удалил строки № 750 и 751, они все равно будут разбиты на другой строке.

Ниже приведены мои коды для вашей информации:

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

Я старался while ((x = reader.ReadLine()) != null), но исключение "Невозможно получить доступ к удаленному объекту" было выброшено.

Наконец я понял это с помощью:while (stream.CanRead && (x = reader.ReadLine()) != null)

5 ответов

Хотя это не объясняет, что происходит, я бы лично не использовал Peek, Я бы использовал:

string line;
while ((line = reader.ReadLine()) != null)
{
    // Use the line
}

Таким образом, вы читаете только в одном месте. Это почему-то кажется более вменяемым, чем проверка, можете ли вы читать, а затем читать.

Вы также можете написать метод для создания IEnumerable<string> из TextReader (или из Func<TextReader> или имя файла), который может сделать все это более приятным. Если вы просто читаете файл и используете.NET 4, тогда File.ReadLines уже встроен.

РЕДАКТИРОВАТЬ: Вот одна из причин, вы можете получить -1, из документов StreamReader.Peek:

Целое число, представляющее следующий символ для чтения, или -1, если нет символов для чтения или если поток не поддерживает поиск.

Поддерживает ли ваш поток поиск?

Я не уверен, почему метод Peek возвращает -1 в вашем случае, но обычный способ чтения строк с классом StreamReader до конца файла - это повторный вызов метода ReadLine до тех пор, пока null возвращается:

string line;
while ((line = reader.ReadLine()) != null)
{
    Console.WriteLine(line);
}

Вам нужно использовать Peek? Вы пропускаете определенные строки? Если вы хотите прочитать все строки, используйте это.

       while(!sr.EndOfStream)
            {
                //Do stuff
            }

Как указано в MSDN, Peek Method возвращает не только -1, когда вы достигаете конца потока, но также и в случае внутренних ошибок:

Метод Peek возвращает целочисленное значение, чтобы определить, произошел ли конец файла или произошла другая ошибка. Это позволяет пользователю сначала проверить, является ли возвращаемое значение -1, прежде чем приводить его к типу Char.

Возможно, проверьте правильность преобразований данных в вашей команде SQL, я думаю, этот метод тоже должен работать!

Я столкнулся с подобной проблемой при попытке взаимодействия с приложением, которое требовало аутентификации. Peek() будет возвращать -1, когда встречаются с причудливыми символами (символы юникода?), А ReadLine() также ненадежен и в конечном итоге блокирует мое приложение, так как кажется, что стандартный поток процесса не был закрыт.

Использование метода Read() было единственным способом убедить меня, что я получил ВСЕ строки и символы. Кроме того, использование обработчиков событий ErrorDataReceived или OutputDataReceived также оказалось НЕОБХОДИМЫМ (пропущенные строки). Ниже показано, как я решил свою проблему и застраховал все строки и символы, которые были получены:

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;
    }
}
Другие вопросы по тегам