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