Properties - pliki tekstowe
Spis treści
1 Wstęp
2 Pliki .properties
3 Ładowanie plików .properties
4 Zapisywanie do plików .properties
5 Podsumowanie
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ść
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:
- Ą - \u0104; ą - \u0105
- Ć - \u0106; ć - \u0107
- Ę - \u0118; ę - \u0119
- Ł - \u0141; ł - \u0142
- Ń - \u0143; ń - \u0144
- Ó - \u00d3; ó - \u00f3
- Ś - \u015a; ś - \u015b
- Ź - \u0179; ź - \u017a
- Ż - \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();
}
}
}
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();
}
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.
elis dnia 26-02-2008 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 dnia 25-02-2008 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 dnia 22-02-2008 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.


