Java

Properties - pliki tekstowe



Wstęp


Zapewne każdy z was spotkał się z tym problemem. Problemem, który dręczył pokolenia informatyków i zapewne będzie dręczył kolejne. Gdzie należy trzymać konfigurację potrzebną do prawidłowego działania programu.
Pierwszym i najbardziej naturalnym postępowaniem jest "zaszycie" konfiguracji w kodzie. Jest to najgorsza z możliwych metod. Do jej głównych wad należą:
  • trudność wprowadzania zmian. Zmiana wymaga ponownej kompilacji kodu
  • możliwa redundancja kodu
Jednak ma ona jedną zaletę. Jest bardzo szybka na etapie implementacji oraz bardzo bezpieczna. Zazwyczaj używa się jej tam gdzie:
  • nie ma obsługi plików
  • są bardzo duże ograniczenia w zakresie wykorzystania pamięci / szybkości procesora
Drugą znacznie bardziej poprawną metodą jest przeniesienie konfiguracji do osobnego pliku. W ten sposób uzyskujemy bardzo dużą elastyczność i możliwość zmiany ustawień bez potrzeby ingerencji w kod. W języku Java istnieją dwie główne metody tworzenia konfiguracji za pomocą plików. Pierwsza z nich to wykorzystanie dokumentów XML. Druga, i tą się tu zajmiemy dokładnie, to wykorzystanie obiektu Properties.

Pliki .properties


Podstawą działania obiektu Properties są pliki tekstowe. Zgodnie z konwencją mają one rozszerzenie .properties. Ich zawartość to pary < klucz >>=< wartość >> każda para w osobnej i pojedynczej linii. Ostatnie oznacza iż wartość nie zależnie jak długa musi znajdować się w jednej linii. Przykład pliku:
# komentarz
klucz=wartość

Istotną cechy to
  • plik powinien być zapisany w ISO-8859-1
  • należy unikać polskich znaków w nazwach kluczy
  • klucze muszą być unikalne

Jak widać kodowanie powoduje że nie będziemy mogli w prosty sposób używać polskich znaków. Rozwiązaniem jest zamiana polskich znaków na kody UTF-8:
  1. Ą - \u0104; ą - \u0105
  2. Ć - \u0106; ć - \u0107
  3. Ę - \u0118; ę - \u0119
  4. Ł - \u0141; ł - \u0142
  5. Ń - \u0143; ń - \u0144
  6. Ó - \u00d3; ó - \u00f3
  7. Ś - \u015a; ś - \u015b
  8. Ź - \u0179; ź - \u017a
  9. Ż - \u017b; ż - \u017c

Ładowanie plików .properties


Jak mamy już utworzony nasz plik .properties to czas załadować go do obiektu. W tym celu musimy:
  • utworzyć strumień wejściowy InputStream
  • utworzyć obiekt Properties
  • załadować dane ze strumienia wejścia do obiektu Properties

Dodatkowo wypiszemy jego zawartość.
I oto klasa to realizująca:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
 
 
public class PropertiesTest {
        //Plik z konfiguracją
        private File f = new File("conf.properties");
        //przyszły obiekt Properties
        private Properties properties = new Properties();
 
        public static void main(String[] args) {
                System.setProperty("file.encoding", "UTF-8");
                PropertiesTest pt = new PropertiesTest();
                pt.loadProperties();
                System.out.println(pt.properties.getProperty("klucz"));
        }
 
        public void loadProperties(){
                //Strumień wejściowy
                InputStream is;
                try {
                        is = new FileInputStream(f);
                        //ładujemy nasze ustawienia
                        properties.load(is);
                } catch (FileNotFoundException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }
}


Jak widać jest to bardzo proste.

Zapisywanie do plików .properties


Została jeszcze jedna kwestia do poruszenia. Jak zapisywać zmienione ustawienia do plików? Obiekt Properties posiada dwie metody, które pozwalają na tą operację.
  • save(FileOutputStream, String) - oznaczoną jako przestarzała
  • store(FileOutputStream, String) - zalecaną

Pierwszy argument to strumień wyjścia do którego zostaną zapisane dane. Drugi to komentarz. Tu istotna uwaga jeżeli podamy komentarz jako pusty to zostanie do pliku wstawiona data utworzenia i pusta linia. Jeżeli komentarz będzie równy null to wstawiona zostanie tylko data utworzenia.
Na koniec dodatkowa metoda zapisująca nasze ustawienia:
public void saveProperties(String key, String value){
        OutputStream os;
        try {
                os = new FileOutputStream(f);
                properties.setProperty(key, value);
                properties.store(os, null);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
                e.printStackTrace();
}


Podsumowanie


Pliki .properties są podstawowym sposobem zapisu danych konfiguracyjnych. Ich istotną wadą jest konieczność stosowania kodowania ISO-8859-1 co utrudnia stosowanie polskich znaków.

5 komentarzy

Koziołek 2015-01-29 13:59

@Olamagato, mówisz o zupełnie innym mechanizmie i zupełnie innym API. Zgadzam się, ze nowszym, ale Properties API nadal jest szeroko używane.

Olamagato 2012-05-14 13:03

Artykuł w całości zdezaktualizowany przez istniejącą od Javy 1.4 klasę java.util.prefs.Preferences, która właśnie służy do niezależnego od platformy i języka trzymania swoich ustawień. Ustawienia można przechowywać w danych prywatnych konta użytkownika lub w danych systemowych (dla wszystkich kont wspólnie). Rozwiązuje to więc całkowicie problem z kodowaniem polskich znaków. Jedynym ograniczeniem jest limit 8 KB danych, który jak na dane konfiguracyjne jest spory.

elis 2008-02-26 08:36

Wyrzucone zostanie wtedy FNFE, które zostanie wyłapane przez catch(IOE...) a printStackTrace wypisze nam przyczynę (brak dostępu). Sprawdziłem ;-)

Koziołek 2008-02-25 16:55

Niekoniecznie. Jeżeli plik istnieje, a nie masz praw do jego odczytu to IOE nie powie ci tego, a FNFE już tak.

elis 2008-02-22 07:25

Świetny artykuł! Tylko jedna uwaga - w tym przypadku (skoro nie obsługujemy błędów) nie jest niezbędne wyłapywanie wyjątków FileNotFoundException, wystarczy IOException. Pozdrawiam.