Słowo „strumień” zostało wybrane, ponieważ reprezentuje (w prawdziwym życiu) bardzo podobne znaczenie do tego, co chcemy przekazać, gdy go używamy.
Na chwilę zapomnijmy o sklepie z podkładami i zacznijmy myśleć o analogii do strumienia wody. Otrzymujesz ciągły przepływ danych, tak jak woda stale przepływa w rzece. Niekoniecznie wiesz, skąd pochodzą dane i najczęściej nie musisz; czy to z pliku, gniazda czy innego źródła, to nie powinno (nie powinno) mieć znaczenia. Jest to bardzo podobne do odbierania strumienia wody, dzięki czemu nie musisz wiedzieć, skąd pochodzi; czy to z jeziora, fontanny, czy innego źródła, to nie powinno (nie powinno) mieć znaczenia.
To powiedziawszy, kiedy zaczniesz myśleć, że zależy ci tylko na uzyskaniu potrzebnych danych, bez względu na to, skąd pochodzą, abstrakcje, o których mówili inni, stają się wyraźniejsze. Zaczynasz myśleć, że możesz owijać strumienie, a twoje metody będą nadal działać idealnie. Na przykład możesz to zrobić:
int ReadInt(StreamReader reader) { return Int32.Parse(reader.ReadLine()); }
// in another method:
Stream fileStream = new FileStream("My Data.dat");
Stream zipStream = new ZipDecompressorStream(fileStream);
Stream decryptedStream = new DecryptionStream(zipStream);
StreamReader reader = new StreamReader(decryptedStream);
int x = ReadInt(reader);
Jak widać, bardzo łatwo jest zmienić źródło wejściowe bez zmiany logiki przetwarzania. Na przykład, aby odczytać dane z gniazda sieciowego zamiast pliku:
Stream stream = new NetworkStream(mySocket);
StreamReader reader = new StreamReader(stream);
int x = ReadInt(reader);
Tak proste, jak to tylko możliwe. Piękno trwa, ponieważ można użyć dowolnego źródła wejściowego, o ile można zbudować dla niego „opakowanie” strumienia. Możesz nawet to zrobić:
public class RandomNumbersStreamReader : StreamReader {
private Random random = new Random();
public String ReadLine() { return random.Next().ToString(); }
}
// and to call it:
int x = ReadInt(new RandomNumbersStreamReader());
Widzieć? Dopóki twoja metoda nie dba o to, jakie jest źródło wejściowe, możesz dostosowywać swoje źródło na różne sposoby. Abstrakcja pozwala oddzielić dane wejściowe od logiki przetwarzania w bardzo elegancki sposób.
Pamiętaj, że strumień, który sami stworzyliśmy, nie ma sklepu z zapleczem, ale nadal doskonale służy naszym celom.
Podsumowując, strumień jest tylko źródłem danych wejściowych, ukrywającym (abstrakcyjnym) inne źródło. Dopóki nie złamiesz abstrakcji, twój kod będzie bardzo elastyczny.
ReadInt
definiuje się na samej górze za pomocąint.Parse
, która odbiera zwrócony ciągreader.ReadLine()
i analizuje go. Oczywiście możesz stworzyć podobnąReadString
metodę. Czy to jest wystarczająco jasne?Stream.Copy
znacznie ułatwia życie w wielu aplikacjach.Chodzi o to, że nie powinieneś wiedzieć, czym jest sklep z podkładami - to abstrakcja. Rzeczywiście, może nie być nawet sklepu z kopiami zapasowymi - możesz czytać z sieci, a dane nigdy nie są „przechowywane”.
Jeśli potrafisz napisać kod, który działa niezależnie od tego, czy rozmawiasz z systemem plików, pamięcią, siecią, czy czymkolwiek innym, co obsługuje pomysł streamowania, twój kod jest znacznie bardziej elastyczny.
Ponadto strumienie są często łączone razem - możesz mieć strumień, który kompresuje wszystko, co się w nim znajduje, zapisując skompresowaną formę w innym strumieniu lub taki, który szyfruje dane itp. Na drugim końcu byłoby odwrotnie łańcuch, deszyfrowanie, dekompresowanie lub cokolwiek innego.
źródło
StreamReader
- lub lepiej -TextReader
to Twój kod nie wie, jaki rodzaj strumienia leży u podstaw przepływu danych. A raczej może użyćBaseStream
właściwości do znalezienia typu - ale może to być typ, którego Twój kod nigdy wcześniej nie widział. Chodzi o to, że nie powinieneś się tym przejmować. I tak, możesz absolutnie skończyć pisaniem kodu, który czasami będzie używany dla strumienia sieciowego, a czasem dla strumienia plików. Jeśli chodzi o strumienie przesyłające dane przez proces - cóż, nie byłoby to możliwe w procesie ... to byłby dostawca strumienia.Celem strumienia jest zapewnienie warstwy abstrakcji między tobą a sklepem z zapleczem. Dlatego dany blok kodu korzystający ze strumienia nie musi dbać o to, czy magazyn kopii zapasowych jest plikiem dyskowym, pamięcią itp.
źródło
Nie chodzi o strumienie - chodzi o pływanie. Jeśli potrafisz pływać jednym strumieniem, możesz pływać dowolnym napotkanym strumieniem.
źródło
Aby dodać do komory echa, strumień jest abstrakcją, więc nie obchodzi Cię podstawowy sklep. Jest to najbardziej sensowne, gdy rozważasz scenariusze ze strumieniami i bez nich.
Pliki są w większości nieciekawe, ponieważ strumienie nie robią wiele więcej niż metody nie oparte na strumieniach, które znam. Zacznijmy od plików internetowych.
Jeśli chcę pobrać plik z Internetu, muszę otworzyć gniazdo TCP, nawiązać połączenie i odbierać bajty, dopóki nie będzie więcej bajtów. Muszę zarządzać buforem, znać rozmiar oczekiwanego pliku i pisać kod, aby wykryć przerwanie połączenia i odpowiednio go obsłużyć.
Powiedzmy, że mam jakiś obiekt TcpDataStream. Tworzę je z odpowiednimi informacjami o połączeniu, a następnie czytam bajty ze strumienia, aż powie, że nie ma już bajtów. Strumień obsługuje zarządzanie buforem, warunki końca danych i zarządzanie połączeniami.
W ten sposób strumienie ułatwiają operacje wejścia / wyjścia. Z pewnością możesz napisać klasę TcpFileDownloader, która robi to, co robi strumień, ale wtedy masz klasę specyficzną dla TCP. Większość interfejsów strumieniowych po prostu udostępnia metody Read () i Write (), a wszelkie bardziej skomplikowane koncepcje są obsługiwane przez wewnętrzną implementację. Z tego powodu możesz używać tego samego podstawowego kodu do odczytu lub zapisu w pamięci, plikach dyskowych, gniazdach i wielu innych magazynach danych.
źródło
Wizualizacja, której używam, to pasy transmisyjne, nie w prawdziwych fabrykach, ponieważ nic o tym nie wiem, ale w fabrykach kreskówek, w których przedmioty poruszają się wzdłuż linii i są stemplowane, pakowane w pudełka, liczone i sprawdzane przez sekwencję głupich urządzeń.
Masz proste elementy, które wykonują jedną rzecz, na przykład urządzenie do nakładania wiśni na ciasto. To urządzenie ma strumień wejściowy ciast bez wiśni i strumień wyjściowy ciast z wiśniami. Istnieją trzy zalety, o których warto wspomnieć, tworząc taką strukturę przetwarzania.
Po pierwsze, upraszcza same elementy: jeśli chcesz nałożyć ciasto czekoladowe na lukier, nie potrzebujesz skomplikowanego urządzenia, które wie wszystko o ciastach, możesz stworzyć głupie urządzenie, które przyklei lukier czekoladowy do wszystkiego, co jest do niego podawane (w bajki, chodzi o tyle, że nie wie, że następnym przedmiotem nie jest ciasto, to Wile E. Coyote).
Po drugie, możesz tworzyć różne produkty, umieszczając urządzenia w różnych sekwencjach: może chcesz, aby twoje ciastka miały lukier na wisience zamiast wisienki na wisience, i możesz to zrobić po prostu zamieniając urządzenia na linii .
Po trzecie, urządzenia nie muszą zarządzać zapasami, boksowaniem ani rozpakowywaniem. Najskuteczniejszy sposób agregowania i pakowania rzeczy jest zmienny: może dzisiaj wkładasz swoje ciastka do 48 pudełek i wysyłasz je ciężarówką, ale jutro chcesz wysłać pudełka po sześć w odpowiedzi na niestandardowe zamówienia. Tego rodzaju zmianę można uwzględnić poprzez wymianę lub ponowną konfigurację maszyn na początku i na końcu linii produkcyjnej; maszyna wiśniowa na środku linii nie musi być zmieniana, aby przetwarzać inną liczbę elementów na raz, zawsze działa z jednym elementem na raz i nie musi wiedzieć, w jaki sposób jego wejście lub wyjście jest być zgrupowane.
źródło
Kiedy po raz pierwszy usłyszałem o transmisji strumieniowej, było to w kontekście transmisji na żywo za pomocą kamery internetowej. Tak więc jeden host nadaje zawartość wideo, a drugi odbiera treść wideo. Więc to jest streaming? No cóż ... tak ... ale transmisja na żywo jest konkretną koncepcją i myślę, że pytanie odnosi się do abstrakcyjnej koncepcji Streaming. Zobacz https://en.wikipedia.org/wiki/Live_streaming
Przejdźmy więc dalej.
Wideo nie jest jedynym zasobem, który można przesyłać strumieniowo. Dźwięk można również przesyłać strumieniowo. Mówimy teraz o multimediach przesyłanych strumieniowo. Zobacz https://en.wikipedia.org/wiki/Streaming_media . Dźwięk może być dostarczany od źródła do celu na wiele sposobów. Porównajmy zatem niektóre metody dostarczania danych.
Klasyczne pobieranie plików Klasyczne pobieranie plików nie odbywa się w czasie rzeczywistym. Przed użyciem pliku musisz poczekać na zakończenie pobierania.
Pobieranie progresywne Fragmenty pobierania progresywnego pobierają dane ze strumieniowego pliku multimedialnego do bufora tymczasowego. Dane w tym buforze są wykonalne: dane audio-wideo w buforze można odtwarzać. Z tego powodu użytkownicy mogą oglądać / słuchać przesyłanego strumieniowo pliku multimedialnego podczas pobierania. Możliwe jest szybkie przewijanie do przodu i do tyłu, zjazd z bufora. W każdym razie progresywne pobieranie nie jest przesyłaniem strumieniowym na żywo.
Streaming Dzieje się w czasie rzeczywistym i dzieli dane. Streaming jest realizowany w transmisjach na żywo. Klienci słuchający transmisji nie mogą przewijać do przodu ani do tyłu. W strumieniach wideo dane są odrzucane po odtworzeniu.
Serwer przesyłania strumieniowego utrzymuje dwukierunkowe połączenie ze swoim klientem, a serwer sieciowy zamyka połączenie po odpowiedzi serwera.
Audio i wideo to nie jedyne rzeczy, które można przesyłać strumieniowo. Rzućmy okiem na pojęcie strumieni w podręczniku PHP.
W PHP zasób to odwołanie do zewnętrznego źródła, takiego jak plik, połączenie z bazą danych. Innymi słowy, strumień jest źródłem, z którego można odczytać lub zapisać. Więc jeśli pracowałeś
fopen()
, to już pracowałeś ze strumieniami.Przykład pliku tekstowego, który podlega strumieniowaniu:
Pliki zip można również przesyłać strumieniowo. Ponadto przesyłanie strumieniowe nie ogranicza się do plików. Można również przesyłać strumieniowo połączenia HTTP, FTP, SSH oraz wejścia / wyjścia.
Co wikipedia mówi o koncepcji Streaming?
Zobacz: https://en.wikipedia.org/wiki/Stream_%28computing%29 .
Wikipedia prowadzi do tego: https://srfi.schemers.org/srfi-41/srfi-41.html, a autorzy mają to do powiedzenia na temat strumieni:
Strumień jest więc strukturą danych.
Mój wniosek: strumień jest źródłem, które może zawierać dane, które można odczytywać lub zapisywać sekwencyjnie. Strumień nie odczytuje wszystkiego, co zawiera źródło, odczytuje / zapisuje sekwencyjnie.
Przydatne linki:
źródło
To tylko koncepcja, kolejny poziom abstrakcji, który ułatwia życie. Wszystkie mają wspólny interfejs, co oznacza, że można je łączyć w potoku. Na przykład, koduj do base64, następnie zip, a następnie zapisz to na dysk i wszystko w jednym wierszu!
źródło
Najlepszym wyjaśnieniem strumieni, jakie widziałem, jest rozdział 3 SICP . (Może być konieczne przeczytanie pierwszych 2 rozdziałów, aby miało to sens, ale i tak powinieneś. :-)
W ogóle nie używają steramów jako bajtów, ale raczej liczby całkowite. Najważniejsze punkty, które z tego wyciągnąłem:
źródło
Kolejna kwestia (do odczytu sytuacji pliku):
stream
może pozwolić ci zrobić coś innego wcześniejfinished reading all content of the file
.źródło
Pomyśl o strumieniach jako o abstrakcyjnym źródle danych (bajty, znaki itp.). Abstrahują od rzeczywistej mechaniki odczytu i zapisu do konkretnego źródła danych, czy to gniazda sieciowego, pliku na dysku czy odpowiedzi z serwera WWW.
źródło
Myślę, że należy wziąć pod uwagę, że sam sklep z podkładami jest często tylko kolejną abstrakcją. Strumień pamięci jest dość łatwy do zrozumienia, ale plik różni się diametralnie w zależności od używanego systemu plików, nieważne jakiego dysku twardego używasz. Nie wszystkie strumienie faktycznie znajdują się na szczycie sklepu z zapleczem: strumienie sieciowe są po prostu strumieniami.
Rzecz w tym, że ograniczamy naszą uwagę do tego, co ważne. Dzięki standardowej abstrakcji możemy wykonywać typowe operacje. Nawet jeśli nie chcesz na przykład dzisiaj wyszukiwać pliku lub odpowiedzi HTTP na adresy URL, nie oznacza to, że nie będziesz chciał jutro.
Strumienie pierwotnie powstało, gdy pamięć była niewielka w porównaniu do pamięci. Sam odczyt pliku C może być znaczącym obciążeniem. Minimalizacja zajmowanego miejsca była niezwykle ważna. Dlatego bardzo przydatna była abstrakcja, w której bardzo niewiele trzeba było załadować. Dzisiaj jest równie przydatny podczas komunikacji sieciowej i, jak się okazuje, rzadko jest tak restrykcyjny, gdy mamy do czynienia z plikami. Możliwość przezroczystego dodawania ogólnych elementów, takich jak buforowanie, czyni je jeszcze bardziej użytecznymi.
źródło
Strumień to abstrakcja ciągu bajtów. Chodzi o to, że nie musisz wiedzieć, skąd pochodzą bajty, tylko że możesz je odczytać w znormalizowany sposób.
Na przykład, jeśli przetwarzasz dane za pośrednictwem strumienia, nie ma znaczenia dla twojego kodu, czy dane pochodzą z pliku, połączenia sieciowego, ciągu, obiektu blob w bazie danych itp. Itp.
Nie ma w sobie nic złego w interakcji z samym sklepem z podkładem, z wyjątkiem tego, że wiąże cię on z implementacją sklepu z podkładem.
źródło
Strumień to abstrakcja zapewniająca standardowy zestaw metod i właściwości do interakcji z danymi. Abstrahując od rzeczywistego nośnika pamięci, kod można napisać bez całkowitego polegania na tym nośniku, a nawet implementacji tego nośnika.
Dobrą analogią może być rozważenie torby. Nie obchodzi cię, z czego zrobiona jest torba ani co robi, kiedy wkładasz do niej swoje rzeczy, pod warunkiem, że torba spełnia rolę torby i możesz odzyskać swoje rzeczy. Strumień definiuje dla nośników danych to, co definiuje pojęcie torby dla różnych jej przypadków (takich jak worek na śmieci, torebka, plecak itp.) - zasady interakcji.
źródło
Krótko mówiąc, brakowało mi tutaj słowa:
Strumienie to kolejki zwykle przechowywane w buforze zawierające wszelkiego rodzaju dane.
(Teraz, ponieważ wszyscy wiemy, jakie są kolejki, nie trzeba tego dalej wyjaśniać).
źródło