— Zaczniemy od strumieni wejścia/wyjścia pliku. Ale po kolei.

Istnieją dwie klasy do odczytywania i zapisywania plików: FileInputStream i FileOutputStream. Jak już się pewnie domyślasz FileInputStream pozwala na sekwencyjny odczyt bajtów z pliku, a FileOutputStream na sekwencyjny zapis bajtów do pliku. Oto metody, jakie posiadają te klasy:

Metoda Co robi ta metoda
FileInputStream(String fileName);
— To konstruktor. Pozwala określić nazwę pliku na dysku, z którego utworzony obiekt będzie odczytywał dane.
int read();
— Metoda ta odczytuje jeden bajt z pliku i go zwraca. Zwracana wartość jest rozszerzana do int.
int available();
— Metoda ta zwraca liczbę nieodczytanych (dostępnych) bajtów.
void close();
— Ta metoda «zamyka» strumień. Wywołuje się ją po zakończeniu pracy ze strumieniem.
Następnie obiekt wykonuje operacje porządkowe potrzebne do zamknięcia pliku itd.
W tym momencie nie można odczytać więcej danych ze strumienia.

Tak dla zabawy obliczmy sumę wszystkich bajtów w pliku. Oto, jak wygląda kod:

Zsumujmy wszystkie bajty w pliku
public static void main(String[] args) throws Exception
{
 //Utwórz obiekt FileInputStream powiązany z «c:/data.txt».
 FileInputStream inputStream = new FileInputStream("c:/data.txt");
 long sum = 0;

 while (inputStream.available() > 0) //tak długo, jak występują nieodczytane bajty
 {
  int data = inputStream.read(); //Odczytaj następny bajt
  sum +=  data; //Dodaj go do bieżącej sumy
 }
 inputStream.close(); //Zamknij strumień

 System.out.println(sum); //Wyświetl sumę na ekranie.
}

— Zajmowaliśmy się już czymś takim wcześniej. Jak jest zbudowany FileOutputStream?

– OK. Spójrz na to:

Metoda Co robi ta metoda
FileOutputStream (String fileName);
— To jest konstruktor. Pozwala on określić nazwę pliku na dysku, do którego utworzony obiekt będzie zapisywał dane.
void write(int data);
— Ta metoda zapisze następny bajt, obcinając dane do jednego bajtu.
void flush();
— Dane do zapisu są często najpierw gromadzone w pamięci w dużych blokach i dopiero wtedy zapisywane na dysku.

Polecenie flush wymusza zapisanie na dysku wszystkich niezachowanych informacji.

void close();
— Ta metoda «zamyka» strumień. Wywołuje się ją po zakończeniu pracy ze strumieniem.
Następnie obiekt wykonuje operacje porządkowe potrzebne do zamknięcia pliku itd.

Nie możesz już zapisywać danych w strumieniu, a polecenie flush jest wywoływane automatycznie.

– To wszystko?

— Tak, właściwie to istnieje tylko jedna metoda służąca do zapisu danych: write(). Zapisuje ona tylko jeden bajt na raz. Jednak pozwala Ci zapisać do pliku tyle informacji, ile chcesz.

Programowanie to proces dzielenia jednego dużego i złożonego zadania na wiele małych. Zasadniczo odbywa się tu ten sam proces: odczyt i zapis dużych bloków danych jest dzielony na odczyt i każdorazowy zapis w częściach o rozmiarze jednego bajta.

Oto jak można wykorzystać te klasy do skopiowania pliku na dysk:

Skopiuj plik na dysk
public static void main(String[] args) throws Exception
{
 //Utwórz strumień do odczytu bajtów z pliku
 FileInputStream inputStream = new FileInputStream("c:/data.txt");
 //Utwórz strumień do zapisu bajtów do pliku
 FileOutputStream outputStream = new FileOutputStream("c:/result.txt");

 while (inputStream.available() > 0) //tak długo, jak występują nieodczytane bajty
 {
  int data = inputStream.read(); //Wczytaj następny bajt do zmiennej
  outputStream.write(data); //i zapisz go do drugiego strumienia
 }

 inputStream.close(); //Zamknij oba strumienie. Nie są już nam potrzebne.
 outputStream.close();
}

— Dzięki, Raszi. W końcu rozumiem, jak ten kod działa naprawdę.