C # с использованием потоков

116

Для меня потоки загадочны. Я не знаю, когда использовать какой поток и как их использовать. Может кто-нибудь объяснить мне, как используются потоки?

Если я правильно понял, есть три типа потоков:

  • stream
  • read stream
  • write stream

Это верно? И, например, в чем разница между а Memorystreamи а FileStream?

Мартейн
источник
13
вы можете проверить stackoverflow.com/questions/507747/…
Preets
3
Возьмите массив байтов и затем создайте для него оболочку ( Stream), которая предоставляет некоторые полезные методы, такие как чтение, запись и изменение позиции. Теперь вы можете создавать классы на основе их резервного хранилища (FileStream, MemoryStream), которые наследуются Streamи основываются на этой функциональности на основе конкретного резервного хранилища.
The Muffin Man

Ответы:

80

Поток представляет собой объект , используемый для передачи данных. Существует общий класс потока System.IO.Stream, от которого наследуются все другие классы потоков в .NET. StreamКласс имеет дело с байтами.

Конкретные классы потоков используются для работы с другими типами данных, кроме байтов. Например:

  • FileStreamКласс используется , когда источник снаружи файл
  • MemoryStream используется для хранения данных в памяти
  • System.Net.Sockets.NetworkStream обрабатывает сетевые данные

Потоки чтения / записи, такие как потоки StreamReaderи StreamWriterне являются потоками - они не являются производными System.IO.Stream, они предназначены для помощи в записи и чтении данных из потока и в поток!

Арсен Мкртчян
источник
3
Итак, если я правильно понимаю, поток содержит данные и ничего с ними не делает. «Вспомогательные» классы чтения и записи могут обрабатывать (манипулировать) данными в потоке?
Martijn
9
Нет, Stream не является контейнером данных, он используется для передачи данных, например FileStream передает данные из byte [] в физический файл, NetworkStream передает byte [] по сокету. Классы Reader Writer - это вспомогательные классы для записи и чтения из потока, например StreamReader можно использовать для чтения из строки Stream, а не из byte []. если вы укажете FileStream в качестве параметра, он будет читать из файла, если NetworkStream из сокета.
Арсен Мкртчян
кроме того, StreamReader и StreamWriter предназначены для чтения и записи ТЕКСТОВЫХ (символьных) потоков.
1c1cle
1
там есть хорошая статья, которая поможет вам понять MemoryStream. codeproject.com/Articles/832387/…
Цзяцзи Ли
2
@ user420667. хороший вопрос. В обоих случаях AudioStream и TemperatureStream они, скорее всего, будут BinaryStreams для драйвера, связанного с устройством. Или вы можете создать CustomStream, созданный специально для интерфейса.
1c1cle
62

Чтобы немного расширить другие ответы здесь и помочь объяснить большую часть примера кода, который вы увидите пунктирным, большую часть времени вы не читаете и не записываете в поток напрямую. Потоки - это низкоуровневое средство передачи данных.

Вы заметите, что все функции для чтения и записи ориентированы на байты, например WriteByte (). Здесь нет функций для работы с целыми числами, строками и т. Д. Это делает поток очень универсальным, но менее простым в работе, если, скажем, вы просто хотите передать текст.

Однако .NET предоставляет классы, которые преобразуют собственные типы в интерфейс низкоуровневого потока и передают данные в поток или из него. Некоторые известные такие классы:

StreamWriter // Badly named. Should be TextWriter.
StreamReader // Badly named. Should be TextReader.
BinaryWriter
BinaryReader

Чтобы использовать их, сначала вы приобретаете свой поток, затем создаете один из указанных выше классов и связываете его с потоком. Например

MemoryStream memoryStream = new MemoryStream();
StreamWriter myStreamWriter = new StreamWriter(memoryStream);

StreamReader и StreamWriter преобразуют собственные типы в их строковые представления, а затем передают строки в поток и из потока как байты. Так

myStreamWriter.Write(123);

запишет в поток «123» (три символа «1», «2», затем «3»). Если вы имеете дело с текстовыми файлами (например, html), вам следует использовать классы StreamReader и StreamWriter.

В то время как

myBinaryWriter.Write(123);

запишет четыре байта, представляющих 32-битное целое число 123 (0x7B, 0x00, 0x00, 0x00). Если вы имеете дело с двоичными файлами или сетевыми протоколами, вы можете использовать BinaryReader и BinaryWriter. (Если вы обмениваетесь данными с сетями или другими системами, вам нужно помнить о порядке байтов , но это уже другая статья.)

Тим Уильямс
источник
Классы адаптеров StreamWriter и Reader серьезно неудачно названы. Спасибо, что упомянули об этом. Меня до сих пор удивляет, почему они придумали это название.
Tarik
Кроме того, плохо названы даже классы записи и чтения двоичных файлов.
Tarik
22

Потоки хороши для работы с большими объемами данных. Когда нецелесообразно загружать все данные в память одновременно, вы можете открыть его как поток и работать с небольшими фрагментами.

meatvest
источник
1
Хотел бы увидеть пример того, что вы только что сказали: «Работайте с небольшими кусками».
Jenna Leaf
2
Потоки также подходят для небольших объемов данных. Если программист на C # хочет манипулировать содержимым файла, он должен использовать потоки, независимо от объема данных. То же самое верно и для сетевых потоков. Конечно, если программист кодирует язык более низкого уровня, такой как C, тогда можно записывать символы или байты непосредственно на диск или сокет, но даже для небольшого количества данных это отнимает много времени и более подвержено ошибка.
1c1cle
10

Stream - это просто абстракция (или оболочка) над physicalпотоком байтов. Этот physicalпоток называется base stream. Таким образом, всегда существует базовый поток, над которым создается оболочка потока, и поэтому оболочка названа в честь типа базового потока FileStream, MemoryStreamт. Е. И т. Д.

Преимущество обертки потока заключается в том, что вы получаете унифицированный API для взаимодействия с потоками любого базового типа usb, fileи т. Д.

Зачем рассматривать данные как поток - поскольку фрагменты данных загружаются по запросу, мы можем проверять / обрабатывать данные как фрагменты, а не загружать все данные в память. Именно так большинство программ работают с большими файлами, например, для шифрования файла образа ОС.

Анвар Хусейн
источник
4

Есть только один основной тип Stream. Однако в различных обстоятельствах некоторые члены будут вызывать исключение при вызове, потому что в этом контексте операция была недоступна.

Например MemoryStream - это просто способ перемещать байты в и из фрагмента памяти. Следовательно, вы можете вызвать на нем чтение и запись.

С другой стороны, a FileStreamпозволяет вам читать или записывать (или и то, и другое) из / в файл. Возможность чтения или записи зависит от того, как был открыт файл. Вы не можете записать в файл, если открыли его только для чтения.

AnthonyWJones
источник
3

Я бы начал с чтения потоков в MSDN: http://msdn.microsoft.com/en-us/library/system.io.stream.aspx

Memorystream и FileStream - это потоки, используемые для работы с необработанной памятью и файлами соответственно ...

Robban
источник
Спасибо за ссылку. Мне понравилось, что «Вы можете просматривать исходный код в Интернете, загружать справочные материалы для просмотра в автономном режиме и переходить по источникам (включая исправления и обновления) во время отладки». Эта функция предлагает новый уровень понимания.
Дэвид
1

Я бы не назвал эти разные виды потоков. Класс Stream имеет свойства CanRead и CanWrite, которые говорят вам, можно ли читать и записывать конкретный поток.

Основное различие между разными классами потоков (такими как MemoryStream и FileStream) - это резервное хранилище, откуда данные считываются или куда они записываются. Это как бы очевидно из названия. MemoryStream сохраняет данные только в памяти, FileStream поддерживается файлом на диске, NetworkStream считывает данные из сети и так далее.

Маттиас С
источник