package de.axone.file; import java.io.File; import java.io.FileInputStream; import java.io.IOError; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import de.axone.data.Charsets; /** * Slurps data from inputs until all data is read. * * Will return byte arrays or ByteBuffers of exactly the size of the * available data. * * Don't use on unlimited sources (like /dev/random, /dev/null) because * it will create OutOfMemory errors. * * This methods don't close the source. So encapsulate in try/finallyin * and do it manually by yourself. * * TODO: Die Sache mit den Buffern lässt sich bestimmt weiter optimieren * und kürzen. * Und das Naminb vereinheitlichen. * * @author flo */ public class Slurper { private static final int DEFAULT_STARTSIZE = 4096, DEFAULT_EXTENDSIZE = 4096, DEFAULT_COPY_BUFFER = 4096; //private static final byte [] EMPTY_ARRAY = new byte[]{}; private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); private static final Charset DEFAULT_CHARSET = Charsets.UTF8; public static String slurpString( File in ) throws IOException { return slurpString( in, DEFAULT_CHARSET ); } public static String slurpString( File in, Charset charset ) throws IOException { try( FileInputStream fin = new FileInputStream( in ) ){ return slurpString( fin, charset ); } } public static String slurpString( Path in ) throws IOException { try( InputStream fin = Files.newInputStream( in ) ){ return slurpString( fin ); } } public static String slurpString( InputStream in ) throws IOException { return slurpString( in, DEFAULT_CHARSET ); } public static String slurpString( InputStream in, int startsize ) throws IOException { return slurpString( in, DEFAULT_CHARSET, startsize ); } public static String slurpString( InputStream in, int startsize, int extendsize ) throws IOException { return slurpString( in, DEFAULT_CHARSET, startsize, extendsize ); } public static String slurpString( InputStream in, Charset charsetName ) throws IOException { return new String( slurp( in ), charsetName ); } public static String slurpString( InputStream in, Charset charsetName, int startsize ) throws IOException { return new String( slurp( in, startsize ), charsetName ); } public static String slurpString( InputStream in, Charset charsetName, int startsize, int extendsize ) throws IOException { return new String( slurp( in, startsize, extendsize ), charsetName ); } /* public static ByteBuffer slurpInBuffer( File in ) throws IOException { try( FileChannel fch = FileChannel.open( in.toPath(), StandardOpenOption.READ ) ){ return slurp( fch ); } } */ public static byte[] slurp( File in ) throws IOException { try( FileInputStream fin = new FileInputStream( in ) ){ return slurp( fin ); } } public static byte[] slurp( Path in ) throws IOException { try( InputStream fin = Files.newInputStream( in ) ){ return slurp( fin ); } } public static byte[] slurp( InputStream in ) throws IOException { return slurp( in, DEFAULT_STARTSIZE, DEFAULT_EXTENDSIZE ); } public static byte[] slurp( InputStream in, int startsize ) throws IOException { return slurp( in, startsize, DEFAULT_EXTENDSIZE ); } public static byte[] slurp( InputStream in, int startsize, int extendsize ) throws IOException { ByteBuffer result = slurp( Channels.newChannel( in ), startsize, extendsize ); if( result.hasArray() ){ return result.array(); } else { byte [] r = new byte[ result.remaining() ]; result.get( r ); return r; } } public static ByteBuffer slurp( ReadableByteChannel in ) throws IOException{ return slurp( in, DEFAULT_STARTSIZE, DEFAULT_EXTENDSIZE ); } public static ByteBuffer slurp( ReadableByteChannel in, int startsize ) throws IOException{ return slurp( in, startsize, DEFAULT_EXTENDSIZE ); } public static ByteBuffer slurp( ReadableByteChannel in, int startsize, int extendsize ) throws IOException{ if( startsize <= 0 ) startsize = DEFAULT_STARTSIZE; if( extendsize <= 1 ) extendsize = DEFAULT_EXTENDSIZE; ByteBuffer buffer = ByteBuffer.allocateDirect( startsize ); int count = in.read( buffer ); if( count >= 0 ){ ByteBuffer bb = ByteBuffer.allocate( 1 ); int b = in.read( bb ); // there is more in the buffer; if( b >= 0 ){ // store one char if( b == 1 ){ bb.flip(); buffer = addToBuffer( buffer, bb, extendsize+1 ); } ByteBuffer readBuffer = ByteBuffer.allocateDirect( extendsize ); while( in.read( readBuffer ) >= 0 ){ readBuffer.flip(); buffer = addToBuffer( buffer, readBuffer, extendsize ); readBuffer.clear(); } } return trim( buffer ); } else { return EMPTY_BUFFER; } } /** * Add 'add' to 'buffer' * * @param buffer where to add at position * @param add where to add from position to limit * @param extendsize * @return */ private static ByteBuffer addToBuffer( ByteBuffer buffer, ByteBuffer add, int extendsize ){ int pos = buffer.position(); int bLen = buffer.limit(); int remaining = bLen-pos; int len = add.remaining(); if( len > remaining ){ int missing = len-remaining; missing = missing > extendsize ? missing : extendsize; ByteBuffer newBuffer = ByteBuffer.allocateDirect( bLen+missing ); buffer.flip(); newBuffer.put( buffer ); buffer = newBuffer; } buffer.put( add ); return buffer; } private static ByteBuffer trim( ByteBuffer buffer ){ if( buffer.capacity() != buffer.position() ){ ByteBuffer result = ByteBuffer.allocateDirect( buffer.position() ); buffer.flip(); result.put( buffer ); buffer = result; } buffer.rewind(); return buffer; } public static void copy( OutputStream outS, InputStream inS ) throws IOException{ try( WritableByteChannel dst = Channels.newChannel( outS ); ReadableByteChannel src = Channels.newChannel( inS ); ){ ByteBuffer buffer = ByteBuffer.allocateDirect( DEFAULT_COPY_BUFFER ); while( ( src.read( buffer ) ) > -1 ){ buffer.flip(); dst.write( buffer ); buffer.compact(); } buffer.flip(); while( buffer.hasRemaining() ){ dst.write( buffer ); } } } public static void burp( OutputStream outS, byte [] data ) throws IOException { outS.write( data, 0, data.length ); outS.flush(); } public static void burp( File outS, ByteBuffer buffer ) throws IOException { burp( outS.toPath(), buffer ); } public static void burp( Path outS, ByteBuffer buffer ) throws IOException { try( WritableByteChannel ch = FileChannel.open( outS, StandardOpenOption.WRITE ) ){ ch.write( buffer ); } } public static void burp( Path outS, String value ) throws IOException { byte [] bytes = value.getBytes( "utf-8" ); ByteBuffer buffer = ByteBuffer.wrap( bytes ); burp( outS, buffer ); } public static void print( File file ){ try { System.out.println( slurpString( file ) ); } catch( IOException e ){ throw new IOError( e ); } } }