Co to jest strumień w świecie programowania? Dlaczego tego potrzebujemy?
Jeśli to możliwe, prosimy o wyjaśnienie za pomocą analogii.
Odpowiedzi:
Strumień reprezentuje sekwencję obiektów (zwykle bajtów, ale niekoniecznie), do których można uzyskać dostęp w kolejności sekwencyjnej. Typowe operacje na strumieniu:
Określony strumień może obsługiwać odczyt (w takim przypadku jest to „strumień wejściowy”), zapis („strumień wyjściowy”) lub oba. Nie wszystkie strumienie można przeszukiwać.
Odrzucenie jest dość rzadkie, ale zawsze można je dodać do strumienia, opakowując rzeczywisty strumień wejściowy w inny strumień wejściowy, który przechowuje wewnętrzny bufor. Odczyty pochodzą z bufora, a jeśli wrócisz, dane są umieszczane w buforze. Jeśli w buforze nie ma nic, strumień wypychający odczytuje strumień rzeczywisty. To jest prosty przykład „adaptera strumienia”: znajduje się on na „końcu” strumienia wejściowego, sam jest strumieniem wejściowym i robi coś więcej niż oryginalny strumień.
Strumień jest użyteczną abstrakcją, ponieważ może opisywać pliki (które tak naprawdę są tablicami, stąd szukanie jest proste), ale także wejścia / wyjścia terminala (których nie można przeszukiwać, chyba że są buforowane), gniazda, porty szeregowe itp. Możesz więc pisać kod, który mówi albo „Potrzebuję pewnych danych i nie obchodzi mnie, skąd one pochodzą ani w jaki sposób się tu dostały” albo „Stworzę pewne dane i wszystko zależy od dzwoniącego, co się z nimi stanie”. Pierwsza przyjmuje parametr strumienia wejściowego, druga przyjmuje parametr strumienia wyjściowego.
Najlepsza analogia, jaką przychodzi mi do głowy, jest taka, że strumień jest pasem transmisyjnym zbliżającym się do ciebie lub odchodzącym od ciebie (lub czasami jednym i drugim). Pobierasz rzeczy ze strumienia wejściowego, umieszczasz je w strumieniu wyjściowym. Niektóre przenośniki, o których możesz pomyśleć, jako wychodzące z dziury w ścianie - nie można ich szukać, czytanie lub pisanie to jednorazowa okazja. Niektóre przenośniki są rozłożone przed tobą i możesz poruszać się, wybierając miejsce w strumieniu, które chcesz czytać / pisać - to jest wyszukiwanie.
Jak jednak mówi IRBMe, najlepiej jest myśleć o strumieniu pod kątem oferowanych przez niego operacji (które różnią się w zależności od implementacji, ale mają wiele wspólnego), a nie przez analogię fizyczną. Strumienie to „rzeczy, które możesz czytać lub pisać”. Kiedy zaczynasz podłączać adaptery strumieniowe, możesz myśleć o nich jako o pudełku z przenośnikiem wchodzącym i wychodzącym, które łączysz z innymi strumieniami, a następnie pudełko wykonuje pewną transformację danych (spakowanie ich lub zmiana doprowadzeń linii UNIX do systemów DOS lub cokolwiek). Potoki to kolejny dokładny test metafory: w tym miejscu tworzysz parę strumieni, tak że wszystko, co napiszesz w jednym, może być odczytane z drugiego. Pomyśl o tunelach czasoprzestrzennych :-)
Strumień jest już metaforą, analogią, więc naprawdę nie ma potrzeby przedstawiania kolejnego. Możesz myśleć o tym w zasadzie jako o rurze z przepływem wody, w której woda jest w rzeczywistości danymi, a rura jest strumieniem. Przypuszczam, że jest to rodzaj dwukierunkowej rury, jeśli strumień jest dwukierunkowy. Zasadniczo jest to powszechna abstrakcja, która jest umieszczana na rzeczach, w których istnieje przepływ lub sekwencja danych w jednym lub obu kierunkach.
W językach takich jak C #, VB.Net, C ++, Java itp. Metafora strumienia jest używana do wielu celów. Istnieją strumienie plików, w których otwierasz plik i możesz czytać ze strumienia lub zapisywać w nim w sposób ciągły; Istnieją strumienie sieciowe, w których czytanie zi zapisywanie do strumienia odczytuje i zapisuje do bazowego ustanowionego połączenia sieciowego. Strumienie przeznaczone tylko do zapisu są zwykle nazywane strumieniami wyjściowymi, tak jak w tym przykładzie, i podobnie strumienie przeznaczone tylko do odczytu nazywane są strumieniami wejściowymi, jak w tym przykładzie.
Strumień może przeprowadzać transformację lub kodowanie danych (na przykład SslStream w .Net pochłonie dane negocjacji SSL i ukryje je przed Tobą; TelnetStream może ukryć negocjacje Telnet przed Tobą, ale zapewnia dostęp do danych; A ZipOutputStream w Javie pozwala na zapisywanie w plikach w archiwum zip bez martwienia się o wewnętrzne cechy formatu pliku zip.
Inną powszechną rzeczą, którą możesz znaleźć, są strumienie tekstowe, które umożliwiają pisanie łańcuchów zamiast bajtów, lub niektóre języki zapewniają strumienie binarne, które umożliwiają pisanie typów pierwotnych. Typową rzeczą, którą można znaleźć w strumieniach tekstowych, jest kodowanie znaków, o którym należy wiedzieć.
Niektóre strumienie obsługują również dostęp losowy, jak w tym przykładzie. Z drugiej strony, strumień sieciowy z oczywistych powodów nie.
Systemy operacyjne podobne do UNIX obsługują również model strumienia z wejściem i wyjściem programu, jak opisano tutaj .
Odpowiedzi udzielone do tej pory są doskonałe. Podaję tylko inny, aby podkreślić, że strumień nie jest sekwencją bajtów ani nie jest specyficzny dla języka programowania, ponieważ koncepcja jest uniwersalna (podczas gdy jej implementacja może być unikalna). Często widzę w Internecie mnóstwo wyjaśnień w zakresie SQL, C lub Java, które mają sens, ponieważ strumień plików zajmuje się lokalizacjami pamięci i operacjami niskiego poziomu. Często jednak omawiają, jak utworzyć strumień plików i operować na potencjalnym pliku w swoim języku, zamiast omawiać koncepcję strumienia.
Jak wspomniano, a stream
jest metaforą, abstrakcją czegoś bardziej złożonego. Aby Twoja wyobraźnia działała, podaję kilka innych metafor:
wąż jest strumieniem
wąż, dysza i powiązane mechanizmy umożliwiające przepływ gazu do zbiornika to strumień
autostrada to strumień
twoje uszy i oczy są strumieniami
Miejmy nadzieję, że zauważysz w tych przykładach, że metafory strumienia istnieją tylko po to, aby pozwolić, aby coś przez nie przepłynęło (lub na niej w przypadku autostrady) i nie zawsze same stawiają to, co przenoszą. Ważna różnica. Nie odnosimy się do naszych uszu jako sekwencji słów. Wąż jest nadal wężem, jeśli nie przepływa przez niego woda, ale musimy go podłączyć do kranu, aby prawidłowo spełniał swoje zadanie. Samochód nie jest jedynym „rodzajem” pojazdu, który może poruszać się po autostradzie.
W ten sposób może istnieć strumień, przez który nie przechodzą żadne dane, o ile jest połączony z plikiem .
Następnie musimy odpowiedzieć na kilka pytań. Mam zamiar używać plików do opisywania strumieni, więc ... Co to jest plik? A jak czytamy plik? Spróbuję odpowiedzieć na to pytanie, zachowując pewien poziom abstrakcji, aby uniknąć niepotrzebnej złożoności i wykorzystam koncepcję pliku w odniesieniu do systemu operacyjnego Linux ze względu na jego prostotę i dostępność.
Plik to abstrakcja :)
Lub, tak prosto, jak potrafię wyjaśnić, plik składa się z jednej części struktury danych opisującej plik i jednej części danych, które stanowią rzeczywistą zawartość.
Część struktury danych (nazywana i-węzłem w systemach UNIX / Linux) identyfikuje ważne informacje o treści, ale nie zawiera samej treści (ani nazwy pliku w tym zakresie). Jedną z informacji, które przechowuje, jest adres w pamięci, od którego zaczyna się treść. Tak więc mając nazwę pliku (lub twarde łącze w Linuksie), deskryptor pliku (numeryczna nazwa pliku, o którą dba system operacyjny) i początkową lokalizację w pamięci, mamy coś, co możemy nazwać plikiem.
(kluczową kwestią jest to, że „plik” jest definiowany przez system operacyjny, ponieważ ostatecznie to system operacyjny musi sobie z nim radzić. i tak, pliki są znacznie bardziej złożone).
Na razie w porządku. Ale jak otrzymamy zawartość pliku, powiedzieć list miłosny do swojego beau, żebyśmy mogli go wydrukować?
Jeśli zaczniemy od wyniku i cofniemy się, kiedy otworzymy plik na naszym komputerze, cała jego zawartość jest rozpryskiwana na naszym ekranie, abyśmy mogli ją przeczytać. Ale jak? Bardzo metodyczna jest odpowiedź. Zawartość samego pliku to kolejna struktura danych. Załóżmy, że jest to tablica znaków. Możemy również myśleć o tym jako o sznurku.
Jak więc „odczytujemy” ten ciąg? Znajdując jego lokalizację w pamięci i iterując po naszej tablicy znaków, po jednym znaku na raz, aż do osiągnięcia końca znaku pliku. Innymi słowy, program.
Strumień jest „tworzony”, gdy wywoływany jest jego program i ma on miejsce w pamięci, do którego można się podłączyć lub z którym można się połączyć . Podobnie jak nasz przykład z wężem wodnym, wąż jest nieefektywny, jeśli nie jest podłączony do kranu. W przypadku strumienia, aby istniał, musi być połączony z plikiem.
Strumienie można dalej udoskonalać, np. Strumień do odbioru danych wejściowych lub strumień do wysyłania zawartości plików na standardowe wyjście. UNIX / linux łączy i utrzymuje otwarte 3 strumienie plików dla nas od razu, stdin (standardowe wejście), stdout (standardowe wyjście) i stderr (standardowy błąd). Strumienie mogą być budowane jako same struktury danych lub obiekty, co pozwala nam wykonywać bardziej złożone operacje przesyłania danych przez nie, takie jak otwieranie strumienia, zamykanie strumienia lub sprawdzanie błędów pliku, do którego jest podłączony strumień. C ++ cin
jest przykładem obiektu typu stream.
Z pewnością, jeśli wybierzesz, możesz napisać własny strumień.
Strumień to fragment kodu wielokrotnego użytku, który abstrahuje od złożoności obsługi danych, jednocześnie zapewniając użyteczne operacje do wykonania na danych.
Inna analogia: nie możesz pływać pod prąd, dlatego możesz po prostu pobrać następny bit, bajt, ciąg lub obiekt ze strumienia, podczas gdy już odczytane dane są usuwane. Bilet w jedną stronę ... lub po prostu kolejka bez przechowywania wytrwałości.
Czy potrzebujemy więc kolejek? Ty decydujesz.
Słowo „strumień” zostało wybrane, ponieważ reprezentuje (w prawdziwym życiu) bardzo podobne znaczenie do tego, co chcemy przekazać, kiedy go używamy.
Zacznij myśleć o analogii do strumienia wody. Otrzymujesz ciągły przepływ danych, tak jak woda nieustannie płynie w rzece. Nie zawsze wiesz, skąd pochodzą dane, a najczęściej nie musisz; czy to z pliku, gniazda czy innego źródła, nie ma to (nie powinno) znaczenia. Jest to bardzo podobne do otrzymywania strumienia wody, dzięki czemu nie musisz wiedzieć, skąd pochodzi; czy to z jeziora, fontanny czy innego źródła, to nie ma (nie powinno) mieć znaczenia. źródło