Когда использовать StreamReader.ReadBlock ()? - PullRequest
11 голосов
/ 28 сентября 2010

Я хотел бы знать о ситуации, когда Read (char [], int, int) не может вернуть все запрошенные символы, а ReadBlock () возвращает все символы как положено (например, когда StreamReader работает с экземпляром объекта FileStream).

Ответы [ 2 ]

15 голосов
/ 01 декабря 2010

На практике при использовании StreamReader это может произойти только с потоком, который может задерживаться на некоторое время - например, с сетевым потоком, как люди упоминали здесь.

Однако с TextReader как правило, вы можете ожидать, что это произойдет в любое время (в том числе, возможно, с будущей версией .NET в случае, если это в настоящее время не происходит - что это не произойдет с StreamReader на FileStream isn ').документально подтверждено, поэтому нет гарантии, что это не произойдет в будущем.

В частности, во многих случаях это проще (с эффектом более простого, более надежного и, вероятно, более эффективного кода).) для разработчиков не возвращать запрошенную сумму, если они могут частично выполнить вызов, просто опустошив текущий буфер, или используя запрошенную сумму в качестве суммы для передачи в источник поддержки (поток или другой TextReader) перед выполнениемоперация, которая может возвращать только меньшее количество символов.

Теперь, чтобы ответить на реальный вопрос относительно «Когда тo использовать StreamReader.ReadBlock ()? "(или, в более общем случае, когда использовать TextReader.ReadBlock ()).Необходимо иметь в виду следующее:

  1. Оба Read() и ReadBlock() гарантированно вернут хотя бы один символ, если не был прочитан весь источник.Ни один из них не вернет 0, если имеется ожидающее содержимое.

  2. Вызов ReadBlock(), когда Read() сделает, бесполезно, так как он повторяется без необходимости.

  3. Но, с другой стороны, это не , что расточительно.

  4. Но, с другой стороны, случаи, когда Read() вернет меньше запрошенных символов, часто бываютв случаях, когда другой поток занимается получением контента, который будет заполнять буфер для следующего вызова, или когда этот контент еще не существует (например, пользовательский ввод или ожидающая операция на другом компьютере) - в этом случае лучший общий параллелизм можно найти вобработка частичного результата, а затем повторный вызов Read(), когда он закончится.

Итак.Если вы можете сделать что-то полезное с частичным результатом, тогда позвоните Read() и поработайте над тем, что вы получите.В частности, если вы просматриваете и работаете с результатом каждого Read(), тогда делайте это, а не с ReadBlock().

. Известный случай, если вы создаете свой собственный TextReader, который поддерживается другим.Нет смысла вызывать ReadBlock(), если алгоритму действительно не нужно определенное количество символов для работы - просто верните столько, сколько вы можете из вызова на Read() и позвольте вызывающему коду позвонить ReadBlock(), если это необходимо.

В частности, обратите внимание, что следующий код:

char buffer = char[4096];
int len = 0;
while((len = tr.ReadBlock(buffer, 0 , 4096)) != 0)
  DoSomething(buffer, 0, len);

Может быть переписан как:

char buffer = char[4096];
for(int len = tr.Read(buffer, 0, 4096); len != 0; len = tr.Read(buffer, 0, 4096))
  DoSomething(buffer, 0, len);

Иногда он может вызывать DoSomething() с меньшими размерами, но можеттакже обеспечьте лучший параллелизм, если есть другой поток, предоставляющий данные для следующего вызова Read().

Однако в большинстве случаев выигрыш незначителен.Если вам действительно нужно определенное количество символов, тогда звоните ReadBlock().Наиболее важно в тех случаях, когда Read() будет иметь тот же результат, что и ReadBlock(), накладные расходы на ReadBlock(), проверяющие, что это так, очень незначительные Не пытайтесь угадать, является ли Read() безопасным или нет в данном случае;если требуется гарантия ReadBlock(), используйте ReadBlock().

0 голосов
/ 28 сентября 2010

Это серьезная проблема для сетевых потоков, особенно если потоковые данные достаточно велики, а сервер, предоставляющий поток, делает это в виде фрагментированного вывода (т. Е. Довольно типично для HTTP), поскольку вызов только Read(), то есть чтение одного символа, дает-1 при достижении EOS, вызовы Read(char[], int, int) с аргументами доходят до количества запрошенных символов или меньше, если достигается EOS, и затем возвращают количество прочитанных символов или ноль, если EOS был достигнут

Принимая во внимание, что ReadBlock() ожидает доступности данных из Stream, поэтому вы никогда не столкнетесь с этой проблемой.

Еще одна вещь, которую стоит отметить, - обе формы читают максимальное количество символов и не гарантируют, чтовернуть столько символов, если их не так много

Я задал вопрос на подобные темы некоторое время назад - Сбой чтения из HttpResponseStream - когда у меня возникли проблемы с чтением из потоков HTTP

...