JavaRush /Blog Java /Random-PL /We/Wy w Javie. Klasy FileInputStream, FileOutputStream, B...

We/Wy w Javie. Klasy FileInputStream, FileOutputStream, BufferedInputStream

Opublikowano w grupie Random-PL
Cześć! Na dzisiejszym wykładzie będziemy kontynuować dyskusję na temat strumieni wejściowych i wyjściowych w Javie, czyli w skrócie Java I/O („input-output”). To nie pierwszy wykład na ten temat i nie ostatni :) Tak się składa, że ​​Java jako język daje wiele możliwości pracy z wejściem/wyjściem. Klas realizujących tę funkcjonalność jest całkiem sporo, dlatego podzieliliśmy je na kilka wykładów, żebyście się na początku nie pomylili :) We/Wy w Javie.  Klasy FileInputStream, FileOutputStream, BufferedInputStream - 1W poprzednich wykładach poruszaliśmy BufferedReader , a także klasy abstrakcyjne InputStream i OutputStream oraz kilka potomków. Dzisiaj przyjrzymy się 3 nowym klasom: FileInputStream , FileOutputStream i BufferedInputStream .

Klasa FileOutputStream

Głównym celem klasy FileOutputStream jest zapisywanie bajtów do pliku. Nic skomplikowanego :) FileOutputStream jest jedną z implementacji abstrakcyjnej klasy OutputStream . W konstruktorze obiekty tej klasy przyjmują albo ścieżkę do pliku docelowego (do którego mają zostać zapisane bajty), albo obiekt klasy File. Spójrzmy na oba przykłady:
public class Main {

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


       File file = new File("C:\\Users\\Username\\Desktop\\test.txt");
       FileOutputStream fileOutputStream = new FileOutputStream(file);

       String greetings = "Cześć! Witamy w JavaRush - najlepszej witrynie dla tych, którzy chcą zostać programistami!";

       fileOutputStream.write(greetings.getBytes());

       fileOutputStream.close();
   }
}
Tworząc obiekt, Fileokreśliliśmy w konstruktorze ścieżkę, w której ma się on znajdować. Nie ma potrzeby tworzenia go z wyprzedzeniem: jeśli nie istnieje, program sam go utworzy. Możesz obejść się bez tworzenia dodatkowego obiektu i po prostu przekazać ciąg znaków z adresem:
public class Main {

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


       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt");

       String greetings = "Cześć! Witamy w JavaRush - najlepszej witrynie dla tych, którzy chcą zostać programistami!";

       fileOutputStream.write(greetings.getBytes());

       fileOutputStream.close();
   }
}
Wynik w obu przypadkach będzie taki sam. Możemy otworzyć nasz plik i zobaczyć tam:

Cześć! Добро пожаловать на JavaRush — лучший сайт для тех, кто хочет стать программистом!
Jednak jest tu jedno zastrzeżenie. Spróbuj uruchomić kod z powyższego przykładu kilka razy z rzędu, a następnie spójrz na plik i odpowiedz na pytanie: ile linii widzisz w nim zapisanych? Tylko jeden. Ale uruchomiłeś kod kilka razy. Okazuje się jednak, że za każdym razem dane były nadpisywane, zastępując stare. A co jeśli nam to nie odpowiada i potrzebujemy nagrywania sekwencyjnego? A co jeśli będziemy chcieli zapisać nasze powitanie do pliku trzy razy z rzędu? Tutaj wszystko jest proste. Ponieważ sam język nie może wiedzieć, jakiego rodzaju zachowania potrzebujemy w każdym przypadku, FileOutputStreammożesz przekazać konstruktorowi dodatkowy parametr - boolean append. Jeśli jego wartość to true , dane zostaną zapisane na końcu pliku. Jeśli false (a wartością domyślną jest false ), stare dane zostaną usunięte i zapisane zostaną nowe. Przetestujmy i uruchommy nasz zmodyfikowany kod trzy razy:
public class Main {

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


       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true);

       String greetings = "Cześć! Witamy w JavaRush — najlepszej witrynie dla tych, którzy chcą zostać programistami!\r\n";

       fileOutputStream.write(greetings.getBytes());

       fileOutputStream.close();
   }
}
Wynik w pliku:

Cześć! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Cześć! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Cześć! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Inna rzecz! Należy pamiętać o tej funkcji podczas korzystania z klas we/wy. Kiedyś musiałem godzinami siedzieć nad zadaniami, żeby zrozumieć, dokąd poszły moje stare dane z plików :) I oczywiście, podobnie jak w przypadku innych klas I/O, nie zapomnij o zwolnieniu zasobów przez klasę close().

Klasa FileInputStream

Klasa ma FileInputStreamodwrotny cel - odczytywanie bajtów z pliku. Podobnie jak FileOutputStreamdziedziczy OutputStream, ta klasa wywodzi się z klasy abstrakcyjnej InputStream. Napiszmy kilka linijek tekstu w naszym tekście „ test.txt ”:

«So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters»
We/Wy w Javie.  Klasy FileInputStream, FileOutputStream, BufferedInputStream - 2 Tak wygląda implementacja odczytu danych z pliku za pomocą FileInputStream:
public class Main {

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

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");

       int i;

       while((i=fileInputStream.read())!= -1){

           System.out.print((char)i);
       }
   }
}
Odczytujemy jeden bajt z pliku, konwertujemy odczytane bajty na znaki i wysyłamy je do konsoli. A oto wynik w konsoli:

So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters

Klasa BufferedInputStream

Myślę, że biorąc pod uwagę wiedzę z poprzednich wykładów, można łatwo stwierdzić, po co te zajęcia są potrzebne BufferedInputStreami jakie mają nad nimi zalety FileInputStream:) Spotkaliśmy się już ze strumieniami buforowanymi, więc spróbuj zgadnąć (lub zapamiętać) przed dalszą lekturą :) Strumienie buforowane są potrzebne przede wszystkim do optymalizacji operacji we/wy. Uzyskiwanie dostępu do źródła danych, na przykład odczytywanie z pliku, jest operacją wymagającą dużej wydajności. A dostęp do pliku w celu odczytania jednego bajtu za każdym razem jest marnotrawstwem. Dlatego BufferedInputStreamodczytuje dane nie po bajcie, ale blokami i tymczasowo przechowuje je w specjalnym buforze. Dzięki temu możemy zoptymalizować działanie programu poprzez zmniejszenie ilości dostępów do pliku. Zobaczmy jak to wygląda:
public class Main {

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

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");

       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200);

       int i;

       while((i = bufferedInputStream.read())!= -1){

           System.out.print((char)i);
       }
   }
}
Tutaj stworzyliśmy obiekt BufferedInputStream. Akceptuje obiekt lub dowolny z jego następców jako dane wejściowe InputStream, więc poprzedni FileInputStreamwystarczy. Jako dodatkowy parametr przyjmuje rozmiar bufora w bajtach. Teraz dzięki temu dane będą odczytywane z pliku nie po bajcie, a po 200! Wyobraź sobie, jak bardzo zmniejszyliśmy liczbę dostępów do plików. Aby porównać wydajność, możesz wziąć duży plik tekstowy o rozmiarze kilku megabajtów i porównać czas potrzebny na jego odczytanie i wyświetlenie na konsoli w milisekundach, używając FileInputStreami BufferedInputStream. Oto oba przykłady kodu:
public class Main {

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

       Date date = new Date();

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf");

       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

       int i;

       while((i = bufferedInputStream.read())!= -1){

           System.out.print((char)i);
       }

       Date date1 = new Date();

       System.out.println((date1.getTime() - date.getTime()));
   }
}



public class Main {

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

       Date date = new Date();

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf");


       int i;

       while((i = fileInputStream.read())!= -1){

           System.out.print((char)i);
       }

       Date date1 = new Date();

       System.out.println((date1.getTime() - date.getTime()));
   }
}
Podczas czytania pliku o wielkości 1,5 MB na moim komputerze FileInputStreamwykonał on zadanie w ~ 3500 milisekund, ale tutaj BufferedInputStreamwykonał to zadanie w ~ 1700 milisekund. Jak widać, buforowany strumień zoptymalizował wydajność programu 2 razy! :) Będziemy kontynuować naukę klas I/O - do zobaczenia wkrótce!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION