Trzy największe pomyłki w dziejach świata: komunizm, bomba atomowa i Windows
Część 5.3. Operacje na plikach tekstowych

Ponieważ żaden poważniejszy program nie obejdzie się bez odwołań do plików dyskowych, to na zakończenie kursu poznamy podstawowe metody pracy z plikami tekstowymi. Java pozwala na współpracę programu z wszelkiego typu plikami i katalogami: tekstowymi i binarnymi, zapisanymi na dysku lokalnym i dostępnymi przez połączenie sieciowe. Omówienie wszystkich tych możliwości znacznie jednak przekracza zakres naszego kursu. Dlatego też omówimy jedynie pracę z lokalnymi plikami tekstowymi.

Praca z plikami wymaga użycia w aplikacji klasy File, która umożliwia odwołanie do pliku. Następnie potrzebną będą klasy FileInputStream i FileOutputStream, które umożliwiają odpowiednio czytanie z i zapisywanie do pliku dyskowego. Do otwierania i zapisu pliku użyjemy obiektu klasy FileDialog, która otwiera okienko dialogowe umożliwiające wybór lokalizacji i nazwy otwieranego / zapisywanego pliku.

Ponieważ każda operacja związana z plikiem dyskowym może spowodować wyjątek w programie (np.: brak pliku, który chcemy czytać, atrybut read-only dla zapisywanego pliku, itp.), to musimy wszystkie operacje dyskowe wykonywać z użyciem bloku try...catch.

W tej części kursu omówimy podstawowe metody w/w klas, a następnie napiszemy program: prosty edytor tekstowy z możliwością otwarcia pliku, jego edycji w komponencie TextArea oraz zapisanie do tego samego lub nowego pliku.

Klasa File

Klasa reprezentująca pliki i katalogi dyskowe jako abstrakt niezależny od systemu operacyjnego. Jego działanie i implementacja w konkretnym środowisku realizowane są przez maszynę wirtualną podczas pracy aplikacji. Podawanie ścieżki dostępu w zmiennych i/lub stałych powinno być zgodne ze standardem środowiska, w którym program pracuje. Dlatego bezpieczniej jest korzystać z klasy FileDialog, która jest ściśle związana z konkretnym systemem.

Obiekt klasy File jest niezmienny: raz utworzony reprezentuje obiekt, który nie może podlegać jakimkolwiek zmianom.

Konstruktor
File (String ścieżkaNazwa)tworzy instancję do pliku o podanej nazwie
Metody
setText (String tekst)zmienia wyświetlany w etykiecie tekst na podany
boolean exists ()sprawdza, czy podany plik istnieje
String getName ()pobiera nazwę pliku
boolean isDirectory ()sprawdza, czy podany plik jest katalogiem
boolean isFile ()sprawdza, czy podany plik jest plikiem
boolean canRead ()sprawdza, czy program może czytać z pliku
boolean canWrite ()sprawdza, czy program może zapisywać do pliku
boolean createNewFile ()tworzy nowy plik (tylko jeżeli podany plik nie istnieje)
boolean delete ()kasowanie pliku
long length ()zwraca długość pliku w bajtach
boolean renameTo (File plik)zmienia nazwę pliku

Klasa FileInputStream

Obiekt klasy FileInputStream służy do pobrania bajtów z danymi z pliku dyskowego. Może być użyty do odczytywania zarówno plików tekstowych, jak i binarnych (baz danych, grafiki, itp.).

Konstruktory
FileInputStream (File plik)otwiera strumień wejściowy dla pliku skojarzonego z obiektem typu File
FileInputStream (String nazwa)otwiera strumień wejściowy dla pliku o podanej nazwie (z pełną ścieżką dostępu)
Metody
read ()odczyt jednego bajtu danych
read (byte[ ] n)odczyt n.length bajtów z pliku i zapisuje je do podanej tablicy
read (byte[ ] n, int start, int ile)wczytuje z pliku ile bajtów od pozycji start i umieszcza je w tablicy (należy pamiętać, że bajty w pliku numerowane są od zera)
skip (long n)przesuwa wskaźnik pliku o n bajtów (dodatnie do przodu, a ujemne - wstecz)
close ()zamyka strumień i zwalnia związane z nim zasoby systemowe

Klasa FileOutputStream

Obiekt klasy FileOutputStream służy do zapisywania danych do pliku dyskowego (obiektu klasy File Jeżeli plik, do którego chcemy zapisywać dane nie może być otwarty w trybie do zapisu, to konstruktor klasy spowoduje powstanie wyjątku. Klasa może być wykorzystana do zapisu do pliku zarówno danych tekstowych, jak i binarnych (np. plików graficznych).

Konstruktory
FileOutputStream (File plik)tworzy strumień zapisu dla pliku dyskowego skojarzonego z obiektem plik
FileOutputStream (File plik, boolean dopisywanie)tworzy strumień zapisu dla pliku dyskowego skojarzonego z obiektem plik do dopisywania na końcu pliku
FileOutputStream (String nazwa)tworzy strumień zapisu dla pliku dyskowego o podanej nazwie
FileOutputStream (String nazwa, boolean dopisywanie)tworzy strumień zapisu dla pliku dyskowego o podanej nazwie do dopisywania na końcu pliku
Metody
write ()zapis jednego bajtu danych
write (byte[ ] n)zapis z tablicy bajtowej n do pliku n.length bajtów
write (byte[ ] n, int start, int ile)zapisuje do pliku ile bajtów z tablicy bajtowej n poczynając od pozycji start
close ()zamyka strumień i zwalnia związane z nim zasoby systemowe

Klasa FileDialog

Obiekt klasy FileDialog służy do wyświetlenia ona dialogowego, z którego użytkownik może wybrać istniejący lub podać nazwę nowego pliku. Jest to okno modalne, co oznacza, że użytkownik nie ma możliwości powrotu do aplikacji bez wybrania pliku lub anulowania wyboru.

Konstruktory
FileDialog (Frame okno)tworzy okno dialogowe do wybierania pliku
FileDialog (Frame okno, String tytuł)tworzy okno dialogowe do wybierania pliku z podanym tytułem okna
FileDialog (Frame okno, String tytuł, int tryb)tworzy okno dialogowe do wybierania pliku z podanym tytułem okna i trybem, który może być jedną z wartości:
FileDialog.LOAD - otwarcie pliku do odczytu
FileDialog.SAVE - otwarcie pliku do zapisu
Metody
setMode (int tryb)określenie trybu otwierania pliku:
FileDialog.LOAD - otwarcie pliku do odczytu
FileDialog.SAVE - otwarcie pliku do zapisu
setDirectory (String katalog)definiuje katalog bieżący dla okienka dialogowego
setFile (String plik)definiuje domyślną nazwę pliku dla okienka dialogowego
setFilenameFilter (FilenameFilter filtr)definiuje filtr wyświetlanych w okienku plików (bp.: "*.*" lub "*.txt")
show ( )wyświetla okno dialogowe
String getDirectory ( )zwraca nazwę katalogu wybranego przez użytkownika
String getFile ( )zwraca nazwę pliku wybranego przez użytkownika

 

Na zakończenie tej części kursu program demonstrujący pracę z plikami dyskowymi. Jest to prosty edytor tekstowy pozwalający otworzyć plik, dokonać jego edycji i zapisać pod tą sama lub zmieniona nazwą. Można też zapisać nowy tekst do nowego lub już istniejącego pliku bez otwierania pliku.

import java.awt.*;
import java.awt.event.*;
import java.io.*;

public class FileEditor extends Frame implements WindowListener, ActionListener
{ TextArea textArea;

  public FileEditor()
  { super ( );
    addWindowListener(this);
    setSize(800, 600);
    setResizable(false);
    setTitle("Edytor plików tekstowych");
    setLayout(null);
      
    textArea = new TextArea();
    textArea.setBounds(0, 40, 800, 580);
    this.add(textArea);
      
    MenuBar menuBar = new MenuBar();
    setMenuBar(menuBar);
    Menu menu = new Menu("Plik");
    menu.add(new MenuItem("Otwórz"));
    menu.add(new MenuItem("Zapisz"));
    menu.add(new MenuItem("-"));
    menu.add(new MenuItem("Zamknij"));
    menuBar.add(menu);
      
    menu.addActionListener(this);
    setVisible(true);
  }

  // metoda obsługująca wybraną opcję z menu
  public void actionPerformed (ActionEvent e)
  { String command = e.getActionCommand();
    if (command.equals("Zamknij"))    { System.exit(0); }
    else if (command.equals("Otwórz"))
    { String fileName = ShowFileDialog(FileDialog.LOAD);
      if (fileName != null)
      { // wywołanie metody otwarcia pliku
        Load(fileName);
      }
    }
    else if (command.equals("Zapisz"))
    { String fileName = ShowFileDialog(FileDialog.SAVE);
      if (fileName != null)
      { // wywołanie metody zapisu pliku
        Save(fileName);
      }
    }
  }

  // metoda odpowiedzialna za wyświetlanie okna wyboru pliku
  public String ShowFileDialog (int mode)
  { // tworzymy nowe okno dialogowe
    FileDialog fileDialog = new FileDialog(this);

    // ustalamy tryb odczyt / zapis
    fileDialog.setMode(mode);
    // wyświetlamy okno dialogowe
    fileDialog.show();
    // pobieramy i zwracamy nazwę wybranego pliku
    String fileName = fileDialog.getFile();
    return (fileName);
  }

  // wczytanie i wyświetlenie pliku
  public void Load (String fileName)
  { // tworzenie zmiennych strumienia i pliku wejściowego
    FileInputStream fileInput = null;
    File file = new File(fileName);

    // otwarcie pliku wejściowego:
    // może wystąpić wyjątek, dlatego musimy użyć bloku try...catch
    try
    { fileInput = new FileInputStream(file);
    }
    catch(FileNotFoundException e)
    { System.out.println("Brak pliku " + fileName);
      return;
    }

    textArea.setText("");
    byte buffer [ ] = new byte [ (int)file.length() ];
    // czytanie z pliku:
    // tu też może wystąpić wyjątek, dlatego używamy bloku try...catch
    try
    { fileInput.read(buffer);
      { textArea.append (new String(buffer));
      }
	  fileInput.close();
    }
    catch(IOException e)
    { System.out.println("Bład podczas czytania pliku");
      return;
    }

    // zmieniamy tytuł aplikacji
    setTitle("Edytor plików tekstowych [" + fileName + "]");
  }


  // zapis tekstu do pliku na dysk
  public void Save (String fileName)
  { // tworzenie zmiennych strumienia i pliku wyjściowego
    FileOutputStream fileOutput = null;
    File file = new File(fileName);

    // otwarcie pliku wyjściowego:
    // może wystąpić wyjątek, dlatego musimy użyć bloku try...catch
    try
    { fileOutput = new FileOutputStream(file);
    }
    catch(FileNotFoundException e)
    { System.out.println("Błąd otwarcia do zapisu pliku " + fileName);
      return;
    }

    // zapis do pliku:
    // tu też może wystąpić wyjątek, dlatego używamy bloku try...catch
    try
    { byte buffer[] = textArea.getText().getBytes();
      fileOutput.write(buffer);
	  fileOutput.close();
    }
    catch(IOException e)
    { System.out.println("Błada podczas zapisu pliku");
      return;
    }

    // zmieniamy tytuł aplikacji
    setTitle("Edytor plików tekstowych [" + fileName + "]");
  }


  public static void main(String args[])
  { 
    new FileEditor();
  }

  public void windowClosing    (WindowEvent e) { System.exit(0); }
  public void windowClosed     (WindowEvent e) {   }
  public void windowOpened     (WindowEvent e) {   }
  public void windowIconified  (WindowEvent e) {   }
  public void windowDeiconified(WindowEvent e) {   }
  public void windowActivated  (WindowEvent e) {   }
  public void windowDeactivated(WindowEvent e) {   }
}

 

A tak wygląda okno programu po uruchomieniu:

Okno programu
« wstecz   dalej »