Wie kann eine Datei kopiert werden?
Im Folgenden werden vier Beispiele gezeigt, die jeweils
in einer statischen Methode gekapselt sind. Der
jeweilige Methodenaufruf kann direkt in main()
erfolgen, sodass die ausführende Klasse wie folgt
aussehen kann.
public class DateiKopierenBsp { private static final String IN_PATH = "/<pfadZu>/<datei>"; private static final String OUT_PATH = "/<pfadZu>/<kopierteDatei>"; public static void main(String[] args) { // hier Methodenaufruf } //... }
Kopieren innerhalb des lokalen Dateibaums
Sollen beliebige Dateitypen innerhalb des lokalen
Dateibaums von einem Ort zum anderen kopiert werden, so
kann dies mittels der Klasse FileChannel
erfolgen.
public static boolean copyFileFromExtToExtByChannel() { File in = new File(IN_PATH); File out = new File(OUT_PATH); try (FileInputStream fis = new FileInputStream(in); FileOutputStream fos = new FileOutputStream(out); FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel();) { inChannel.transferTo(0, inChannel.size(), outChannel); } catch (IOException e) { return false; } return true; }
Hierzu müssen die beiden Dateien als File
-Objekte
vorliegen. Sie werden im Beispiel anhand des jeweiligen
Pfades erzeugt und an die Konstruktoren von FileInputStream
bzw. FileOutputStream
übergeben. Von
beiden werden FileChannel
-Objekte gebildet.
Sowohl die Streams, als auch die Channel müssen
nach ihrer Nutzung wieder geschlossen werden. Um dies zu
automatisieren, werden deren Deklarationen in ein Try-with-Resources-Statement
eingeschlossen [4].
Die Klasse FileChannel
kennt die Methode transferTo()
, die auf dem
Eingabe-Channel aufgerufen wird. Ihr werden drei
Parameter übergeben, zwei long
-Werte
und der Ausgabe-Channel. Der erste long
-Wert
bezeichnet den Startpunkt des Dateitransfers innerhalb
der Datei (bei einer Kopie natürlich das erste
byte), der zweite die Länge des Transfers in bytes.
Die
Methode kann auch verwendet werden, um Dateien aus dem
Classpath heraus zu exportieren. Hierzu muss der
Eingabepfad, etwa innerhalb eines Eclipse-Projektes,
dann in der Form
src<package><dateiname> // ohne führenden '/'!
angegeben werden. Vorsicht ist jedoch geboten, wenn das Projekt als *.jar gepackt werden soll. Der Export aus dem Archiv heraus ist zur Laufzeit auf diese Weise nicht möglich.
Ohne den Komfort eines FileChannel
, der
weitere Funktionen wie Locking, partielles Kopieren,
etc. bereitstellt, kann ein solcher Transfer auch byte
für byte direkt durch die Streams erfolgen. Hierbei
wird der Dateiinhalt, unter Auslassung der Channel, in
einem byte-Array zwischengespeichert und dann innerhalb
einer Schleife durch den OutputStream
in
eine neuen Datei wieder eingelesen.
public static boolean copyFileFromExtToExt() { try (FileInputStream fis = new FileInputStream(IN_PATH); FileOutputStream fos = new FileOutputStream(OUT_PATH);) { byte[] buf = new byte[1024]; int i = 0; while ((i = fis.read(buf)) != -1) { fos.write(buf, 0, i); } } catch (IOException e) { return false; } return true; }
Laut eigenen, nicht allgemeingültigen Messungen ist
der Transfer durch FileChannel
ca. 4-5 mal
schneller.
Kopieren aus dem ClassPath in den lokalen Dateibaum
Ersetzt man den FileInputStream
durch einen
InputStream
, so kann man sich dieses
Verfahren zunutze machen, um Dateien zur Laufzeit aus
dem *.jar-Archiv der Applikation heraus in den lokalen
Dateibaum zu kopieren. Die Ursache liegt darin, dass
Java in *.jar-Archiven gespeicherte Dateien nicht als
solche behandelt.
public static boolean copyBinaryFileFromClassPathToExt() { try (InputStream is = DateiKopierenBsp.class.getResourceAsStream(IN_PATH); FileOutputStream fos = new FileOutputStream(OUT_PATH);) { byte[] buf = new byte[1024]; int i = 0; while((i=is.read(buf))!=-1) { fos.write(buf, 0, i); } } catch (IOException e) { return false; } return true; }
Desweiteren sollten die Daten dabei durch getResourceAsStream()
geladen werden. Die Methode ist in der Klasse Class
definiert, sodass zunächst das Class
-Objekt
der ladenden Klasse ermittelt werden muss. Wie hier, in
statischen Umgebungen, muss dies durch die Eigenschaft class
,
bei Objekten duch getClass()
erfolgen.
Bei textbasierten Dateien kann die Kopie auch mit Hilfe
eines ByteArrayOutputStream
und eines PrintWriter
erfolgen. Das Einlesen der Daten bleibt dabei
unverändert. Dafür kann man sich die Vorteile
des ByteArrayOutputStream
zunutze machen
und das gewünschte Character-Set festlegen [9].
public static boolean copyTextFileFromClassPathToExt() { try (InputStream is = DateiKopierenBsp.class.getResourceAsStream(IN_PATH); PrintWriter pWriter = new PrintWriter(new FileWriter(OUT_PATH));) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; for (int length; (length = is.read(buffer)) != -1;) { bos.write(buffer, 0, length); } String s = bos.toString("UTF-8"); pWriter.println(s); } catch (IOException e) { return false; } return true; }
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.