Cześć! Dzisiejsza lekcja zostanie dla wygody podzielona na dwie części. Powtórzymy kilka starych tematów, które poruszaliśmy wcześniej, i rozważymy kilka nowych funkcji :) Zacznijmy od pierwszego. Masz już zajęcia jak
Oczywiście
Czego więc potrzebujemy, aby tak się stało? Przede wszystkim potrzebujemy nowego
BufferedReader
wiele razy. Mam nadzieję, że nie miałeś czasu zapomnieć o tym stwierdzeniu:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Zanim zaczniesz czytać dalej, spróbuj sobie przypomnieć, za co odpowiada każdy składnik — System.in
, InputStreamReader
, — i dlaczego jest potrzebny. BufferedReader
Czy pamiętasz? Jeśli nie, nie martw się. :) Jeśli o czymś zapomniałeś, przeczytaj ponownie tę lekcję , która jest poświęcona zajęciom z czytania. Pokrótce przypomnimy, co potrafi każdy z nich. System.in
— jest to strumień do odbierania danych z klawiatury. W zasadzie samo wystarczyłoby zaimplementować logikę wymaganą do czytania tekstu. Ale, jak pamiętasz, System.in
może odczytywać tylko bajty, a nie znaki:
public class Main {
public static void main(String[] args) throws IOException {
while (true) {
int x = System.in.read();
System.out.println(x);
}
}
}
Jeśli wykonamy ten kod i wprowadzimy cyrylicę „Й”, wynik będzie następujący:
Й
208
153
10
Znaki cyrylicy zajmują 2 bajty w pamięci i są wyświetlane na ekranie. Liczba 10 jest dziesiętną reprezentacją znaku wysuwu wiersza, tj. od naciśnięcia Enter. Czytanie bajtów to taka przyjemność, więc używanie System.in
nie jest zbyt wygodne. Aby poprawnie odczytać litery cyrylicy (i inne), używamy InputStreamReader
jako opakowania:
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);
}
}
}
Wpisujemy tę samą literę „Й”, ale tym razem wynik jest inny:
Й
1049
10
InputStreamReader
przekonwertował dwa bajty (208 i 153) na pojedynczą liczbę 1049. To właśnie oznacza odczytywanie znaków. 1049 odpowiada cyrylicy „Й”. Łatwo możemy się przekonać, że to prawda:
public class Main {
public static void main(String[] args) throws IOException {
char x = 1049;
System.out.println(x);
}
}
Wyjście konsoli:
Й
I ponieważ forBufferedReader
(i ogólnie BufferedAnythingYouWant
), klasy buforowane są używane do optymalizacji wydajności. Dostęp do źródła danych (pliku, konsoli, zasobu sieciowego) jest dość kosztowny pod względem wydajności. Dlatego, aby ograniczyć liczbę dostępów, BufferedReader
odczytuje i gromadzi dane w specjalnym buforze, a stamtąd je pobieramy. W rezultacie liczba dostępów do źródła danych jest zmniejszona — prawdopodobnie o kilka rzędów wielkości! Kolejną BufferedReader
jego cechą i jej przewagą nad zwykłą InputStreamReader
, jest niezwykle pomocna readLine()
metoda, która odczytuje całe wiersze danych, a nie pojedyncze liczby. Jest to oczywiście bardzo wygodne w przypadku dużych tekstów. Oto jak wygląda czytanie wierszy:
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 ("The user entered the following text:");
System.out.println(s);
reader.close();
}
}
BufferedReader+InputStreamReader is faster than InputStreamReader alone
The user entered the following text:
BufferedReader+InputStreamReader is faster than InputStreamReader alone

BufferedReader
jest bardzo elastyczny. Nie jesteś ograniczony do pracy z klawiaturą. Na przykład możesz odczytywać dane bezpośrednio z sieci, po prostu przekazując wymagany adres URL do czytnika:
public class URLReader {
public static void main(String[] args) throws Exception {
URL oracle = new URL("https://www.oracle.com/index.html");
BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
Możesz odczytać dane z pliku, przekazując ścieżkę do pliku:
public class Main {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("testFile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream));
String str;
while ((str = reader.readLine()) != null) {
System.out.println (str);
}
reader.close();
}
}
Wymiana pliku System.out
Przyjrzyjmy się teraz interesującej możliwości, o której wcześniej nie mówiliśmy. Jak zapewne pamiętasz,System
klasa ma dwa pola statyczne — System.in
i System.out
. Ci bracia bliźniacy to obiekty strumieniowe. System.in
jest InputStream
. I System.out
jest PrintStream
. W tej chwili porozmawiamy o System.out
. Jeśli przejdziemy do System
kodu źródłowego klasy, zobaczymy to:
public final class System {
……………...
public final static PrintStream out = null;
…………
}
Zatem System.out
jest po prostu zwykłą zmienną statyczną klasySystem
. Nie ma w tym nic magicznego :) out
Zmienna jest PrintStream
referencją. Oto interesujące pytanie: kiedy System.out.println()
jest wykonywane, dlaczego dokładnie dane wyjściowe trafiają do konsoli, a nie gdzie indziej? I czy da się to jakoś zmienić? Załóżmy na przykład, że chcemy odczytać dane z konsoli i zapisać je do pliku tekstowego. Czy można to jakoś zaimplementować po prostu przy użyciu System.out
zamiast dodatkowych klas czytelników i pisarzy? Rzeczywiście jest :) I możemy to zrobić, mimo że System.out
zmienna jest oznaczona modyfikatorem final
! 
PrintStream
obiektu, który zastąpi obecny. Bieżący obiekt, ustawiony wSystem
class domyślnie nie służy naszym celom: wskazuje na konsolę. Musisz utworzyć nowy, który wskazuje plik tekstowy — „miejsce docelowe” dla naszych danych. Po drugie, musimy zrozumieć, jak przypisać nową wartość do System.out
zmiennej. Nie możesz użyć prostego operatora przypisania, ponieważ zmienna jest oznaczona final
. Pracujmy wstecz od końca. Tak się składa, że System
klasa ma metodę, której potrzebujemy: setOut()
. Pobiera PrintStream
obiekt i ustawia go jako miejsce docelowe dla danych wyjściowych. Właśnie tego potrzebujemy! Pozostało tylko stworzyć PrintStream
obiekt. To też jest łatwe:
PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt"));
Pełny kod będzie wyglądał następująco:
public class SystemRedirectService {
public static void main(String arr[]) throws FileNotFoundException
{
PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt"));
/* Save the current value of System.out in a separate variable so that later
we can switch back to console output */
PrintStream console = System.out;
// Assign a new value to System.out
System.setOut(filePrintStream);
System.out.println("This line will be written to the text file");
// Restore the old value of System.out
System.setOut(console);
System.out.println("But this line will be output to the console!");
}
}
W rezultacie pierwszy ciąg jest zapisywany do pliku tekstowego, a drugi jest wyświetlany w konsoli :) Możesz skopiować ten kod do swojego IDE i uruchomić go. Otwórz plik tekstowy, a zobaczysz, że napis został tam pomyślnie zapisany :) Na tym nasza lekcja dobiegła końca. Dzisiaj przypomnieliśmy sobie, jak pracować ze strumieniami i czytnikami. Przypomnieliśmy sobie, czym się od siebie różnią i poznaliśmy kilka nowych możliwości System.out
, z których korzystaliśmy na prawie każdej lekcji :) Do następnych lekcji!
Więcej czytania: |
---|
GO TO FULL VERSION