I/O-Grundlagen |
|
| import java.io.*; | Die mit ...Stream endenden Klassen lesen und schreiben Binärdaten und die mit ...Reader/...Writer endenden Textzeichen. |
|
BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) ); String s = in.readLine(); |
Texteingabe von Tastatur. |
|
try( BufferedReader in = new BufferedReader( new InputStreamReader( new FileInputStream("MyFile.txt"), "UTF-8")) ) { String line; while((line = in.readLine()) != null) { // ... } } |
Text lesen aus Datei. Beim InputStreamReader möglichst immer das Encoding angeben (im Beispiel "UTF-8"). |
|
try( BufferedWriter out = new BufferedWriter( new OutputStreamWriter( new FileOutputStream("MyFile.txt"), "UTF-8")) ) { // s = ... out.write( s ); out.newLine(); } |
Text schreiben in Datei. 'FileOutputStream( "MyFile.txt", true )' hängt an bestehende Datei an (append). Beim OutputStreamWriter möglichst immer das Encoding angeben (im Beispiel "UTF-8"). |
|
try( ObjectInputStream in = new ObjectInputStream( new FileInputStream( "MyObjs.dat" ) ) ) { MyClass myObj = (MyClass) in.readObject(); } |
Objekt lesen aus Datei. |
|
try( ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream( "MyObjs.dat" ) ) ) { out.writeObject( myObj ); out.flush(); } |
Objekt schreiben in Datei. |
|
byte[] buffer = { 72, 65, 76, 76, 79 }; byte[] result = new ByteArrayInputStream( buffer ).readAllBytes(); System.out.println( Arrays.toString( result ) ); |
InputStream.readAllBytes() gibt es ab Java 9. |
|
byte[] buffer = { 72, 65, 76, 76, 79 }; new ByteArrayInputStream( buffer ).transferTo( System.out ); |
InputStream.transferTo() gibt es ab Java 9. |
|
ZipInputStream, ZipOutputStream, GZIPInputStream, GZIPOutputStream |
Komprimieren/Dekomprimieren. |
|
class MyClass implements Serializable { String s; // stored transient int i; // transient: not stored } |
Serialisierung (Speicherung) eines Objekts ermöglichen. |
|
Runtime.getRuntime().exec( "C:\\Windows\\Calc.exe" ); |
Kommando in getrenntem Betriebssystem-Prozess starten. |
|
Falls Sie einen OutputStream in einen InputStream wandeln müssen, hilft vielleicht folgendes Code-Snippet:
PipedInputStream in = new PipedInputStream();
PipedOUtputStream out = new PipedOutputStream( in );
new Thread(
new Runnable() {
public void run() {
// class1 muss eine beliebige putDataOnOutputStream()-Methode implementieren:
class1.putDataOnOutputStream( out );
}
}
).start();
// class2 muss eine beliebige processDataFromInputStream()-Methode implementieren:
class2.processDataFromInputStream( in );
|
|
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.*;
public class FileCopy
{
public static void main( String[] args ) throws IOException
{
if( 2 != args.length )
System.out.println( "Error: Parameter missing:\n java FileCopy InputFile OutputFile\n" );
else
copy( args[0], args[1], false, false );
}
// Seit Java JDK 7 bevorzugte Methode
public static void copySinceJava17( File fin, File fout, boolean append ) throws IOException
{
if( append ) {
try( OutputStream out = Files.newOutputStream( fout.toPath(), StandardOpenOption.CREATE, StandardOpenOption.APPEND ) ) {
Files.copy( fin.toPath(), out );
}
} else {
Files.copy( fin.toPath(), fout.toPath(), StandardCopyOption.REPLACE_EXISTING );
}
}
// Seit Java JDK 1.4 bevorzugte Methode
public static void copySinceJava14( File fin, File fout, boolean append ) throws IOException
{
FileChannel inChannel = new FileInputStream( fin ).getChannel();
FileChannel outChannel = new FileOutputStream( fout, append ).getChannel();
try {
inChannel.transferTo( 0, inChannel.size(), outChannel );
} finally {
if( inChannel != null ) try { inChannel.close(); } catch( IOException ex ) {/*ok*/}
if( outChannel != null ) try { outChannel.close(); } catch( IOException ex ) {/*ok*/}
}
}
// Bis Java JDK 1.3 zu verwendende Methode
public static void copyUptoJava13( File fin, File fout, boolean append ) throws IOException
{
int len = 32768;
byte[] buff = new byte[(int) Math.min( len, fin.length() )];
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream( fin );
fos = new FileOutputStream( fout, append );
while( 0 < (len = fis.read( buff )) )
fos.write( buff, 0, len );
} finally {
try { if( fos != null ) fos.close(); } catch( IOException ex ) {/*ok*/}
try { if( fis != null ) fis.close(); } catch( IOException ex ) {/*ok*/}
}
}
// Zusaetzliche Fehlerueberpruefungen
public static void copy( String fromFileName, String toFileName,
boolean overwriteIfExists, boolean append ) throws IOException
{
File fromFile = new File( fromFileName );
File toFile = new File( toFileName );
if( !fromFile.exists() )
throw new IOException( "Fehler: Quelldatei fehlt: " + fromFileName );
if( !fromFile.isFile() )
throw new IOException( "Fehler: Quelle ist ein Verzeichnis: " + fromFileName );
if( !fromFile.canRead() )
throw new IOException( "Fehler: Keine Leseberechtigung fuer Quelldatei: " + fromFileName );
if( toFile.isDirectory() )
toFile = new File( toFile, fromFile.getName() );
if( toFile.exists() ) {
if( !overwriteIfExists && !append )
throw new IOException( "Fehler: Zieldatei existiert bereits: " + toFileName );
if( !toFile.canWrite() )
throw new IOException( "Fehler: Keine Schreibberechtigung fuer Zieldatei: " + toFileName );
} else {
String parent = toFile.getParent();
if( parent == null )
parent = System.getProperty( "user.dir" );
File dir = new File( parent );
if( !dir.exists() )
throw new IOException( "Fehler: Zielverzeichnis existiert nicht: " + parent );
if( dir.isFile() )
throw new IOException( "Fehler: Ziel ist kein Verzeichnis: " + parent );
if( !dir.canWrite() )
throw new IOException( "Fehler: Keine Schreibberechtigung fuer Zielverzeichnis: " + parent );
}
copySinceJava17( fromFile, toFile, append );
}
}
Konventionelle Variante mit File.listFiles():
import java.io.File;
public class GetFilesInDir1
{
public static void main( String[] args )
{
System.out.println( "\nZeige rekursiv alle Dateien in einem Verzeichnis und den Unterverzeichnissen.\n" +
"Das Startverzeichnis wird als Kommandozeilenparameter uebergeben.\n" );
String startDir = ".";
if( args != null && args.length > 0 ) {
startDir = args[0];
}
System.out.println( getFilesInDirToString( startDir, null, null, null ) );
}
public static String getFilesInDirToString( String dir, String spacesStart, String spacesAdd, String lineSeparator )
{
if( lineSeparator == null ) { lineSeparator = System.getProperty( "line.separator" ); }
if( spacesStart == null ) { spacesStart = ""; }
if( spacesAdd == null ) { spacesAdd = " "; }
if( dir == null || dir.trim().length() == 0 ) {
return lineSeparator + "Fehler: Verzeichnis muss uebergeben werden." + lineSeparator;
}
File[] entries = (new File( dir )).listFiles();
if( entries == null ) {
return lineSeparator + "Fehler: '" + dir + "' ist kein Verzeichnis." + lineSeparator;
}
if( entries.length == 0 ) {
return spacesStart + "'" + dir + "' enthaelt keine Dateien oder Verzeichnisse." + lineSeparator;
}
StringBuilder sb = new StringBuilder( "" );
for( int i = 0; i < entries.length; i++ ) {
if( entries[i].isFile() ) {
sb.append( spacesStart ).append( entries[i] ).append( lineSeparator );
}
}
for( int i = 0; i < entries.length; i++ ) {
if( entries[i].isDirectory() ) {
sb.append( lineSeparator )
.append( spacesStart ).append( "Verzeichnis " ).append( entries[i].toString() ).append( lineSeparator )
.append( getFilesInDirToString( entries[i].toString(), spacesStart + spacesAdd, spacesAdd, lineSeparator ) );
}
}
return sb.toString();
}
}
NIO-Variante mit Files.walkFileTree():
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class GetFilesInDir2
{
public static void main( String[] args ) throws IOException
{
System.out.println( "\nZeige rekursiv alle Dateien in einem Verzeichnis und den Unterverzeichnissen.\n" +
"Das Startverzeichnis wird als Kommandozeilenparameter uebergeben.\n" );
String startDir = ".";
if( args != null && args.length > 0 ) {
startDir = args[0];
}
getFilesInDir( startDir );
}
public static void getFilesInDir( String startDir ) throws IOException {
Files.walkFileTree( Paths.get( startDir ), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile( Path path, BasicFileAttributes bfa ) {
System.out.println( path + " (Dateigroesse: " + bfa.size() + " Bytes)" );
return FileVisitResult.CONTINUE;
}
});
}
}
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
public class DateiSuche
{
public static void main( String[] args ) throws IOException
{
System.out.println( "\nSuche rekursiv nach Dateien, welche einem Dateinamens-Pattern entsprechen.\n" +
"Zusaetzlich kann optional ein Unterverzeichnis angegeben werden, das ausgeschlossen werden soll.\n" +
"Kommandozeilenparameter: DateinamensPattern StartVerzeichnis AuschlussVerzeichnis.\nBeispiele:\n" +
" * .\n" +
" *.prop* /MeinStartDir MeinExcludeDir\n" +
" *.{txt,java,class} . target\n" );
String pattern = ( args.length > 0 ) ? args[0] : "*";
String startDir = ( args.length > 1 ) ? args[1] : ".";
String excludeDir = ( args.length > 2 ) ? args[2] : null;
System.out.println( sucheDateien( pattern, startDir, excludeDir ) );
}
public static List<Path> sucheDateien( String pattern, String startDir, String excludeDir ) throws IOException
{
List<Path> result = new ArrayList<>();
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher( "glob:" + pattern );
Files.walkFileTree( Paths.get( startDir ), new SimpleFileVisitor<Path>() {
boolean excludeDirFound;
@Override
public FileVisitResult visitFile( Path path, BasicFileAttributes bfa ) {
excludeDirFound = false;
if( excludeDir != null && excludeDir.length() > 0 ) {
path.getParent().spliterator().forEachRemaining( subpath -> {
if( excludeDir.equals( subpath.toString() ) ) {
excludeDirFound |= true;
}
} );
}
if( !excludeDirFound && pathMatcher.matches( path.getFileName() ) ) {
result.add( path );
}
return FileVisitResult.CONTINUE;
}
} );
return result;
}
}
Alternativ (mit eingeschränkter Funktionalität):
/** Liste Dateien auf, gefiltert per Dateiname mit Joker */
private static List<Path> listFilesWithJoker( String dir, String filenameWithJoker )
{
List<Path> paths = new ArrayList<>();
try( DirectoryStream<Path> dirStream = Files.newDirectoryStream( Paths.get( dir ), filenameWithJoker ) ) {
dirStream.forEach( paths::add );
} catch( IOException ex ) {
LOGGER.error( "Fehler bei der Suche nach " + dir + "/" + filenameWithJoker + "-Dateien. ", ex );
}
return paths;
}
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
public class TextSucheInDateien
{
public static void main( String[] args ) throws IOException
{
System.out.println( "\nSuche nach einem Suchtext rekursiv in Dateien, welche einem Dateinamens-Pattern entsprechen.\n" +
"Zusaetzlich kann optional ein Unterverzeichnis angegeben werden, das ausgeschlossen werden soll.\n" +
"Kommandozeilenparameter: Suchtext DateinamensPattern StartVerzeichnis AuschlussVerzeichnis.\nBeispiele:\n" +
" MeinSuchText * .\n" +
" MeinSuchText *.prop* /MeinStartDir MeinExcludeDir\n" +
" walkFileTree *.{xml,java} . target\n" );
String suchtext = ( args.length > 0 ) ? args[0] : "walkFileTree";
String pattern = ( args.length > 1 ) ? args[1] : "*";
String startDir = ( args.length > 2 ) ? args[2] : ".";
String excludeDir = ( args.length > 3 ) ? args[3] : null;
List<Path> pathes = sucheDateien( pattern, startDir, excludeDir );
List<List<String>> result = sucheTextInDateien( suchtext, pathes );
for( List<String> ss : result ) {
System.out.println( ss.get( 0 ) + ": " + ss.get( 1 ) );
}
}
public static List<Path> sucheDateien( String pattern, String startDir, String excludeDir ) throws IOException
{
List<Path> result = new ArrayList<>();
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher( "glob:" + pattern );
Files.walkFileTree( Paths.get( startDir ), new SimpleFileVisitor<Path>() {
boolean excludeDirFound;
@Override
public FileVisitResult visitFile( Path path, BasicFileAttributes bfa ) {
excludeDirFound = false;
if( excludeDir != null && excludeDir.length() > 0 ) {
path.getParent().spliterator().forEachRemaining( subpath -> {
if( excludeDir.equals( subpath.toString() ) ) {
excludeDirFound |= true;
}
} );
}
if( !excludeDirFound && pathMatcher.matches( path.getFileName() ) ) {
result.add( path );
}
return FileVisitResult.CONTINUE;
}
} );
return result;
}
public static List<List<String>> sucheTextInDateien( String suchtext, List<Path> pathes ) throws IOException
{
List<List<String>> result = new ArrayList<>();
String suchtextLowercase = suchtext.toLowerCase();
for( Path p : pathes ) {
Files.lines( p, StandardCharsets.UTF_8 ).forEach( line -> {
if( line.toLowerCase().contains( suchtextLowercase ) ) {
result.add( Arrays.asList( p.toString(), line ) );
}
});
}
return result;
}
}
import java.io.*;
import java.net.*;
import java.nio.file.Files;
/**
* Resource --> URL --> URI --> Path im Dateisystem
* (insbesondere wenn der Ressource-Pfad Leerzeichen enthaelt)
*/
public class RessourcePfadMitLeerzeichen
{
public static void main( String[] args ) throws IOException, URISyntaxException
{
// Ressource-Datei im Ressource-Verzeichnis (z.B. in: "src/main/resources/Leerzeichen im Ressource-Pfad"):
String ressourceDateiPfad = "Leerzeichen im Ressource-Pfad/Dateiname mit Leerzeichen.txt";
// URL zu Ressource-Datei (enthaelt "%20" statt Leerzeichen):
URL ressourceUrl = RessourcePfadMitLeerzeichen.class.getResource( ressourceDateiPfad );
if( ressourceUrl == null ) {
ressourceDateiPfad = "/" + ressourceDateiPfad;
ressourceUrl = RessourcePfadMitLeerzeichen.class.getResource( ressourceDateiPfad );
}
if( ressourceUrl == null ) {
throw new FileNotFoundException( "Ressource '" + ressourceDateiPfad + "' fehlt" );
}
// URL --> URI (enthaelt auch "%20" statt Leerzeichen):
URI ressourceUri = ressourceUrl.toURI();
// URL-Decoded und URI-Path (enthalten Leerzeichen statt "%20"):
String urlDecoded = URLDecoder.decode( ressourceUrl.toString(), StandardCharsets.UTF_8.toString() );
String uriPath = ressourceUrl.toURI().getPath();
// Ergebnisse:
System.out.println( "" );
System.out.println( "Ressource-Dateipfad: " + ressourceDateiPfad );
System.out.println( "Ressource-URL: " + ressourceUrl );
System.out.println( "Ressource-URI: " + ressourceUri );
System.out.println( "URL-Decoded: " + urlDecoded );
System.out.println( "URI-Path: " + uriPath );
// ResourceAsStream funktioniert sowohl im Dateisystem als auch in Jar:
System.out.print( "Dateiinhalt per ResourceAsStream: " );
try( InputStream is = RessourcePfadMitLeerzeichen.class.getResourceAsStream( ressourceDateiPfad ) ) {
try( BufferedReader rd = new BufferedReader( new InputStreamReader( is, StandardCharsets.UTF_8 ) ) ) {
System.out.println( rd.readLine() );
}
}
// URI-Path funktioniert im Dateisystem, aber nicht in Jar:
System.out.print( "Dateiinhalt aus Datei im Dateisystem: " );
if( uriPath == null ) {
System.out.println( "-- nicht moeglich: URI-Path ist null --" );
} else {
Files.lines( new File( uriPath ).toPath(), StandardCharsets.UTF_8 ).forEach( System.out::println );
}
}
}
Wenn Sie eine entsprechende Ressource-Datei in dem angegebenen Ressource-Verzeichnis anlegen, und das Java-Programm direkt ausführen, erhalten Sie beispielsweise:
Ressource-Dateipfad: /Leerzeichen im Ressource-Pfad/Dateiname mit Leerzeichen.txt Ressource-URL: file:/D:/MeinWorkspace/Ressource-Pfad%20mit%20Leerzeichen/target/classes/Leerzeichen%20im%20Ressource-Pfad/Dateiname%20mit%20Leerzeichen.txt Ressource-URI: file:/D:/MeinWorkspace/Ressource-Pfad%20mit%20Leerzeichen/target/classes/Leerzeichen%20im%20Ressource-Pfad/Dateiname%20mit%20Leerzeichen.txt URL-Decoded: file:/D:/MeinWorkspace/Ressource-Pfad mit Leerzeichen/target/classes/Leerzeichen im Ressource-Pfad/Dateiname mit Leerzeichen.txt URI-Path: /D:/MeinWorkspace/Ressource-Pfad mit Leerzeichen/target/classes/Leerzeichen im Ressource-Pfad/Dateiname mit Leerzeichen.txt Dateiinhalt per ResourceAsStream: Dateiinhalt in UTF-8 mit Leerzeichen und äöü߀ Dateiinhalt aus Datei im Dateisystem: Dateiinhalt in UTF-8 mit Leerzeichen und äöü߀
Wenn Sie stattdessen die kompilierte Java-Klasse zusammen mit der Ressource-Datei in eine Jar-Datei verpacken, und dann diese Jar-Datei ausführen, erhalten Sie beispielsweise:
Ressource-Dateipfad: /Leerzeichen im Ressource-Pfad/Dateiname mit Leerzeichen.txt Ressource-URL: jar:file:/D:/MeinWorkspace/Ressource-Pfad%20mit%20Leerzeichen/target/RessourcePfadMitLeerzeichen.jar!/Leerzeichen%20im%20Ressource-Pfad/Dateiname%20mit%20Leerzeichen.txt Ressource-URI: jar:file:/D:/MeinWorkspace/Ressource-Pfad%20mit%20Leerzeichen/target/RessourcePfadMitLeerzeichen.jar!/Leerzeichen%20im%20Ressource-Pfad/Dateiname%20mit%20Leerzeichen.txt URL-Decoded: jar:file:/D:/MeinWorkspace/Ressource-Pfad mit Leerzeichen/target/RessourcePfadMitLeerzeichen.jar!/Leerzeichen im Ressource-Pfad/Dateiname mit Leerzeichen.txt URI-Path: null Dateiinhalt per ResourceAsStream: Dateiinhalt in UTF-8 mit Leerzeichen und äöü߀ Dateiinhalt aus Datei im Dateisystem: -- nicht moeglich: URI-Path ist null --
import java.io.*;
import java.nio.charset.*;
import java.util.*;
import java.util.zip.*;
/**
* Hilfsklasse zum Zippen und Unzippen.
*/
public class ZipUtil
{
/**
* Interface fuer Unzip-Callback-Objekt zur Verarbeitung einzelner ZipEntries zu OutputStreams.
*/
public interface UnzippedEntryInOutputStream
{
OutputStream verarbeiteUnzippedEntry( String name ) throws IOException;
}
/**
* Interface fuer Unzip-Callback-Objekt zur Verarbeitung einzelner ZipEntries aus Entry-InputStreams.
*/
public interface UnzippedEntryFromInputStream
{
void verarbeiteUnzippedEntry( String name, InputStream instreamForUnzipped ) throws IOException;
}
/**
* Zip: Einen InputStream in einen OutputStream zippen.<br>
* Beide Streams werden mit close() geschlossen.
* @param instreamForZip InputStream, der gezipped werden soll.
* @param outstreamZipped OutputStream, gezipped.
* @param origFilename Originaldateiname (wird in der Zipdatei gespeichert mit UTF-8-Character-Encoding).
*/
public static void zipStream( InputStream instreamForZip, OutputStream outstreamZipped, String origFilename ) throws IOException
{
zipStream( instreamForZip, outstreamZipped, origFilename, StandardCharsets.UTF_8 );
}
/**
* Zip: Einen InputStream in einen OutputStream zippen.<br>
* Beide Streams werden mit close() geschlossen.
* @param instreamForZip InputStream, der gezipped werden soll.
* @param outstreamZipped OutputStream, gezipped.
* @param origFilename Originaldateiname (wird in der Zipdatei gespeichert).
* @param zipCharEncoding Charset fuer Character-Encoding des Zip-Entry-Namens, normalerweise StandardCharsets.UTF_8
*/
public static void zipStream( InputStream instreamForZip, OutputStream outstreamZipped, String origFilename, Charset zipCharEncoding ) throws IOException
{
IOException ex = null;
try {
byte[] buf = new byte[65536];
int len;
try( ZipOutputStream zout = new ZipOutputStream( new BufferedOutputStream( outstreamZipped ), zipCharEncoding ) ) {
zout.putNextEntry( new ZipEntry( origFilename ) );
while( (len = instreamForZip.read( buf )) > 0 ) {
zout.write( buf, 0, len );
}
try { zout.closeEntry(); } catch( IOException e ) { ex = e; }
try { zout.finish(); } catch( IOException e ) { if( ex == null ) { ex = e; } }
try { zout.flush(); } catch( IOException e ) { if( ex == null ) { ex = e; } }
}
} finally {
try { instreamForZip.close(); } catch( IOException e ) { if( ex == null ) { ex = e; } }
}
if( ex != null ) { throw ex; }
}
/**
* Unzip: Einen gezippten InputStream in einen InputStream entzippen.<br>
* Die Streams werden mit close() geschlossen.
* @param instreamZipped InputStream der gezippten Datei
* @param verarbeitung Callback-Objekt zur Verarbeitung einzelner ZipEntries aus Entry-InputStreams
* @return Anzahl Entries
*/
public static long unzipStream( InputStream instreamZipped, UnzippedEntryFromInputStream verarbeitung ) throws IOException
{
return unzipStream( instreamZipped, verarbeitung, StandardCharsets.UTF_8 );
}
/**
* Unzip: Einen gezippten InputStream in einen InputStream entzippen.<br>
* Die Streams werden mit close() geschlossen.
* @param instreamZipped InputStream der gezippten Datei
* @param verarbeitung Callback-Objekt zur Verarbeitung einzelner ZipEntries aus Entry-InputStreams
* @param zipCharEncoding Charset fuer Character-Encoding des Zip-Entry-Namens, normalerweise StandardCharsets.UTF_8
* @return Anzahl Entries
*/
public static long unzipStream( InputStream instreamZipped, UnzippedEntryFromInputStream verarbeitung, Charset zipCharEncoding ) throws IOException
{
long anzahlEntries = 0;
try( BufferedInputStream in = new BufferedInputStream( instreamZipped );
ZipInputStream zin = new ZipInputStream( in, zipCharEncoding ) {
@Override public void close() throws IOException {
// Do nothing:
// Das Ueberschreiben von close() ist notwendig, um "java.io.IOException: Stream closed" zu vermeiden,
// falls in verarbeitung.verarbeiteUnzippedEntry() XML geparst wird,
// wegen eines Fehlers im JAXP-XMLStreamReader, siehe http://bugs.sun.com/view_bug.do?bug_id=6539065
}
} ) {
ZipEntry zipEntry;
while( (zipEntry = zin.getNextEntry()) != null ) {
verarbeitung.verarbeiteUnzippedEntry( zipEntry.getName(), zin );
zin.closeEntry();
anzahlEntries++;
}
}
return anzahlEntries;
}
/**
* Unzip: Einen gezippten InputStream in einen OutputStream entzippen.<br>
* Die Streams werden mit close() geschlossen.
* @param instreamZipped InputStream der gezippten Datei
* @param verarbeitung Callback-Objekt zur Verarbeitung einzelner ZipEntries zu OutputStreams
* @return Anzahl Entries
*/
public static long unzipStream( InputStream instreamZipped, UnzippedEntryInOutputStream verarbeitung ) throws IOException
{
return unzipStream( instreamZipped, verarbeitung, StandardCharsets.UTF_8 );
}
/**
* Unzip: Einen gezippten InputStream in einen OutputStream entzippen.<br>
* Die Streams werden mit close() geschlossen.
* @param instreamZipped InputStream der gezippten Datei
* @param verarbeitung Callback-Objekt zur Verarbeitung einzelner ZipEntries zu OutputStreams
* @param zipCharEncoding Charset fuer Character-Encoding des Zip-Entry-Namens, normalerweise StandardCharsets.UTF_8
* @return Anzahl Entries
*/
public static long unzipStream( InputStream instreamZipped, UnzippedEntryInOutputStream verarbeitung, Charset zipCharEncoding ) throws IOException
{
long anzahlEntries = 0;
try( ZipInputStream zin = new ZipInputStream( new BufferedInputStream( instreamZipped ), zipCharEncoding ) ) {
IOException ex = null;
ZipEntry zipEntry;
while( ex == null && (zipEntry = zin.getNextEntry()) != null ) {
OutputStream os = verarbeitung.verarbeiteUnzippedEntry( zipEntry.getName() );
if( os != null ) {
try( BufferedOutputStream bos = new BufferedOutputStream( os ) ) {
int size;
byte[] buffer = new byte[64 * 1024];
while( (size = zin.read( buffer, 0, buffer.length )) > 0 ) {
bos.write( buffer, 0, size );
}
try { bos.flush(); } catch( IOException e ) { ex = e; }
}
anzahlEntries++;
}
zin.closeEntry();
}
if( ex != null ) { throw ex; }
}
return anzahlEntries;
}
/**
* Aus einem gezippten InputStream den Namen des ersten Eintrags ermitteln.<br>
* Der InputStream wird mit close() geschlossen.
* @param instreamZipped InputStream der gezippten Datei
* @return Name des ersten Entries (gespeichert im UTF-8-Character-Encoding).
*/
public static String getNameOfFirstEntry( InputStream instreamZipped ) throws IOException
{
return getNameOfFirstEntry( instreamZipped, StandardCharsets.UTF_8 );
}
/**
* Aus einem gezippten InputStream den Namen des ersten Eintrags ermitteln.<br>
* Der InputStream wird mit close() geschlossen.
* @param instreamZipped InputStream der gezippten Datei
* @param zipCharEncoding Charset fuer Character-Encoding des Zip-Entry-Namens, normalerweise StandardCharsets.UTF_8
* @return Name des ersten Entries.
*/
public static String getNameOfFirstEntry( InputStream instreamZipped, Charset zipCharEncoding ) throws IOException
{
String entryName = null;
try( ZipInputStream zin = new ZipInputStream( new BufferedInputStream( instreamZipped ), zipCharEncoding ) ) {
ZipEntry zipEntry = zin.getNextEntry();
if( zipEntry != null ) {
entryName = zipEntry.getName();
}
} finally {
instreamZipped.close();
}
return entryName;
}
/**
* Unzip-Callback-Klasse zur Speicherung einzelner ZipEntries in Dateien.
*/
public static class UnzippedEntryToFile implements UnzippedEntryInOutputStream
{
public String filenamePrefix = "unzipped.";
public final List<String> filenames = new ArrayList<String>();
@Override
public OutputStream verarbeiteUnzippedEntry( String entryName ) throws IOException
{
if( entryName == null ) { return null; }
String filename = entryName;
if( filename.startsWith( "/" ) ) { filename = filename.substring( 1 ); }
if( this.filenamePrefix != null ) { filename = this.filenamePrefix + filename; }
this.filenames.add( filename );
if( filename.endsWith( "/" ) || filename.endsWith( "\\" ) ) {
(new File( filename )).mkdirs();
return null;
}
return new FileOutputStream( filename );
}
}
/**
* Unzip-Callback-Klasse zur Speicherung einzelner ZipEntries in Strings (mit vorgegebener maximaler Laenge).
*/
public static class UnzippedEntryToString implements UnzippedEntryFromInputStream
{
public int lenMax = 2048;
public String fileCharEncoding = "UTF-8";
public final List<String> strings = new ArrayList<String>();
public UnzippedEntryToString( String fileCharEncoding )
{
this.fileCharEncoding = fileCharEncoding;
}
@Override
public void verarbeiteUnzippedEntry( String entryName, InputStream unzippedEntryInstream ) throws IOException
{
byte[] buffer = new byte[this.lenMax];
int len = unzippedEntryInstream.read( buffer );
this.strings.add( new String( buffer, 0, len, this.fileCharEncoding ) );
}
}
/**
* Nur fuer manuellen Unzip-Test
*/
public static void main( String[] args ) throws IOException
{
if( args.length > 0 ) {
UnzippedEntryToFile callback = new UnzippedEntryToFile();
callback.filenamePrefix = null;
try( InputStream is = new FileInputStream( args[0] ) ) {
System.out.println( "Anzahl Entries: " + unzipStream( is, callback, StandardCharsets.UTF_8 ) );
System.out.println( "Entry-Namen: " + callback.filenames );
}
}
}
}
import java.io.*;
import java.nio.charset.*;
import org.junit.*;
/**
* JUnit-Test fuer ZipUtil
*/
public class ZipUtilTest
{
@Test
public void testZipUtil() throws IOException
{
testZipUtil( StandardCharsets.UTF_8, StandardCharsets.UTF_8 );
testZipUtil( StandardCharsets.UTF_8, StandardCharsets.ISO_8859_1 );
testZipUtil( StandardCharsets.ISO_8859_1, StandardCharsets.UTF_8 );
testZipUtil( StandardCharsets.ISO_8859_1, StandardCharsets.ISO_8859_1 );
}
public void testZipUtil( Charset fileCharEncoding, Charset zipCharEncoding ) throws IOException
{
String targetPath = "target/";
String origFilename = "MeineDatei-äöüß.txt";
String zipFilename = origFilename + ".zip";
String unzippedFilenamePrefix = "unzipped.";
String meinText = "BlaBlupp äöüß\u20AC";
String meinTextCmp = ( StandardCharsets.UTF_8.equals( fileCharEncoding ) ) ? meinText : meinText.replace( '\u20AC', '?' );
int zipResultSize = 168;
if( StandardCharsets.UTF_8.equals( fileCharEncoding ) ) { zipResultSize += 7; }
if( StandardCharsets.UTF_8.equals( zipCharEncoding ) ) { zipResultSize += 8; }
// Zip mit ByteArray:
try( InputStream isForZip = new ByteArrayInputStream( meinText.getBytes( fileCharEncoding ) );
ByteArrayOutputStream bosZipped = new ByteArrayOutputStream() ) {
ZipUtil.zipStream( isForZip, bosZipped, origFilename, zipCharEncoding );
Assert.assertEquals( zipResultSize, bosZipped.size() );
}
// Zip mit Datei:
(new File( targetPath )).mkdir();
try( BufferedWriter out = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(
targetPath + origFilename ), fileCharEncoding ) ) ) {
out.write( meinText );
}
try( InputStream isForZip = new FileInputStream( targetPath + origFilename );
OutputStream fosZipped = new FileOutputStream( targetPath + zipFilename )) {
ZipUtil.zipStream( isForZip, fosZipped, origFilename, zipCharEncoding );
File zipFile = new File( targetPath + zipFilename );
Assert.assertTrue( zipFile.exists() );
Assert.assertEquals( zipResultSize, zipFile.length() );
}
// Unzip aus InputStream zu String:
ZipUtil.UnzippedEntryToString entryToString = new ZipUtil.UnzippedEntryToString( fileCharEncoding.name() );
try( InputStream is = new FileInputStream( targetPath + zipFilename ) ) {
long anzahlEntries = ZipUtil.unzipStream( is, entryToString, zipCharEncoding );
Assert.assertEquals( 1, anzahlEntries );
Assert.assertEquals( 1, entryToString.strings.size() );
Assert.assertEquals( meinTextCmp, entryToString.strings.get( 0 ) );
}
// Unzip in OutputStream in Datei:
ZipUtil.UnzippedEntryToFile entryToFile = new ZipUtil.UnzippedEntryToFile();
entryToFile.filenamePrefix = targetPath + unzippedFilenamePrefix;
try( InputStream is = new FileInputStream( targetPath + zipFilename ) ) {
long anzahlEntries = ZipUtil.unzipStream( is, entryToFile, zipCharEncoding );
Assert.assertEquals( 1, anzahlEntries );
Assert.assertEquals( 1, entryToFile.filenames.size() );
Assert.assertEquals( targetPath + unzippedFilenamePrefix + origFilename, entryToFile.filenames.get( 0 ) );
}
try( BufferedReader in = new BufferedReader( new InputStreamReader( new FileInputStream(
targetPath + unzippedFilenamePrefix + origFilename ), fileCharEncoding ) ) ) {
Assert.assertEquals( meinTextCmp, in.readLine() );
}
}
}
Mit JUnit 4.10 führen Sie aus:
javac -cp .;junit-4.10.jar *.java
java -cp .;junit-4.10.jar org.junit.runner.JUnitCore ZipUtilTest
Für JUnit 4.12 downloaden Sie junit-4.12.jar und hamcrest-core-1.3.jar und führen aus:
javac -cp .;junit-4.12.jar *.java
java -cp .;junit-4.12.jar;hamcrest-core-1.3.jar org.junit.runner.JUnitCore ZipUtilTest
Falls Sie beim Unzippen folgende Fehlermeldung erhalten:
java.lang.IllegalArgumentException: MALFORMED
at java.util.zip.ZipCoder.toString
Dann haben Sie wahrscheinlich ein Character-Encoding-Problem beim Aufruf von ZipInputStream.getNextEntry() wegen Umlauten und Sonderzeichen im Zip-Entry-Namen. Erweitern Sie den new ZipInputStream()-Aufruf um den passenden Character-Encoding-Charset, z.B.:
ZipInputStream zin = new ZipInputStream( meinInputStream, StandardCharsets.ISO_8859_1 );
bzw.:
ZipInputStream zin = new ZipInputStream( meinInputStream, StandardCharsets.UTF_8 );
Analoges gilt natürlich ebenso für ZipOutputStream.
Folgendermaßen kann die Prozess-ID unter Windows und Linux ermittelt werden:
import java.io.IOException;
import java.io.InputStream;
/** PID-Ermittlung (= Prozess-ID) mit Java 8 und Java 9, unter Windows und Linux */
public class GetPID
{
public static void main( String[] args ) throws IOException, InterruptedException
{
System.out.println( getPidJava8() );
System.out.println( getPidJava9() );
}
/** PID-Ermittlung mit Java 8 */
static long getPidJava8() throws IOException, InterruptedException
{
String os = System.getenv( "OS" );
if( os == null ) { os = "Linux"; }
System.out.println( "\n" + os );
// Linux ($PPID = Parent Process ID):
final String[] commandsLinux = new String[] { "/bin/sh", "-c", "echo $PPID" };
// Windows:
final String[] commandsWindows = new String[] { "powershell",
"gwmi win32_process | ?{$_.ProcessID -eq $pid} | select ParentProcessID | fw -c 2" };
final String[] commands = ( os != null && os.toLowerCase().contains( "windows" ) )
? commandsWindows : commandsLinux;
final Process proc = Runtime.getRuntime().exec( commands );
if( proc.waitFor() == 0 ) {
try( final InputStream in = proc.getInputStream() ) {
final int available = in.available();
final byte[] outputBytes = new byte[available];
in.read( outputBytes );
final String pid = new String( outputBytes );
return Long.parseLong( pid.trim() );
}
}
throw new IllegalStateException( "PID kann nicht ermittelt werden" );
}
/** PID-Ermittlung mit Java 9 */
static long getPidJava9()
{
return ProcessHandle.current().pid();
}
}
Folgendermaßen kann der Webbrowser gestartet werden und darin Text mit besonderen Unicode-Zeichen angezeigt werden:
import java.awt.Desktop;
import java.io.*;
/** Start des Webbrowsers und darin Anzeige besonderer Unicode-Zeichen */
public class DesktopBrowser
{
public static void main( String[] args ) throws IOException
{
String textKonsole = "\nText mit besonderen Unicode-Zeichen: \u25D0" +
toSurrogates( 0x1f605 ) + toSurrogates( 0x1f310 ) + toSurrogates( 0x1f575 ) + toSurrogates( 0x1F917 );
String textHtml = "<html><body><h1>Text mit besonderen Unicode-Zeichen: " +
"◐ 😅 🌐 🕵 🤗" + "</h1></body></html>";
System.out.println( textKonsole );
zeigeImBrowser( erstelleTemporaereDatei( textHtml, "Unicode-Webseite-", ".html" ) );
}
private static String toSurrogates( int codePoint )
{
return new String( new char[] { Character.highSurrogate( codePoint ), Character.lowSurrogate( codePoint ) } );
}
private static File erstelleTemporaereDatei( String text, String dateinamePrefix, String dateinameSuffix ) throws IOException
{
File tmpFile = File.createTempFile( dateinamePrefix, dateinameSuffix );
try( FileOutputStream fos = new FileOutputStream( tmpFile );
BufferedOutputStream bos = new BufferedOutputStream( fos ) ) {
bos.write( text.getBytes() );
bos.flush();
}
return tmpFile;
}
private static void zeigeImBrowser( File htmlFile ) throws IOException
{
if( Desktop.isDesktopSupported() ) {
Desktop desktop = Desktop.getDesktop();
if( desktop != null && desktop.isSupported( Desktop.Action.BROWSE ) ) {
desktop.browse( htmlFile.toURI() );
}
}
}
}
Ab Java 7 gibt es weitere File-I/O-Klassen und -Methoden, die vieles vereinfachen,
siehe bei
OpenJDK oder
java.nio.file,
zum Beispiel:
FileSystems.getDefault(),
FileSystem,
Path.getFileSystem(),
Path,
Paths,
Files,
Files.deleteIfExists(),
Files.copy(),
Files.move(),
Files.newDirectoryStream(),
DirectoryStream,
Files.walkFileTree(),
FileVisitor,
BasicFileAttributes,
FileAttribute,
WatchService,
Path.register(),
AsynchronousFileChannel.
Beachten Sie, dass es die Klasse FileSystem ab Java 7 doppelt gibt: als abstrakte (normalerweise nicht sichtbare) java.io.FileSystem und als java.nio.file.FileSystem.
In Java 8 sind viele weitere neue File-I/O-Klassen und -Methoden im Streaming-API hinzugekommen, siehe: Java 8 Stream-API.