1. Wprowadzenie
Wyobraź sobie, że otrzymałeś od księgowego plik z raportem, który zapisano w "Windows-1251" (stare kodowanie dla cyrylicy). Twoja aplikacja Java oczekuje wszystkich danych wejściowych w "UTF-8", w przeciwnym razie zaczyna „marudzić” i wyświetlać krzaczki zamiast liter. Albo, na przykład, integrujesz się z systemem, który akceptuje tylko "ISO-8859-1". Co robić? Oczywiście — przekodować plik!
Przekodowywanie — to proces, w którym odczytujesz tekst z pliku w jednym kodowaniu i zapisujesz go w innym. To tak, jakbyś przepisywał list z jednego języka na drugi, aby odbiorca na pewno zrozumiał Twoją wiadomość.
Jak działa przekodowywanie w Javie: podejście ogólne
W Javie łańcuchy (String) wewnątrz programu są zawsze przechowywane w Unicode (UTF‑16). Oznacza to, że kiedy odczytasz tekst z pliku, jest on już „uniwersalny” i może zostać zapisany w dowolnym obsługiwanym kodowaniu. Dlatego przekodowywanie to po prostu:
- Odczytać plik jako wiersze, podając poprawne kodowanie źródłowe.
- Zapisać te wiersze do nowego pliku, jawnie wskazując wymagane kodowanie docelowe.
Schemat:
[Plik w kodowaniu A] --(odczyt z Charset A)--> [String w pamięci] --(zapis z Charset B)--> [Plik w kodowaniu B]
2. Algorytm przekodowywania krok po kroku
Krok 1. Określ kodowanie źródłowe i docelowe
Kodowanie źródłowe — to, w którym zapisano plik wejściowy (np. "Windows-1251"). Kodowanie docelowe — to, w którym chcesz otrzymać wynik (np. "UTF-8").
Krok 2. Otwórz strumień do odczytu z właściwym kodowaniem
Użyj Files.newBufferedReader(Path, Charset) lub klasycznego InputStreamReader.
Krok 3. Otwórz strumień do zapisu z właściwym kodowaniem
Użyj Files.newBufferedWriter(Path, Charset) lub klasycznego OutputStreamWriter.
Krok 4. Czytaj wiersze i zapisuj je do nowego pliku
Czytaj wiersz po wierszu (albo całość — jeśli plik jest mały) i każdy wiersz zapisuj do nowego pliku.
Krok 5. Zamknij strumienie (najlepiej użyć try-with-resources)
Dzięki temu zapewnisz poprawne zwalnianie zasobów. Stosuj konstrukcję try-with-resources.
3. Przykład kodu: przekodowywanie Windows-1251 → UTF-8
Zaimplementujmy prosty program, który przekoduje plik z Windows‑1251 do UTF‑8. Taki przykład często spotyka się w praktyce, zwłaszcza gdy pracujesz z danymi rosyjskojęzycznymi.
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
public class FileReencoder {
public static void main(String[] args) throws IOException {
// Ścieżki do plików
Path inputPath = Paths.get("input-1251.txt");
Path outputPath = Paths.get("output-utf8.txt");
// Otwieramy reader z kodowaniem źródłowym Windows-1251
try (
BufferedReader reader = Files.newBufferedReader(inputPath, Charset.forName("Windows-1251"));
BufferedWriter writer = Files.newBufferedWriter(outputPath, StandardCharsets.UTF_8)
) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine(); // nie zapominamy o znaku nowej linii!
}
}
System.out.println("Plik został pomyślnie przekodowany z Windows-1251 do UTF-8!");
}
}
Tutaj jawnie wskazujemy kodowanie dla odczytu (Charset.forName("Windows-1251")) i dla zapisu (StandardCharsets.UTF_8). Następnie używamy try-with-resources, aby strumienie zamknęły się automatycznie nawet w przypadku błędów. writer.newLine() — przejście do nowej linii, aby zachować strukturę pliku.
4. Ważne niuanse i wskazówki
Jak ustalić kodowanie źródłowe pliku?
- Sam plik nie zawiera „etykiety” z informacją o kodowaniu (wyjątek — BOM, ale nie zawsze występuje).
- Jeśli plik tworzyłeś Ty — użyj tego samego kodowania, co przy zapisie.
- Jeśli plik przyszedł „skądinąd” — spróbuj otworzyć go w edytorze, który pokazuje kodowanie (np. Notepad++, Visual Studio Code).
- W Linuksie możesz użyć polecenia file -i nazwa_pliku, ale nie zawsze poprawnie rozpoznaje ono kodowanie.
Co się stanie, jeśli podasz błędne kodowanie źródłowe?
Dostaniesz „krzaczki” albo utratę znaków. Na przykład, jeśli odczytasz plik zapisany w Windows‑1251 jako UTF‑8, cyrylica zamieni się w "Привет".
Obsługa wyjątków
Podczas pracy z plikami zawsze mogą wystąpić błędy: plik nie znaleziony, brak uprawnień, błędne kodowanie. Używaj obsługi wyjątków (try-catch) lub wyrzucaj je wyżej (throws), aby aplikacja nie kończyła się nieoczekiwanie „bez podania przyczyny”.
Praca z dużymi plikami
Jeśli plik jest ogromny (wielkości gigabajtów!), używaj odczytu i zapisu wiersz po wierszu, jak w podanych przykładach. Nie wczytuj całego pliku do pamięci — w przeciwnym razie otrzymasz OutOfMemoryError.
Przekodowywanie „w locie” (streaming)
Jeśli plik jest bardzo duży, możesz nawet nie tworzyć pliku pośredniego, tylko czytać i pisać „w locie” — na przykład podczas strumieniowego przetwarzania danych z sieci.
5. Typowe błędy przy przekodowywaniu plików
Błąd №1: Nieprawidłowe kodowanie źródłowe. Jeśli pomylisz się w kodowaniu źródłowym, wynik będzie opłakany: „Privet” zamieni się w "Привет". Zawsze ustalaj, w jakim kodowaniu został utworzony plik.
Błąd №2: Niejawne użycie kodowania systemowego. Jeśli nie wskazać kodowania jawnie, Java użyje systemowego domyślnego (System.getProperty("file.encoding")). To może prowadzić do różnych rezultatów na różnych komputerach (np. na Windows — cp1251, na Linuksie — UTF‑8).
Błąd №3: Odczyt i zapis całego pliku do pamięci. Dla dużych plików takie podejście doprowadzi do przepełnienia pamięci. Używaj odczytu i zapisu wiersz po wierszu.
Błąd №4: Nieobsłużone wyjątki. Pliki mogą nie istnieć, być zajęte przez inne procesy albo zawierać uszkodzone znaki. Zawsze obsługuj wyjątki lub używaj try-with-resources.
Błąd №5: Przekodowywanie plików binarnych. Nie próbuj przekodowywać obrazów, PDF, archiwów i innych plików binarnych! To doprowadzi do ich uszkodzenia. Przekodowywanie ma sens tylko dla plików tekstowych.
GO TO FULL VERSION