Java: różnica między PrintStream i PrintWriter

125

Jaka jest różnica między PrintStreami PrintWriter? Mają wiele wspólnych metod, dzięki czemu często mieszam te dwie klasy. Co więcej, myślę, że możemy ich używać do dokładnie tych samych celów. Ale musi być różnica, w przeciwnym razie byłaby tylko jedna klasa.

Przeszukałem archiwa, ale nie mogłem znaleźć tego pytania.

Martijn Courteaux
źródło
1
+1 Dobre pytanie, również mieszam te dwie klasy, a dokumentacja API też niewiele pomaga.
helpermethod
Inną różnicą jest sposób działania autoflush. Dla piszącego obecność znaku \ n w danych wyjściowych wyzwala funkcję flush (). Ale w strumieniu bajtów (PrintStream) są tylko bajty. autoflush działa wtedy zgodnie z opisem w Javadoc, w oparciu o: „własną koncepcję platformy dotyczącą separatora linii zamiast znaku nowej linii”.
min

Odpowiedzi:

129

Może to zabrzmieć nonszalancko, ale PrintStreamdrukuje do OutputStreami PrintWriterdrukuje do Writer. Ok, wątpię, czy dostanę jakiekolwiek punkty za stwierdzenie oczywistości. Ale to nie wszystko.

Jaka jest więc różnica między OutputStreama a Writer? Oba są strumieniami, przy czym podstawowa różnica polega na tym, że a OutputStreamto strumień bajtów, a a Writerto strumień znaków.

Jeśli OutputStreamzajmuje się bajtami, co z tym PrintStream.print(String)? Konwertuje znaki na bajty przy użyciu domyślnego kodowania platformy. Używanie domyślnego kodowania jest ogólnie złe, ponieważ może prowadzić do błędów podczas przenoszenia z jednej platformy na drugą, zwłaszcza jeśli generujesz plik na jednej platformie, a konsumujesz go na innej.

Za pomocą Writerzwykle określasz kodowanie, które ma być używane, unikając wszelkich zależności platformy.

Po co zawracać sobie głowę posiadaniem PrintStreamlitery JDK, skoro głównym celem jest zapisywanie znaków, a nie bajtów? PrintStreampoprzedza JDK 1.1, kiedy wprowadzono strumienie znaków programu Reader / Writer. Wyobrażam sobie, że Sun zdezaktualizowałby się, PrintStreamgdyby tylko fakt, że jest tak szeroko stosowany. (Wszakże nie chcesz Każde wywołanie System.outwygenerować ostrzeżenie przestarzałej API! Również zmiana typu od PrintStreamcelu PrintWriterna standardowych strumieni wyjściowych złamałby istniejące aplikacje).

mdma
źródło
3
Ja też tak myślałem - ale to nieprawda. Nawet PrintStream utrzymuje Writer pod maską - jeśli przekażesz mu OutputStream, zawinie go.
Jon Skeet
3
@Jon - wewnętrznie istnieje Writer, ale zapisuje do OutputStream, więc efektem netto jest to, że PrintStream zapisuje do OutputStream - następuje konwersja char na bajt i używa domyślnego kodowania platformy. Nie ma takiego wymogu konwersji znaków na bajty w PrintWriter, możesz pozostać ze znakami przez całą drogę.
mdma
„Domyślny zestaw znaków jest określany podczas uruchamiania maszyny wirtualnej i zazwyczaj zależy od ustawień regionalnych i zestawu znaków systemu operacyjnego.”, Również ustawienie regionalne zmienia domyślny zestaw znaków na niektórych platformach.
Pindatjuh
7
Od wersji Java 1.5 PrintStreamnie było ograniczone do używania domyślnego kodowania platformy; istnieją konstruktory, które akceptują nazwę zestawu znaków. W związku z tym rozróżnienie między PrintStreami PrintWriterpolega na tym, że a PrintWriternie może zapisywać surowych bajtów, a dwie klasy zawijają różne typy miejsc docelowych.
Ted Hopp
1
Być może warto również zauważyć znaczną różnicę w ich zachowaniu, podczas gdy oni skutecznie udostępnić interfejs PrintStream„s print()metody są funkcje convenience, które wymagają write(), jako takie wywołują autoflush jeśli włączona. PrintWriterz drugiej strony nie będzie autoflush po wywołaniu print(). Demonstrowałem dzisiaj niektórych początkujących w Javie i to było łapanie uczniów, którzy nie byli zaznajomieni z koniecznością ręcznego spłukiwania. W przeciwnym razie twoja odpowiedź jest świetna.
Robadob
61

Przy PrintStreamużyciu domyślnego kodowania platformy.

PrintStream stream = new PrintStream(output);

Z PrintWritermożna jednak zdać OutputStreamWriterz kodowaniem konkretnego.

PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"));

Zaletą jest to, że możesz kontrolować kodowanie znaków, które powinny być napisane w taki sposób, aby ostatecznie nie skończyły się jako mojibake .

BalusC
źródło
12
Od 1.4 istnieje nowy konstruktor dla PrintStream, który pobiera kodowaniePrintStream(OutputStream out, boolean autoFlush, String encoding)
artbristol,
19

Od wersji JDK 1.4 można określić kodowanie znaków dla PrintStream. Tak więc różnice między PrintStream i PrintWriter dotyczą tylko zachowania automatycznego opróżniania i tego, że PrintStream nie może opakować Writer.

Renan Mozone
źródło
3

Programy zapisujące, takie jak PrintWriter, są przeznaczone do wyjścia tekstowego, a strumienie do wyjścia binarnego. Pisarze zajmują się zestawami znaków za Ciebie. Strumienie nie, ponieważ zakłada się, że nie chcesz tego rodzaju konwersji, która zepsułaby twoje dane binarne, a gdybyś to zrobił, używałbyś programu zapisującego.

sblundy
źródło
1
Z wyjątkiem PrintStream, ponieważ ten pobiera kodowanie, dzięki czemu może obsłużyć nieco więcej niż standardowy OutputStream.
Simon Groenewolt
Brzmi dziwnie, że System.out, którego jedynym celem jest drukowanie łańcuchów, jest w rzeczywistości PrintStream.
min
„Twórcy zajmują się zestawami znaków za Ciebie” - tylko Pisarze zajmujący się zamianą znaków na bajty. Nie wszyscy Pisarze to robią.
Aivar
2

Możesz zapisać nieprzetworzone bajty do Stream, a nie do modułu Writer. W PrintWriter listy javadoc pozostałe różnice (co najważniejsze, jest w stanie ustawić kodowanie strumienia, więc można go zinterpretować surowe bajty Powiedziałbym).

Simon Groenewolt
źródło
Z PrintStream można również określić kodowanie
Aivar,
1

z core Java by Horstmann

Weterani Javy mogą się zastanawiać, co się stało z klasą PrintStream i z System.out. W Javie 1.0 klasa PrintStream po prostu obcięła wszystkie znaki Unicode do znaków ASCII, upuszczając górny bajt. (W tamtym czasie Unicode był nadal 16-bitowym kodowaniem). Oczywiście nie było to czyste ani przenośne podejście i zostało to naprawione wraz z wprowadzeniem czytników i pisarzy w Javie 1.1. Ze względu na zgodność z istniejącym kodem, System.in, System.out i System.err są nadal strumieniami wejścia / wyjścia, a nie czytnikami i piszącymi. Ale teraz klasa PrintStream wewnętrznie konwertuje znaki Unicode na domyślne kodowanie hosta w taki sam sposób, jak robi to PrintWriter. Obiekty typu PrintStream zachowują się dokładnie tak samo jak pisarze druku, gdy używasz metod print i println,

nichijou
źródło
-3

Printwriter to udoskonalenie printstream.

IE printstream do określonego celu.

Spoo
źródło