C # przy użyciu strumieni


116

Strumienie są dla mnie trochę tajemnicze. Nie wiem, kiedy użyć którego strumienia i jak z niego korzystać. Czy ktoś może mi wyjaśnić, jak używane są strumienie?

Jeśli dobrze rozumiem, istnieją trzy typy strumieni:

  • stream
  • read stream
  • write stream

Czy to jest poprawne? Na przykład, jaka jest różnica między a Memorystreami a FileStream?



3
Weź tablicę bajtów, a następnie utwórz dla niej opakowanie ( Stream), które ujawnia przydatne metody, takie jak czytanie, pisanie i zmiana pozycji. Teraz możesz tworzyć klasy na podstawie ich magazynu zapasowego (FileStream, MemoryStream), które dziedziczą Streami budują na podstawie tej funkcji w oparciu o określony magazyn zapasowy.
The Muffin Man,

Odpowiedzi:


80

Strumień Przedmiotem wykorzystywane do przesyłania danych. Istnieje ogólna klasa strumienia System.IO.Stream, z której pochodzą wszystkie inne klasy strumieni w .NET. PlikStreamKlasa zajmuje bajtów.

Konkretne klasy strumienia są używane do obsługi innych typów danych niż bajty. Na przykład:

  • FileStreamKlasa jest używana, gdy źródło zewnątrz jest plikiem
  • MemoryStream służy do przechowywania danych w pamięci
  • System.Net.Sockets.NetworkStream obsługuje dane sieciowe

Strumienie czytające / zapisujące, takie jak StreamReaderi StreamWriternie są strumieniami - nie są one pochodnymi System.IO.Stream, zostały zaprojektowane, aby pomóc w zapisywaniu i odczytywaniu danych zi do przesyłania strumieniowego!


3
Tak więc, jeśli dobrze rozumiem, strumień zawiera dane i nic z nimi nie robi. Klasy pomocnicze czytelnika i pisarza mogą obsługiwać (manipulować) danymi w strumieniu?
Martijn,

9
Nie, Stream nie jest kontenerem danych, służy do przesyłania danych, na przykład FileStream przesyła dane z bajtu [] do pliku fizycznego, NetworkStream przesyła bajt [] przez gniazdo. Klasy programu Reader Writer są klasami pomocniczymi do zapisu i odczytu ze strumienia, na przykład StreamReader może służyć do odczytu z ciągu Stream, a nie bajtu []. jeśli podasz FileStream jako parametr, będzie on czytał z File, jeśli NetworkStream z gniazda.
Arsen Mkrtchyan

dodatkowo StreamReader i StreamWriter służą do odczytywania i zapisywania strumieni TEXT (znaków).
1c1cle

1
jest dobry artykuł, który pomoże ci zrozumieć MemoryStream. codeproject.com/Articles/832387/…
Jiaji Li

2
@ user420667. dobre pytanie. W obu przypadkach AudioStream i TemperatureStream najprawdopodobniej byłyby to BinaryStreams dla sterownika skojarzonego z urządzeniem. Lub możesz utworzyć CustomStream, który został stworzony specjalnie dla tego interfejsu.
1c1cle

62

Aby rozwinąć trochę inne odpowiedzi tutaj i pomóc wyjaśnić wiele przykładowego kodu, który zobaczysz z kropkami, przez większość czasu nie czytasz i nie piszesz bezpośrednio w strumieniu. Strumienie to niskopoziomowe środki do przesyłania danych.

Zauważysz, że funkcje do odczytu i zapisu są zorientowane na bajty, np. WriteByte (). Nie ma funkcji zajmujących się liczbami całkowitymi, łańcuchami itp. To sprawia, że ​​strumień jest bardzo uniwersalny, ale trudniejszy w obsłudze, jeśli, powiedzmy, chcesz po prostu przesłać tekst.

Jednak platforma .NET udostępnia klasy, które konwertują między typami natywnymi a interfejsem strumienia niskiego poziomu oraz przesyłają dane do lub ze strumienia za Ciebie. Niektóre godne uwagi takie klasy to:

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

Aby z nich skorzystać, najpierw zdobądź swój strumień, a następnie utwórz jedną z powyższych klas i skojarz ją ze strumieniem. Na przykład

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

StreamReader i StreamWriter konwertują między typami natywnymi i ich reprezentacjami ciągów, a następnie przesyłają ciągi do i ze strumienia jako bajty. Więc

myStreamWriter.Write(123);

zapisze do strumienia „123” (trzy znaki „1”, „2”, a następnie „3”). Jeśli masz do czynienia z plikami tekstowymi (np. Html), StreamReader i StreamWriter to klasy, których użyjesz.

Natomiast

myBinaryWriter.Write(123);

zapisze cztery bajty reprezentujące 32-bitową wartość całkowitą 123 (0x7B, 0x00, 0x00, 0x00). Jeśli masz do czynienia z plikami binarnymi lub protokołami sieciowymi, możesz użyć BinaryReader i BinaryWriter. (Jeśli wymieniasz dane z sieciami lub innymi systemami, musisz uważać na endianness , ale to kolejny post.)


Klasy adapterów StreamWriter i Reader są bardzo źle nazwane. Dzięki, że o tym wspomniałeś. Jak to się stało, że wymyślili to imię, wciąż mnie zaskakuje.
Tarik

Ponadto nawet klasy binarnych pisarzy i czytelników są źle nazwane.
Tarik

22

Strumienie są dobre do obsługi dużych ilości danych. Jeśli załadowanie wszystkich danych do pamięci w tym samym czasie jest niepraktyczne, możesz otworzyć je jako strumień i pracować z małymi fragmentami.


1
Chciałbym zobaczyć przykład tego, co właśnie powiedziałeś „pracuj z małymi fragmentami”.
Jenna Leaf

2
Strumienie są również dobre dla małych ilości danych. Jeśli programista C # chce manipulować zawartością pliku, musi używać strumieni, niezależnie od ilości danych. To samo dotyczy również strumieni sieciowych. To prawda, jeśli programista koduje język niższego poziomu, taki jak C, to możliwe jest zapisywanie znaków lub bajtów bezpośrednio na dysk lub gniazdo, ale nawet dla małej ilości danych jest to czasochłonne i bardziej podatne na błąd.
1c1cle

10

Strumień to tylko abstrakcja (lub opakowanie) na physicalstrumieniu bajtów. Ten physicalstrumień nazywa się base stream. Więc nie zawsze jest strumień bazowy, nad którym owinięcie strumień jest tworzony, a zatem owinięcie jest nazwany rodzaju strumienia bazowego tj FileStream, MemoryStreametc.

Zaletą opakowania strumienia jest to, że otrzymujesz ujednolicony interfejs API do interakcji ze strumieniami dowolnego bazowego typu usb, fileitp.

Dlaczego miałbyś traktować dane jako strumień - ponieważ fragmenty danych są ładowane na żądanie, możemy sprawdzać / przetwarzać dane jako fragmenty, zamiast ładować całe dane do pamięci. W ten sposób większość programów radzi sobie z dużymi plikami, np. Z szyfrowaniem pliku obrazu systemu operacyjnego.


4

Jest tylko jeden podstawowy typ Stream . Jednak w różnych okolicznościach niektórzy członkowie będą zgłaszać wyjątek po wywołaniu, ponieważ w tym kontekście operacja nie była dostępna.

Na przykład a MemoryStream jest po prostu sposobem na przenoszenie bajtów do i z fragmentu pamięci. Dlatego możesz na nim wywołać odczyt i zapis.

Z drugiej strony a FileStreampozwala na odczyt lub zapis (lub oba) z / do pliku. To, czy możesz rzeczywiście czytać, czy zapisywać, zależy od tego, jak plik został otwarty. Nie możesz zapisywać do pliku, jeśli otworzyłeś go tylko do odczytu.


3

Zacząłbym od czytania strumieni w MSDN: http://msdn.microsoft.com/en-us/library/system.io.stream.aspx

Memorystream i FileStream to strumienie używane odpowiednio do pracy z pamięcią surową i plikami ...


Dzięki za link. Podobało mi się to, że „podczas debugowania można przeglądać kod źródłowy online, pobierać materiały referencyjne do przeglądania w trybie offline i przechodzić przez źródła (w tym poprawki i aktualizacje)”. Ta funkcja oferuje nowy poziom wglądu.
David

1

Nie nazwałbym tych różnych rodzajów strumieni. Klasa Stream ma właściwości CanRead i CanWrite, które informują, czy określony strumień może być odczytywany i zapisywany.

Główną różnicą między różnymi klasami strumieni (takimi jak MemoryStream vs FileStream) jest magazyn zapasowy - skąd dane są odczytywane lub gdzie są zapisywane. To dość oczywiste z nazwy. MemoryStream przechowuje dane tylko w pamięci, FileStream jest wspierany przez plik na dysku, NetworkStream odczytuje dane z sieci i tak dalej.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.