Strumienie wejścia/wyjścia (I/O streams) to jedna z podstawowych koncepcji Javy, która pojawiła się w wczesnych wersjach języka. Koncepcja ta została pierwotnie stworzona w celu abstrahowania procesów odczytu i zapisu danych: strumień może być powiązany z plikiem, siecią lub nawet konsolą — dla kodu wygląda to tak samo.
Problem pojawia się, gdy programista niewłaściwie zarządza strumieniami, zapomina je zamknąć lub myli różne typy strumieni (znakowe i bajtowe), co często prowadzi do wycieków zasobów, zniekształcenia danych lub błędów w czasie wykonania.
Rozwiązanie — umiejętne zrozumienie i stosowanie hierarchii strumieni wejścia/wyjścia (InputStream/OutputStream dla bajtów, Reader/Writer dla znaków), a także obowiązkowe zamykanie strumieni po zakończeniu pracy, najlepiej przez try-with-resources od wersji Javy 7.
Przykład kodu odczytu i zapisu pliku:
try (BufferedReader reader = new BufferedReader(new FileReader("input.txt")); BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) { String line; while ((line = reader.readLine()) != null) { writer.write(line); writer.newLine(); } }
Kluczowe cechy:
Co się stanie, jeśli nie zamkniesz strumienia wejścia/wyjścia w Javie?
Strumienie zajmują zasoby niskiego poziomu systemu operacyjnego, a niezamknięcie strumienia może prowadzić do wycieków pamięci, blokady plików, awarii aplikacji, a nawet wyczerpania deskryptorów plików na poziomie systemu operacyjnego.
Czy można używać tego samego OutputStream do zapisu do różnych plików?
Nie, klasyczny OutputStream jest sztywno powiązany z jednym źródłem/odbiorcą danych. Dla różnych plików — różne obiekty OutputStream.
Jaka jest różnica między PrintWriter a BufferedWriter? Kiedy używać którego?
PrintWriter specjalizuje się w uzupełnianiu wyjścia metodami formatowania, takimi jak println(), i potrafi działać z automatycznym przeładowywaniem. BufferedWriter zwiększa wydajność za pomocą buforowania. W większości zastosowań aplikacyjnych PrintWriter jest preferowany dla tekstowego wyjścia, ale jeśli potrzebujesz szybko pisać znaki lub ciągi bez formatowania — BufferedWriter sprawdzi się lepiej.
Programista odczytuje dane z dużego pliku za pomocą FileInputStream, nie używa buforowania i zapomina zamknąć strumień.
Plusy:
Minusy:
Wykorzystywana jest kombinacja BufferedReader z try-with-resources, odczyt i przetwarzanie odbywają się w paczkach po liniach, strumień automatycznie się zamyka.
Plusy:
Minusy: