Kategória: Java standard könyvtárak.
Beolvasás fájlból kezdetben
A fájlkezelés a Java-ban hosszú utat járt be, és ez egy jó példa arra, hogy hogyan lehet valamit nagyon elrontani. Kezdetben létrehoztak egy rendkívül elbonyolított InputStream és OutputStream hierarchiát, és erre építették rá a fájlműveleteket is. Csak érdekességképpen említem meg, hogy kezdetben hogyan lehetett ezt megoldani:
import java.io.*; import java.nio.charset.Charset; class FileInputExample { public static void main(String[] args) { BufferedReader dis = null; String line = null; try { File file = new File("mydata.txt"); FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis); InputStreamReader isr = new InputStreamReader(bis, Charset.defaultCharset()); dis = new BufferedReader(isr); while ((line = dis.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (dis != null) { try { dis.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } } } }
Tehát szükség volt a következőkre: File, FileInputStream, BufferedInputStream, InputStreamReader, kétszintű hibakezelés, hogy csak az alap példa problémáit említsem. Ezzel valójában két probléma volt:
- Lehetetlen volt megjegyezni, minden egyes alkalommal rá kellett keresni.
- Szinte sikított a változásért, ami be is következett, viszont ezzel még komplikáltabb lett a rendszer. A felülről kompatibilitás kényszere miatt ugyanis a régi rendszer megmaradt (ráadásul részben depricated lett, részben nem; tehát az eredeti példa ráadásul nem is pont így nézett ki mint a fent megadott), és megjelent az új, egyszerűsített változat is.
- Ugyanakkor idővel további javításokat tettek bele, ami egyrészt jó, másrészt tovább fokozta a kuszaságot.
Ha valaki el szeretne mélyedni az input és output stream-ek világában, annak ajánlom elrettentésül az ezen az oldalon található táblázatot: http://tutorials.jenkov.com/java-io/overview.html, a kapcsolódó oldalakat, valamint a https://www.javatpoint.com/java-io oldalt.
Kiírás fájlba kezdetben
A kezdeti fájlba írás is eléggé komplikált (ráadásul hibásan működik, legalábbis nálam):
import java.io.*; class FileInputExample { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("test.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); DataOutputStream outStream = new DataOutputStream(bos); outStream.writeUTF("Hello"); outStream.writeUTF(" world"); outStream.close(); } }
Fájlból olvasás a Scanner osztály segítségével
A Scanner osztály a Java 1.5-ben jelent meg, és jelentős mértékben leegyszerűsítette a beolvasást:
import java.io.*; import java.util.Scanner; class FileInputExample { public static void main(String[] args) throws IOException { File file = new File("mydata.txt"); Scanner sc = new Scanner(file); while (sc.hasNextLine()) { System.out.println(sc.nextLine()); } sc.close(); }
Sőt, ha beállítjuk, hogy az elválasztó karakter az alapértelmezett új sor helyett a fájl vége legyen, akkor egyből be tudjuk olvasni, ciklus nélkül:
import java.io.*; import java.util.Scanner; class FileInputExample { public static void main(String[] args) throws IOException { File file = new File("mydata.txt"); Scanner sc = new Scanner(file); sc.useDelimiter("\\Z"); System.out.println(sc.next()); sc.close(); } }
A try-with-resources módszerrel a fenti lehetőség így néz ki:
import java.io.*; import java.io.FileNotFoundException; import java.util.Scanner; class FileInputExample { public static void main(String[] args) { try (Scanner sc = new Scanner(new File("mydata.txt"))) { while (sc.hasNextLine()) { System.out.println(sc.nextLine()); } } catch (FileNotFoundException e) { e.printStackTrace(); } } }
Kiírás a PrintWriter osztály segítségével
A FileWriter és a PrintWriter osztályok használata valamelyest egyszerűsíti a kiírást, ráadásul a lehetőségeket is javítja:
import java.io.*; class FileInputExample { public static void main(String[] args) throws IOException { FileWriter fileWriter = new FileWriter("test.txt"); PrintWriter printWriter = new PrintWriter(fileWriter); printWriter.println("Hello world"); printWriter.printf("This is a text: %s, and this is an integer: %d.", "apple", 5); printWriter.close(); } }
A Files osztály használata fájlműveletekre
import java.io.*; import java.nio.file.*; class FileInputExample { public static void main(String[] args) throws IOException { Path path = Paths.get("test.txt"); Files.write(path, "Hello".getBytes()); System.out.println(Files.readAllLines(path)); } }
Ennek is vannak nehézségei (a Path szükségessége ahelyett, hogy elég lenne megadni a fájlnevet; Stringet nem tudunk kiírni, csak bájtokat), viszont az eredmény kompakt, ugyanaz az osztály használható kiírásra és beolvasásra is, ráadásul a Files számos egyéb fájlműveletet definiál: fájl és könyvtár létrehozása, létezésnek ellenőrzése, másolás, törlés stb.
Olvasás a resources könyvtárból
Az src/main/resources/ könyvtár belekerül a végeredmény jar fájlba. Onnan az alábbi módon tudunk olvasni:
import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.List; public class MyResourceReader { public static void main(String[] args) { MyResourceReader myResourceReader = new MyResourceReader(); myResourceReader.readFileFormResourcees(); } public void readFileFormResourcees() { try { ClassLoader classLoader = getClass().getClassLoader(); URL resource = classLoader.getResource("mydata.txt"); File file = new File(resource.toURI()); List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8); lines.forEach(System.out::println); } catch (URISyntaxException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
Egyéb fájlműveletek
Ennyi bántást követően lássunk egy olyan megoldást, ami mintaként kellene hogy funkcionáljon minden programozó számára! A Files mellett az eredeti File osztály is definiál alap fájl műveleteket, ráadásul - véleményem szerint - jóval egyszerűbben és természetesebben. Lássunk erre is egy példát!
import java.io.*; class FileInputExample { public static void main(String[] args) { File file = new File("mydata.txt"); System.out.println(file.exists()); file.delete(); System.out.println(file.exists()); } }
Kell magyarázni, hogy mit hajt végre ez a kód? Szerintem nem! Néhány példa a File által nyújtott műveletekre, magyarázat nélkül, ugyanis mindegyik pont azt hajtja végre, amire a neve alapján számítunk: canRead(), canWrite(), createNewFile(), delete(), exists(), getName(), getAbsolutePath, length(), list() (ez a könyvtárat listázza ki, eredménye String[]), mkdir().
A Java fájlkezelési lehetőségeknek csak egy részét érintettük, de ez elég ahhoz, hogy a legfontosabb feladatokat végre tudjuk hajtani.