CodeGym /Blog Java /Random-PL /Czytanie z klawiatury: „czytelnicy”
Autor
Aditi Nawghare
Software Engineer at Siemens

Czytanie z klawiatury: „czytelnicy”

Opublikowano w grupie Random-PL
Cześć! Lekcje i zadania na poziomie 3 nauczyły Cię, jak wyświetlać rzeczy na konsoli i idąc w drugą stronę, jak odczytywać dane z klawiatury.
Czytanie z klawiatury: „czytniki” – 1
Nauczyłeś się nawet używać następującej złożonej konstrukcji, aby to osiągnąć:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Ale jest jedno pytanie, na które jeszcze nie odpowiedzieliśmy.

Jak to na świecie działa?

W rzeczywistości programy rzadko są całkowicie niezależne. Komunikują się z innymi programami, systemami, Internetem itp. Przez „komunikować się” rozumiemy głównie „wymianę danych”. Oznacza to, że otrzymują pewne dane zewnętrzne, a także wysyłają gdzieś wewnętrzne dane programu. Przykłady programów wymieniających dane obfitują w życie codzienne. Na przykład wiele witryn umożliwia zalogowanie się przy użyciu konta na Facebooku lub Twitterze zamiast rejestracji. W tej sytuacji dwa programy (np. Twitter i strona, do której się logujesz) wymieniają niezbędne dane. Końcowym wynikiem jest pomyślne zalogowanie. Słowo „strumień”służy do opisu procesu wymiany danych. Skąd wzięła się ta nazwa? Z twojego doświadczenia wynika, że ​​„strumień” może bardziej kojarzyć się z rzekami niż z programowaniem. To nie przypadek :) Strumień jest zasadniczo ruchomym fragmentem danych. Innymi słowy, w programowaniu to nie woda płynie — ale raczej dane w postaci bajtów i znaków. Możemy odbierać bity danych ze strumienia danych, a następnie ich używać. Ponownie użyjemy analogii woda/przepływ: możesz czerpać wodę z rzeki, aby ugotować zupę, ugasić ogień lub podlać kwiaty. Strumienie umożliwiają pracę z dowolnym źródłem danych: Internetem, systemem plików komputera lub czymś innym — nie ma to znaczenia. Strumienie to uniwersalne narzędzie. Pozwalają programowi odbierać dane z dowolnego miejsca (strumienie wejściowe) i wysyłać je w dowolne miejsce (strumienie wyjściowe). Ich zadanie jest takie samo: pobrać dane z jednego miejsca i przesłać je do innego. Istnieją dwa rodzaje strumieni:
  1. Strumienie wejściowe służą do odbierania danych
  2. Strumienie wyjściowe służą do wysyłania danych.
W Javie strumienie te są implementowane przez klasy InputStreami OutputStream. Ale strumienie można sklasyfikować w inny sposób. Oprócz strumieni wejściowych i wyjściowych mówimy również o strumieniach bajtów i strumieniach znaków . Znaczenie tutaj powinno być wystarczająco jasne: strumień bajtów wysyła informacje jako zestaw bajtów, podczas gdy strumień znaków wysyła je jako zestaw znaków. W tej lekcji skupimy się na strumieniach wejściowych. Link z informacją o strumieniach wyjściowych umieszczę na końcu lekcji. Możesz to przeczytać samodzielnie :) Teraz spójrz na ten kod:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Czy podczas przeglądania lekcji nie uważałeś, że ta kwestia była dość onieśmielająca? :) Tak nie będzie, gdy już zbadamy, jak to działa. Naprawmy wszystko. Zaczniemy od końca. System.injest InputStreamobiektem, instancją klasy, o której mówiliśmy wcześniej. Jest to strumień wejściowy połączony z systemowym urządzeniem wejściowym (klawiaturą). Nawiasem mówiąc, jesteś pośrednio zaznajomiony z tym strumieniem. W końcu często używasz jego „współpracownika” — System.out! jest strumieniem wyjściowymSystem.out systemu . Służy do wysyłania danych do konsoli ulubioną metodą , której stale używasz :) jest strumieniem do przesyłania danych do konsoli, natomiastSystem.out.println()System.outSystem.insłuży do pobierania danych z klawiatury. To wszystko jest proste :) Co więcej, możemy odczytywać dane z klawiatury bez tej ogromnej konstrukcji. Możemy po prostu napisać: System.in.read();

public class Main {

   public static void main(String[] args) throws IOException {

       while (true) {
           int x = System.in.read();
           System.out.println(x);
       }
   }
}
Klasa InputStream(pamiętaj, System.inże jest InputStreamobiektem) ma read()metodę, która pozwala odczytywać dane. Jest jeden problem: odczytuje bajty , a nie znaki . Używanie tylko angielskich liter jest nudne, więc spróbujmy odczytać chiński znak „魚” z klawiatury (po prostu skopiuj tę literę stąd i wklej ją do konsoli za pomocą ctrl + v na PC lub Command + v na Macu ) . Nawiasem mówiąc, ten znak oznacza „rybę”. Wyjście konsoli: 233 173 154 10 Ten symbol i wiele innych chińskich zajmuje 3 bajty w pamięci komputera (w przeciwieństwie do liter łacińskich, które zajmują tylko 1 bajt). W tym przypadku ze strumienia odczytywane są 4 bajty: pierwsze trzy reprezentują znak „魚”, a drugi bajt reprezentuje nową linię (Enter). W związku z tym System.inw swojej nieozdobionej formie nie jest dla nas opcją. Ludzie (z rzadkimi wyjątkami!) nie wiedzą, jak czytać bajty. Ale InputStreamReaderklasa przychodzi na ratunek! Zobaczmy, co to za zwierzę.

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
Przechodzimy System.indo obiektu InputStreamReader . Nazwa klasy mówi to! Tworzymy InputStreamReaderobiekt i przekazujemy mu strumień wejściowy, z którego będzie odczytywał dane. W tym przypadku...

new InputStreamReader(System.in)
...mówimy mu: „odczytasz dane ze strumienia wejściowego systemu (z klawiatury)”. Ale to nie jedyna jego funkcja! Nie InputStreamReadertylko odbiera dane ze strumienia. Konwertuje również strumienie bajtów na strumienie znaków . Innymi słowy, nie trzeba już konwertować danych z „jedynki i zera” na „język czytelny dla człowieka”. InputStreamreaderrobi dla ciebie wszystko. Oczywiście InputStreamReadernie ogranicza się do odczytu danych z konsoli. Może również odczytywać dane z innych miejsc. Na przykład z pliku:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

   public static void main(String[] args) throws IOException {
       InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("C:\\Users\\username\\Desktop\\testFile.txt"));
   }
}
Tutaj tworzymy FileInputStream(jeden rodzaj InputStream), przekazujemy ścieżkę do pliku i przekazujemy sam strumień do InputStreamReader. Teraz będzie mógł odczytać dane z pliku (oczywiście, jeśli plik rzeczywiście istnieje w ścieżce). Używamy również metody InputStreamReaderklasy read()do odczytu danych (źródło danych nie ma znaczenia: konsola, plik lub gdzie indziej). Jaka jest różnica między System.in.read()i InputStreamReader.read()?\ Spróbujmy ponownie odczytać znak „魚” za pomocą InputStreamReader. Przypominam, co faktycznie przeczytał System.in.read(): 233 173 154 10 I jak to InputStreamReadersamo działa?

public class Main {

   public static void main(String[] args) throws IOException {

       InputStreamReader reader = new InputStreamReader(System.in);
       while (true) {
           int x = reader.read();
           System.out.println(x);
       }
   }
}
Wyjście konsoli: 39770 10 Różnica jest natychmiast widoczna. Ostatni bajt (reprezentujący nową linię) pozostaje niezmieniony (liczba 10), ale znak „魚” został przekształcony w pojedynczy kod „39770”. Oto, co to znaczy czytać znaki! Jeśli nie wierzysz, że 39770 reprezentuje literę "魚", łatwo się przekonać :)
import java.io.IOException;

public class Main {

   public static void main(String[] args) throws IOException {

       char x = 39770;
       System.out.println(x);
   }
}
Wyjście konsoli: Ale jeśli InputStreamReaderjest tak wspaniale, dlaczego my też potrzebujemy BufferedReader? InputStreamReaderumie odczytywać dane i konwertować bajty na znaki. O co więcej moglibyśmy prosić? Dlaczego kolejny Czytelnik? :/ Odpowiedź jest bardzo prosta: dla większej wydajności i wygody . Zacznijmy od wykonania. Kiedy BufferedReaderodczytuje dane, wykorzystuje specjalny obszar zwany buforem, w którym „przechowuje” odczytane znaki. Docelowo, gdy te znaki będą potrzebne w programie, zostaną pobrane z bufora, a nie bezpośrednio ze źródła danych (klawiatura, plik itp.). Pozwala to zaoszczędzić wiele zasobów. Aby zrozumieć, jak to działa, wyobraź sobie kuriera w dużej firmie. Kurier siedzi w biurze i czeka, aż ktoś przyniesie paczki do dostarczenia. Za każdym razem, gdy otrzymuje nową paczkę, może od razu ruszać w drogę. Ale w ciągu dnia może być wiele paczek. Musiałby odbyć wiele podróży między biurem a adresami dostawy. Zamiast tego kurier umieszcza pudełko w swoim biurze. Każdy wkłada swoje paczki do pudełka. Teraz kurier może spokojnie zabrać paczkę i przemieszczać się z adresu na adres. Oszczędza to dużo czasu, ponieważ nie musi za każdym razem wracać do biura. W tym przykładzie pudełko jest tylko buforem, a biuro jest źródłem danych. Kurierowi o wiele łatwiej jest odbierać paczki z jednego pudełka podczas realizacji dostaw, niż za każdym razem wracać do biura. Zaoszczędzi też benzynę. Podobnie w programie pobieranie danych z bufora wymaga znacznie mniej zasobów niż każdorazowe odwoływanie się do źródła danych. W rezultacie,BufferedReader+ InputStreamReaderjest szybszy niż InputStreamReadersam . Rozważaliśmy wydajność. A co z wygodą? Główną zaletą jest to, że Bufferedreadermoże odczytywać dane nie tylko po jednym znaku na raz (chociaż może to robić swoją read()metodą), ale także całe wiersze na raz! Odbywa się to za pomocą readLine()metody;

public class Main {

   public static void main(String[] args) throws IOException {

       BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
       String s = reader.readLine();
       System.out.println("We read this line from the keyboard:");
       System.out.println(s);
   }
}
Dane wyjściowe konsoli: CodeGym to najlepsza strona internetowa do nauki języka Java! Czytamy tę linijkę z klawiatury: CodeGym to najlepsza strona do nauki Javy! Jest to szczególnie przydatne przy odczytywaniu dużych ilości danych. Czytanie jednego lub dwóch wierszy tekstu znak po znaku jest nadal możliwe. Ale czytanie w „Wojnie i pokoju” jednej litery na raz byłoby nieco problematyczne :)

Więcej czytania:

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION