manifold.rt.api.util.StreamUtil Maven / Gradle / Ivy
/*
* Copyright (c) 2020 - Manifold Systems LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package manifold.rt.api.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.Flushable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;
import java.util.function.Predicate;
public class StreamUtil
{
// Using a relatively large block size to reduce the number of (very slow)
// native calls into the file system
private static final int BLOCK_SIZE = 8192;
private StreamUtil()
{
/* disable construction */
}
/**
* Converts the specified character sequence to bytes using UTF-8.
*
* @param seq the character sequence to convert
*
* @return the UTF-8 encoded result
*/
public static byte[] toBytes( CharSequence seq )
{
try
{
return seq.toString().getBytes( "UTF-8" );
}
catch( UnsupportedEncodingException ex )
{
throw new RuntimeException( ex ); // shouldn't happen since UTF-8 is supported by all JVMs per spec
}
}
/**
* Converts the specified byte array to a String using UTF-8.
*
* @param bytes the bytes to convert
*
* @return the resulting string
*/
public static String toString( byte[] bytes )
{
try
{
return new String( bytes, "UTF-8" );
}
catch( UnsupportedEncodingException ex )
{
throw new RuntimeException( ex ); // shouldn't happen since UTF-8 is supported by all JVMs per spec
}
}
/**
* Converts the specified byte array to a String using UTF-8.
*
* @param bytes the bytes to convert
* @param offset the index of the first byte to decode
* @param length the number of bytes to decode
*
* @return the resulting string
*/
public static String toString( byte[] bytes, int offset, int length )
{
try
{
return new String( bytes, offset, length, "UTF-8" );
}
catch( UnsupportedEncodingException ex )
{
throw new RuntimeException( ex ); // shouldn't happen since UTF-8 is supported by all JVMs per spec
}
}
/**
* Converts the specified property file text to a Properties object.
*
* @param propFileText the property file text in standard property file format
*
* @return the resulting Properties object
*
* @throws CharacterCodingException if invalid encoding
*/
public static Properties toProperties( String propFileText ) throws CharacterCodingException
{
CharsetEncoder encoder = Charset.forName( "ISO-8859-1" ).newEncoder().onUnmappableCharacter( CodingErrorAction.REPORT );
byte[] bytes = encoder.encode( CharBuffer.wrap( propFileText ) ).array();
Properties props = new Properties();
try
{
props.load( new ByteArrayInputStream( bytes ) );
}
catch( IOException ex )
{
throw new RuntimeException( ex ); // shouldn't happen with BAIS
}
return props;
}
/**
* Returns a reader for the specified input stream, using UTF-8 encoding.
*
* @param in the input stream to wrap
*
* @return a reader for this input stream
*/
public static Reader getInputStreamReader( InputStream in )
{
return getInputStreamReader( in, "UTF-8" );
}
/**
* Returns a reader for the specified input stream, using specified encoding.
*
* @param in the input stream to wrap
* @param charset the input stream to wrap
*
* @return a reader for this input stream
*/
public static Reader getInputStreamReader( InputStream in, String charset )
{
try
{
return new InputStreamReader( in, charset );
}
catch( UnsupportedEncodingException ex )
{
throw new RuntimeException( ex ); // shouldn't happen since UTF-8 is supported by all JVMs per spec
}
}
/**
* Returns a writer for the specified output stream, using UTF-8 encoding.
*
* @param out the output stream to wrap
*
* @return a writer for this output stream
*/
public static Writer getOutputStreamWriter( OutputStream out )
{
try
{
return new OutputStreamWriter( out, "UTF-8" );
}
catch( UnsupportedEncodingException ex )
{
throw new RuntimeException( ex ); // shouldn't happen since UTF-8 is supported by all JVMs per spec
}
}
/**
* Returns an input stream for the specified character sequence, using UTF-8 encoding.
*
* @param cs the character sequence to wrap
*
* @return an input stream for reading the specified character sequence
*/
public static InputStream getStringInputStream( CharSequence cs )
{
return new ByteArrayInputStream( toBytes( cs ) );
}
/**
* Returns the content of the specified input stream. The stream will be closed after calling this method.
*
* @param in the input stream to read
*
* @return the content of the input stream
*
* @throws IOException if an I/O error occurs
*/
public static byte[] getContent( InputStream in ) throws IOException
{
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy( in, baos );
return baos.toByteArray();
}
finally
{
in.close();
}
}
/**
* Returns the content of the specified reader. The reader will be closed after calling this method.
*
* @param in the reader to read
*
* @return the content of the reader
*
* @throws IOException if an I/O error occurs
*/
public static String getContent( Reader in ) throws IOException
{
try
{
StringWriter sw = new StringWriter();
copy( in, sw );
return sw.toString();
}
finally
{
in.close();
}
}
/**
* Copies the content of an input stream to an output stream.
*
* @param in the input stream to read
* @param out the output stream to write
*
* @throws IOException if an I/O error occurs
*/
public static void copy( InputStream in, OutputStream out ) throws IOException
{
// if( in instanceof FileInputStream && out instanceof FileOutputStream )
// {
// copy( (FileInputStream)in, (FileOutputStream)out );
// }
// else
// {
byte[] buf = new byte[BLOCK_SIZE];
while( true )
{
int count = in.read( buf );
if( count < 0 )
{
break;
}
out.write( buf, 0, count );
}
out.flush();
// }
}
/**
* Copies the content of an input stream to a writer.
*
* @param in the input stream to read
* @param writer the writer to write
*
* @throws IOException if an I/O error occurs
*/
public static void copy( InputStream in, Writer writer ) throws IOException
{
copy( getInputStreamReader( in ), writer );
writer.flush();
}
/**
* Copies the content of a reader to an output stream.
*
* @param reader the reader to read
* @param out the output stream to write
*
* @throws IOException if an I/O error occurs
*/
public static void copy( Reader reader, OutputStream out ) throws IOException
{
copy( reader, getOutputStreamWriter( out ) );
out.flush();
}
/**
* Copies the content of a reader to a writer.
*
* @param in the reader to read
* @param out the writer to write
*
* @throws IOException if an I/O error occurs
*/
public static void copy( Reader in, Writer out ) throws IOException
{
char[] buf = new char[BLOCK_SIZE];
while( true )
{
int count = in.read( buf );
if( count < 0 )
{
break;
}
out.write( buf, 0, count );
}
out.flush();
}
/**
* Recursively copy a file or directory to a directory.
*/
public static void copy( File fileOrDirectory, File toDir )
{
copy( fileOrDirectory, toDir, null );
}
public static void copy( File fileOrDirectory, File toDir, Predicate filter )
{
if( filter == null || filter.test( fileOrDirectory ) )
{
File copy = new File( toDir, fileOrDirectory.getName() );
if( fileOrDirectory.isDirectory() )
{
//noinspection ResultOfMethodCallIgnored
copy.mkdir();
for( File child : fileOrDirectory.listFiles() )
{
copy( child, copy, filter );
}
}
else
{
//noinspection ResultOfMethodCallIgnored
try (InputStream is = new FileInputStream( fileOrDirectory );
OutputStream os = new FileOutputStream( copy ))
{
StreamUtil.copy( is, os );
}
catch( Exception e )
{
throw new RuntimeException( e );
}
}
}
}
/**
* Recursively copy a file or directory to a directory.
*/
public static void copy( Path fileOrDirectory, Path toDir )
{
Path copy = PathUtil.create( toDir, PathUtil.getName( fileOrDirectory ) );
if( PathUtil.isDirectory( fileOrDirectory ) )
{
//noinspection ResultOfMethodCallIgnored
try
{
PathUtil.mkdir( copy );
Files.list( fileOrDirectory ).forEach( child -> copy( child, copy ) );
}
catch( IOException e )
{
throw new RuntimeException( e );
}
}
else
{
//noinspection ResultOfMethodCallIgnored
try (InputStream is = Files.newInputStream( fileOrDirectory );
OutputStream os = Files.newOutputStream( copy ))
{
StreamUtil.copy( is, os );
}
catch( Exception e )
{
throw new RuntimeException( e );
}
}
}
/**
* Close and swallow exception the exception. For use in finally blocks
* where the other io exceptions is what is wanted to be thrown.
*
* @param stream the streams to close
*/
public static void closeNoThrow( Closeable stream )
{
if( stream != null )
{
try
{
stream.close();
}
catch( IOException ignore )
{
}
}
}
/**
* Closes the specified streams, suppressing any IOExceptions for inputstreams and readers.
* Even if an I/O exception is thrown, all streams can be considered closed.
*
* @param streams the streams to close
*
* @throws IOException if an i/o exception occurs while closing any outputstream or writer
*/
public static void close( Closeable... streams ) throws IOException
{
close( streams, 0 );
}
private static void close( Closeable[] streams, int idx ) throws IOException
{
if( idx >= streams.length )
{
return; // done
}
Closeable stream = streams[idx];
try
{
if( stream != null )
{
if( stream instanceof Flushable )
{
((Flushable)stream).flush();
}
stream.close();
}
}
catch( IOException ex )
{
if( !(stream instanceof InputStream || stream instanceof Reader) )
{
throw ex; // ignore io exceptions for input streams and readers
}
}
finally
{
close( streams, idx + 1 );
}
}
// /**
// * Recursively copy a file or directory to a directory.
// */
// public static void copy( File fileOrDirectory, File toDir )
// {
// copy( fileOrDirectory, toDir, null );
// }
// /**
// * Recursively copy a file or directory to a directory.
// */
// public static void copy( File fileOrDirectory, File toDir, Predicate filter )
// {
// copy( fileOrDirectory.toPath(), toDir.toPath(), filter );
// }
//
// /**
// * Recursively copy a file or directory to a directory.
// */
// public static void copy( Path fileOrDirectory, Path toDir )
// {
// copy( fileOrDirectory, toDir, null );
// }
// /**
// * Recursively copy a file or directory to a directory.
// */
// public static void copy( Path fileOrDirectory, Path toDir, Predicate filter )
// {
// try
// {
// Files.walkFileTree( fileOrDirectory,
// EnumSet.of( FileVisitOption.FOLLOW_LINKS ), Integer.MAX_VALUE,
// new CopyFileVisitor( toDir, filter ) );
// }
// catch( IOException ioe )
// {
// throw new RuntimeException( ioe );
// }
// }
//
// private static class CopyFileVisitor extends SimpleFileVisitor
// {
// private Path _from;
// private Path _to;
// private Predicate _filter;
//
// CopyFileVisitor( Path to, Predicate filter )
// {
// _to = to;
// _filter = filter;
// }
//
// @Override
// public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs ) throws IOException
// {
// if( _filter != null && !_filter.test( dir ) )
// {
// return FileVisitResult.SKIP_SUBTREE;
// }
//
// if( _from == null )
// {
// _from = dir;
// }
// else
// {
// Files.createDirectories( _to.resolve( _from.relativize( dir ) ) );
// }
// return FileVisitResult.CONTINUE;
// }
//
// @Override
// public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) throws IOException
// {
// if( _filter == null || _filter.test( file ) )
// {
// Files.copy( file, _to.resolve( _from.relativize( file ) ) );
// }
// return FileVisitResult.CONTINUE;
// }
// }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy