Java/File Input Output/Stream
Содержание
- 1 An InputStream class that terminates the stream when it encounters a particular byte sequence.
- 2 An InputStream that implements HTTP/1.1 chunking
- 3 An OutputStream which relays all data written into it into a list of given OutputStreams
- 4 Count OutputStream
- 5 Count the number of bytes read through the stream
- 6 File utilities for file read and write
- 7 General IO Stream manipulation
- 8 General IO stream manipulation utilities
- 9 Show the content of a file
- 10 Some general utility functions for dealing with Streams
- 11 Utilities related to file and stream handling.
- 12 Utility code for dealing with different endian systems
- 13 Utility functions related to Streams
- 14 Utility methods for handling streams
- 15 Various utility methods that have something to do with I/O
An InputStream class that terminates the stream when it encounters a particular byte sequence.
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you 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. *
****************************************************************/
import java.io.IOException;
import java.io.InputStream;
/**
* An InputStream class that terminates the stream when it encounters a
* particular byte sequence.
*
* @version 1.0.0, 24/04/1999
*/
public class CharTerminatedInputStream
extends InputStream {
/**
* The wrapped input stream
*/
private InputStream in;
/**
* The terminating character array
*/
private int match[];
/**
* An array containing the last N characters read from the stream, where
* N is the length of the terminating character array
*/
private int buffer[];
/**
* The number of bytes that have been read that have not been placed
* in the internal buffer.
*/
private int pos = 0;
/**
* Whether the terminating sequence has been read from the stream
*/
private boolean endFound = false;
/**
* A constructor for this object that takes a stream to be wrapped
* and a terminating character sequence.
*
* @param in the <code>InputStream</code> to be wrapped
* @param terminator the array of characters that will terminate the stream.
*
* @throws IllegalArgumentException if the terminator array is null or empty
*/
public CharTerminatedInputStream(InputStream in, char[] terminator) {
if (terminator == null) {
throw new IllegalArgumentException("The terminating character array cannot be null.");
}
if (terminator.length == 0) {
throw new IllegalArgumentException("The terminating character array cannot be of zero length.");
}
match = new int[terminator.length];
buffer = new int[terminator.length];
for (int i = 0; i < terminator.length; i++) {
match[i] = (int)terminator[i];
buffer[i] = (int)terminator[i];
}
this.in = in;
}
/**
* Read a byte off this stream.
*
* @return the byte read off the stream
* @throws IOException if an IOException is encountered while reading off the stream
* @throws ProtocolException if the underlying stream returns -1 before the terminator is seen.
*/
public int read() throws IOException {
if (endFound) {
//We"ve found the match to the terminator
return -1;
}
if (pos == 0) {
//We have no data... read in a record
int b = in.read();
if (b == -1) {
//End of stream reached without seeing the terminator
throw new java.net.ProtocolException("pre-mature end of data");
}
if (b != match[0]) {
//this char is not the first char of the match
return b;
}
//this is a match...put this in the first byte of the buffer,
// and fall through to matching logic
buffer[0] = b;
pos++;
} else {
if (buffer[0] != match[0]) {
//Maybe from a previous scan, there is existing data,
// and the first available char does not match the
// beginning of the terminating string.
return topChar();
}
//we have a match... fall through to matching logic.
}
//MATCHING LOGIC
//The first character is a match... scan for complete match,
// reading extra chars as needed, until complete match is found
for (int i = 0; i < match.length; i++) {
if (i >= pos) {
int b = in.read();
if (b == -1) {
//end of stream found, so match cannot be fulfilled.
// note we don"t set endFound, because otherwise
// remaining part of buffer won"t be returned.
return topChar();
}
//put the read char in the buffer
buffer[pos] = b;
pos++;
}
if (buffer[i] != match[i]) {
//we did not find a match... return the top char
return topChar();
}
}
//A complete match was made...
endFound = true;
return -1;
}
/**
* Private helper method to update the internal buffer of last read characters
*
* @return the byte that was previously at the front of the internal buffer
*/
private int topChar() {
int b = buffer[0];
if (pos > 1) {
//copy down the buffer to keep the fresh data at top
System.arraycopy(buffer, 1, buffer, 0, pos - 1);
}
pos--;
return b;
}
}
An InputStream that implements HTTP/1.1 chunking
package net.matuschek.util;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
// ChunkedInputStream - an InputStream that implements HTTP/1.1 chunking
//
// Copyright (C) 1996,1998 by Jef Poskanzer <jef@acme.ru>. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.ru/java/
/**
* Modifications done by Daniel Matuschek (daniel@matuschek.net)
* - modified JavaDoc documentation
* - adapted to Java 1.2, removed deprecated DataInputStream.readLine() method
* - replaced DataInputStream by InputStream (there was no need for a
* DatainputStream, not idea why this was used in the original version)
* - fixed a bug (there is an CRLF after every the data block)
*/
/**
* An InputStream that implements HTTP/1.1 chunking.
* <P>
* This class lets a Servlet read its request data as an HTTP/1.1 chunked
* stream. Chunked streams are a way to send arbitrary-length data without
* having to know beforehand how much you"re going to send. They are
* introduced by a "Transfer-Encoding: chunked" header, so if such a header
* appears in an HTTP request you should use this class to read any data.
* <P>
* Sample usage:
* <BLOCKQUOTE><PRE><CODE>
* InputStream in = req.getInputStream();
* if ( "chunked".equals( req.getHeader( "Transfer-Encoding" ) ) )
* in = new ChunkedInputStream( in );
* </CODE></PRE></BLOCKQUOTE>
* <P>
* Because it would be impolite to make the authors of every Servlet include
* the above code, this is general done at the server level so that it
* happens automatically. Servlet authors will generally not create
* ChunkedInputStreams. This is in contrast with ChunkedOutputStream,
* which Servlets have to call themselves if they want to use it.
* <P>
*
*
* @author Jef Poskanzer
* @author Daniel Matuschek
* @version $Id: ChunkedInputStream.java,v 1.6 2002/05/31 14:45:56 matuschd Exp $
*/
public class ChunkedInputStream extends FilterInputStream
{
private int contentLength;
private byte[] b1 = new byte[1];
/** number of bytes available in the current chunk */
private int chunkCount = 0;
private Vector<String> footerNames = null;
private Vector<String> footerValues = null;
/**
* Make a ChunkedInputStream.
*/
public ChunkedInputStream( InputStream in )
{
super(in);
contentLength = 0;
}
/**
* The FilterInputStream implementation of the single-byte read()
* method just reads directly from the underlying stream. We want
* to go through our own read-block method, so we have to override.
* Seems like FilterInputStream really ought to do this itself.
*/
public int read() throws IOException
{
if (read(b1,0,1) == -1 ) {
return -1;
}
return b1[0];
}
/**
* Reads into an array of bytes.
* @param b the buffer into which the data is read
* @param off the start offset of the data
* @param len the maximum number of bytes read
* @return the actual number of bytes read, or -1 on EOF
* @exception IOException if an I/O error has occurred
*/
public int read( byte[] b, int off, int len ) throws IOException
{
if (chunkCount == 0) {
startChunk();
if (chunkCount == 0) {
return -1;
}
}
int toRead = Math.min( chunkCount, len );
int r = in.read( b, off, toRead );
if ( r != -1 ) {
chunkCount -= r;
}
return r;
}
/**
* Reads the start of a chunk.
*/
private void startChunk() throws IOException
{
String line = readLine();
if (line.equals("")) {
line=readLine();
}
try {
chunkCount = Integer.parseInt(line.trim(),16);
} catch (NumberFormatException e) {
throw new IOException("malformed chunk ("+line+")");
}
contentLength += chunkCount;
if ( chunkCount == 0 ) {
readFooters();
}
}
/**
* Reads any footers.
*/
private void readFooters() throws IOException
{
footerNames = new Vector<String>();
footerValues = new Vector<String>();
String line;
while ( true ) {
line = readLine();
if ( line.length() == 0 )
break;
int colon = line.indexOf( ":" );
if ( colon != -1 )
{
String name = line.substring( 0, colon ).toLowerCase();
String value = line.substring( colon + 1 ).trim();
footerNames.addElement( name.toLowerCase() );
footerValues.addElement( value );
}
}
}
/**
* Returns the value of a footer field, or null if not known.
* Footers come at the end of a chunked stream, so trying to
* retrieve them before the stream has given an EOF will return
* only nulls.
* @param name the footer field name
*/
public String getFooter( String name )
{
if ( ! isDone() )
return null;
int i = footerNames.indexOf( name.toLowerCase() );
if ( i == -1 )
return null;
return (String) footerValues.elementAt( i );
}
/**
* Returns an Enumeration of the footer names.
*/
public Enumeration getFooters()
{
if ( ! isDone() )
return null;
return footerNames.elements();
}
/**
* Returns the size of the request entity data, or -1 if not known.
*/
public int getContentLength()
{
if (! isDone()) {
return -1;
}
return contentLength;
}
/**
* Tells whether the stream has gotten to its end yet. Remembering
* whether you"ve gotten an EOF works fine too, but this is a convenient
* predicate. java.io.InputStream should probably have its own isEof()
* predicate.
*/
public boolean isDone()
{
return footerNames != null;
}
/**
* ChunkedInputStream used DataInputStream.readLine() before. This method
* is deprecated, therefore we will it replace by our own method.
* Because the chunk lines only use 7bit ASCII, we can use the
* system default encoding
* The data lines itself will not be read using this readLine method
* but by a block read
*/
protected String readLine()
throws IOException
{
final byte CR=13;
final byte LF=10;
ByteBuffer buff = new ByteBuffer();
byte b=0;
int i=0;
do {
b = (byte)this.in.read();
if (b != LF) {
buff.append(b);
}
i++;
} while ((b != LF));
// according to the RFC there must be a CR before the LF, but some
// web servers don"t do this :-(
byte[] byteBuff = buff.getContent();
if (byteBuff.length == 0) {
return "";
}
if (byteBuff[byteBuff.length-1] != CR) {
return new String(byteBuff);
} else {
return new String(byteBuff,0,byteBuff.length-1);
}
}
}
/*********************************************
Copyright (c) 2001 by Daniel Matuschek
*********************************************/
/**
* A ByteBuffer implements a growable byte array. You can simple
* add bytes like you do it using a Vector, but internally the buffer
* is implemented as a real array of bytes. This increases memory usage.
*
* @author Daniel Matuschek
* @version $Id $
*/
class ByteBuffer {
protected final int INITIALSIZE=1024;
protected int used = 0;
protected int size = 0;
protected byte[] buff =null;
/**
* Initializes a new ByteBuffer object and creates
* a temporary buffer array of a predefined initial size.
* If you want to set your own initial size, use the <code>setSize</code>
* method after initializing the object.
*
*/
public ByteBuffer() {
size=INITIALSIZE;
buff=new byte[INITIALSIZE];
}
/**
* Appends a byte to the end of the buffer
*
* If the currently reserved memory is used, the size of the
* internal buffer will be doubled.
* In this case the memory usage will temprary increase by factor 3
* because it need a temporary storage for the old data.
*
* Be sure that you have enough heap memory !
*
* @param b byte to append
*/
public void append(byte b) {
if (used >= size) {
doubleBuffer();
}
buff[used]=b;
used++;
}
/**
* @return the number of bytes stored in the buffer
*/
public int length() {
return used;
}
/**
* @return the buffer contents as a byte array
*/
public byte[] getContent() {
byte[] b = new byte[used];
for (int i=0; i<used; i++) {
b[i]=buff[i];
}
return b;
}
/**
* removes all contents in the buffer
*/
public void clean() {
used=0;
}
/**
* Sets the size of the internal buffer to
* the given value. This is useful, if the size of the
* data that should be stored is known.
* @param size size of the buffer in Bytes
*/
public void setSize(int size) {
// if we have already used more data, ignore it !
if (size < used) {
return;
}
this.size=size;
// create a new (larger) array
byte[] newBuff = new byte[size];
// copy contents
for (int i=0; i<used; i++) {
newBuff[i]=buff[i];
}
buff=newBuff;
}
/**
* Print the buffer content as a String (use it for debugging only !)
* @return a String containing every byte in the buffer as a character
*/
public String toString() {
StringBuffer sb = new StringBuffer(buff.length);
for (int i=0; i<used; i++) {
sb.append(buff[i]);
}
return sb.toString();
}
/**
* doubles the size of the internal buffer
*/
protected void doubleBuffer() {
// increase size
setSize(size*2);
}
}
An OutputStream which relays all data written into it into a list of given OutputStreams
/**
* The utillib library.
* More information is available at http://www.jinchess.ru/.
* Copyright (C) 2002 Alexander Maryanovsky.
* All rights reserved.
*
* The utillib library is free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The utillib library is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with utillib library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.io.OutputStream;
import java.io.IOException;
/**
* An <code>OutputStream</code> which relays all data written into it into a
* list of given <code>OutputStreams</code>.
*/
public class MultiOutputStream extends OutputStream{
/**
* An array containing the OutputStreams we"re relaying data to.
*/
private final OutputStream [] streams;
/**
* Creates a new <code>MultiOutputStream</code> which relays data to the
* specified two <code>OutputStreams</code>. Any <code>null</code> values
* will be silently ignored.
*/
public MultiOutputStream(OutputStream out1, OutputStream out2){
this(new OutputStream[]{out1, out2});
}
/**
* Creates a new <code>MultiOutputStream</code> which relays data to the
* specified <code>OutputStreams</code>. Any <code>null</code> items in the
* array will be silently ignored.
*/
public MultiOutputStream(OutputStream [] streams){
if (streams == null)
throw new IllegalArgumentException("Specified array may not be null");
int count = 0;
for (int i = 0; i < streams.length; i++)
if (streams[i] != null)
count++;
this.streams = new OutputStream[count];
count = 0;
for (int i = 0; i < streams.length; i++){
OutputStream stream = streams[i];
if (stream != null)
this.streams[count++] = stream;
}
}
/**
* Closes all the underlying <code>OutputStreams</code>.
*/
public void close() throws IOException{
for (int i = 0; i < streams.length; i++)
streams[i].close();
}
/**
* Flushes all the underlying <code>OutputStreams</code>.
*/
public void flush() throws IOException{
for (int i = 0; i < streams.length; i++)
streams[i].flush();
}
/**
* Writes the specified <code>byte</code> into the underlying
* <code>OutputStreams</code>.
*/
public void write(int b) throws IOException{
for (int i = 0; i < streams.length; i++)
streams[i].write(b);
}
/**
* Writes the specified amount of bytes from the given byte array starting
* at the specified offset to the underlying <code>OutputStreams</code>.
*/
public void write(byte [] arr, int offset, int length) throws IOException{
for (int i = 0; i < streams.length; i++)
streams[i].write(arr, offset, length);
}
}
Count OutputStream
// CountOutputStream.java
// $Id: CountOutputStream.java,v 1.3 2000/08/16 21:37:57 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
import java.io.OutputStream;
/**
* This class can be used to count number of bytes emitted to a stream. The
* stream will actually throw the data away. It"s main function is to count the
* number of bytes emitted to a stream before actually emitting the bytes
* (that"s not really efficient, but works enough).
*/
public class CountOutputStream extends OutputStream {
protected int count = 0;
/**
* Get the current number of bytes emitted to that stream.
*
* @return The current count value.
*/
public int getCount() {
return count;
}
/**
* Close that count stream.
*/
public void close() {
return;
}
/**
* Flush that count stream.
*/
public void flush() {
return;
}
/**
* Write an array of bytes to that stream.
*/
public void write(byte b[]) {
count += b.length;
}
/**
* Write part of an array of bytes to that stream.
*/
public void write(byte b[], int off, int len) {
count += len;
}
/**
* Write a single byte to that stream.
*/
public void write(int b) {
count++;
}
/**
* Create a new instance of that class.
*/
public CountOutputStream() {
this.count = 0;
}
}
Count the number of bytes read through the stream
// CountInputStream.java
// $Id: CountInputStream.java,v 1.1 2001/04/11 19:03:06 ylafon Exp $
// (c) COPYRIGHT MIT, INRIA and Keio, 2001.
// Please first read the full copyright statement in file COPYRIGHT.html
import java.io.IOException;
import java.io.InputStream;
/**
* count the number of bytes read through the stream
*/
public class CountInputStream extends InputStream {
long count = 0;
long marked = -1;
InputStream is;
public int available() throws IOException {
return is.available();
}
public boolean markSupported() {
return is.markSupported();
}
public int read() throws IOException {
int r = is.read();
if (r > 0) {
count++;
}
return r;
}
public int read(byte[] b, int off, int len) throws IOException {
int r = is.read(b, off, len);
if (r > 0) {
count += r;
}
return r;
}
public long skip(long skipped) throws IOException {
long l = is.skip(skipped);
if (l > 0) {
count += l;
}
return l;
}
public void mark(int readlimit) {
is.mark(readlimit);
marked = count;
}
public void reset() throws IOException {
is.reset();
count = marked;
}
public void close() throws IOException {
is.close();
}
/**
* get the actual number of bytes read
*
* @return a long, the number of bytes read
*/
public long getBytesRead() {
return count;
}
public CountInputStream(InputStream is) {
this.is = is;
}
}
File utilities for file read and write
/*
Milyn - Copyright (C) 2006
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License (version 2.1) as published by the Free Software
Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details:
http://www.gnu.org/licenses/lgpl.txt
*/
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
/**
* File utilities.
* @author
*/
public abstract class FileUtils {
public static void copyFile(String from, String to) throws IOException {
File fromFile = new File(from);
File toFile = new File(to);
writeFile(readFile(fromFile), toFile);
}
/**
* Read the contents of the specified file.
* @param file The file to read.
* @return The file contents.
* @throws IOException Error readiong file.
*/
public static byte[] readFile(File file) throws IOException {
if(!file.exists()) {
throw new IllegalArgumentException("No such file "" + file.getAbsoluteFile() + "".");
} else if(file.isDirectory()) {
throw new IllegalArgumentException("File "" + file.getAbsoluteFile() + "" is a directory. Cannot read.");
}
InputStream stream = new FileInputStream(file);
try {
return StreamUtils.readStream(stream);
} finally {
stream.close();
}
}
public static void writeFile(byte[] bytes, File file) throws IOException {
if(file.isDirectory()) {
throw new IllegalArgumentException("File "" + file.getAbsoluteFile() + "" is an existing directory. Cannot write.");
}
FileOutputStream stream = new FileOutputStream(file);
try {
stream.write(bytes);
stream.flush();
} finally {
stream.close();
}
}
}
/*
Milyn - Copyright (C) 2006
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License (version 2.1) as published by the Free Software
Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details:
http://www.gnu.org/licenses/lgpl.txt
*/
/**
* Stream Utilities.
*
* @author tfennelly
*/
abstract class StreamUtils {
/**
* Read the supplied InputStream and return as a byte array.
*
* @param stream
* The stream to read.
* @return byte array containing the Stream data.
* @throws IOException
* Exception reading from the stream.
*/
public static byte[] readStream(InputStream stream) throws IOException {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
byte[] byteBuf = new byte[1024];
int readCount = 0;
while ((readCount = stream.read(byteBuf)) != -1) {
bytesOut.write(byteBuf, 0, readCount);
}
return bytesOut.toByteArray();
}
/**
* Read the supplied InputStream and return as a byte array.
*
* @param stream
* The stream to read.
* @return A String containing the Stream data.
* @throws IOException
* Exception reading from the stream.
*/
public static String readStreamAsString(InputStream stream) throws IOException {
return new String(readStream(stream));
}
public static byte[] readFile(File file) throws IOException {
InputStream stream = new FileInputStream(file);
try {
return readStream(stream);
} finally {
stream.close();
}
}
public static void writeFile(File file, byte[] data) throws IOException {
OutputStream stream = new FileOutputStream(file);
try {
stream.write(data);
} finally {
try {
stream.flush();
} finally {
stream.close();
}
}
}
public static String readStream(Reader stream) throws IOException {
StringBuffer streamString = new StringBuffer();
char[] readBuffer = new char[256];
int readCount = 0;
while ((readCount = stream.read(readBuffer)) != -1) {
streamString.append(readBuffer, 0, readCount);
}
return streamString.toString();
}
/**
* Compares the 2 streams.
* <p/>
* Calls {@link #trimLines(InputStream)} on each stream before comparing.
* @param s1 Stream 1.
* @param s2 Stream 2.
* @return True if the streams are equal not including leading and trailing
* whitespace on each line and blank lines, otherwise returns false.
*/
public static boolean compareCharStreams(InputStream s1, InputStream s2) {
StringBuffer s1Buf, s2Buf;
try {
s1Buf = trimLines(s1);
s2Buf = trimLines(s2);
return s1Buf.toString().equals(s2Buf.toString());
} catch (IOException e) {
// fail the comparison
}
return false;
}
/**
* Compares the 2 streams.
* <p/>
* Calls {@link #trimLines(java.io.Reader)} on each stream before comparing.
* @param s1 Stream 1.
* @param s2 Stream 2.
* @return True if the streams are equal not including leading and trailing
* whitespace on each line and blank lines, otherwise returns false.
*/
public static boolean compareCharStreams(Reader s1, Reader s2) {
StringBuffer s1Buf, s2Buf;
try {
s1Buf = trimLines(s1);
s2Buf = trimLines(s2);
return s1Buf.toString().equals(s2Buf.toString());
} catch (IOException e) {
// fail the comparison
}
return false;
}
/**
* Compares the 2 streams.
* <p/>
* Calls {@link #trimLines(java.io.Reader)} on each stream before comparing.
* @param s1 Stream 1.
* @param s2 Stream 2.
* @return True if the streams are equal not including leading and trailing
* whitespace on each line and blank lines, otherwise returns false.
*/
public static boolean compareCharStreams(String s1, String s2) {
return compareCharStreams(new StringReader(s1), new StringReader(s2));
}
/**
* Read the lines lines of characters from the stream and trim each line
* i.e. remove all leading and trailing whitespace.
* @param charStream Character stream.
* @return StringBuffer containing the line trimmed stream.
* @throws IOException
*/
public static StringBuffer trimLines(Reader charStream) throws IOException {
StringBuffer stringBuf = new StringBuffer();
BufferedReader reader = new BufferedReader(charStream);
String line;
while((line = reader.readLine()) != null) {
stringBuf.append(line.trim());
}
return stringBuf;
}
/**
* Read the lines lines of characters from the stream and trim each line
* i.e. remove all leading and trailing whitespace.
* @param charStream Character stream.
* @return StringBuffer containing the line trimmed stream.
* @throws IOException
*/
public static StringBuffer trimLines(InputStream charStream) throws IOException {
return trimLines(new InputStreamReader(charStream, "UTF-8"));
}
}
General IO Stream manipulation
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you 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. *
****************************************************************/
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
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.StringReader;
import java.io.StringWriter;
import java.io.Writer;
/**
* General IO Stream manipulation.
* <p>
* This class provides static utility methods for input/output operations, particularly buffered
* copying between sources (<code>InputStream</code>, <code>Reader</code>, <code>String</code> and
* <code>byte[]</code>) and destinations (<code>OutputStream</code>, <code>Writer</code>,
* <code>String</code> and <code>byte[]</code>).
* </p>
*
* <p>Unless otherwise noted, these <code>copy</code> methods do <em>not</em> flush or close the
* streams. Often, doing so would require making non-portable assumptions about the streams" origin
* and further use. This means that both streams" <code>close()</code> methods must be called after
* copying. if one omits this step, then the stream resources (sockets, file descriptors) are
* released when the associated Stream is garbage-collected. It is not a good idea to rely on this
* mechanism. For a good overview of the distinction between "memory management" and "resource
* management", see for a list of valid encoding types.
* @param bufferSize Size of internal buffer to use.
*/
public static String toString( final byte[] input,
final String encoding,
final int bufferSize )
throws IOException
{
final StringWriter sw = new StringWriter();
copy( input, sw, encoding, bufferSize );
return sw.toString();
}
///////////////////////////////////////////////////////////////
// byte[] -> OutputStream
/**
* Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
*/
public static void copy( final byte[] input, final OutputStream output )
throws IOException
{
copy( input, output, DEFAULT_BUFFER_SIZE );
}
/**
* Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
* @param bufferSize Size of internal buffer to use.
*/
public static void copy( final byte[] input,
final OutputStream output,
final int bufferSize )
throws IOException
{
output.write( input );
}
/**
* Compare the contents of two Streams to determine if they are equal or not.
*
* @param input1 the first stream
* @param input2 the second stream
* @return true if the content of the streams are equal or they both don"t exist, false otherwise
*/
public static boolean contentEquals( final InputStream input1,
final InputStream input2 )
throws IOException
{
final InputStream bufferedInput1 = new BufferedInputStream( input1 );
final InputStream bufferedInput2 = new BufferedInputStream( input2 );
int ch = bufferedInput1.read();
while( -1 != ch )
{
final int ch2 = bufferedInput2.read();
if( ch != ch2 )
{
return false;
}
ch = bufferedInput1.read();
}
final int ch2 = bufferedInput2.read();
if( -1 != ch2 )
{
return false;
}
else
{
return true;
}
}
}
General IO stream manipulation utilities
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* General IO stream manipulation utilities.
* <p>
* This class provides static utility methods for input/output operations.
* <ul>
* <li>closeQuietly - these methods close a stream ignoring nulls and exceptions
* <li>toXxx/read - these methods read data from a stream
* <li>write - these methods write data to a stream
* <li>copy - these methods copy all the data from one stream to another
* <li>contentEquals - these methods compare the content of two streams
* </ul>
* <p>
* The byte-to-char methods and char-to-byte methods involve a conversion step.
* Two methods are provided in each case, one that uses the platform default
* encoding and the other which allows you to specify an encoding. You are
* encouraged to always specify an encoding because relying on the platform
* default can lead to unexpected results, for example when moving from
* development to production.
* <p>
* All the methods in this class that read a stream are buffered internally.
* This means that there is no cause to use a <code>BufferedInputStream</code>
* or <code>BufferedReader</code>. The default buffer size of 4K has been shown
* to be efficient in tests.
* <p>
* Wherever possible, the methods in this class do <em>not</em> flush or close
* the stream. This is to avoid making non-portable assumptions about the
* streams" origin and further use. Thus the caller is still responsible for
* closing streams after use.
* <p>
* Origin of code: Excalibur.
*
* @author Peter Donald
* @author Jeff Turner
* @author Matthew Hawthorne
* @author Stephen Colebourne
* @author Gareth Davis
* @author Ian Springer
* @author Niall Pemberton
* @author Sandy McArthur
* @version $Id: IOUtils.java 481854 2006-12-03 18:30:07Z scolebourne $
*/
public class IOUtils {
// NOTE: This class is focussed on InputStream, OutputStream, Reader and
// Writer. Each method should take at least one of these as a parameter,
// or return one of them.
/**
* The Unix directory separator character.
*/
public static final char DIR_SEPARATOR_UNIX = "/";
/**
* The Windows directory separator character.
*/
public static final char DIR_SEPARATOR_WINDOWS = "\\";
/**
* The system directory separator character.
*/
public static final char DIR_SEPARATOR = File.separatorChar;
/**
* The Unix line separator string.
*/
public static final String LINE_SEPARATOR_UNIX = "\n";
/**
* The Windows line separator string.
*/
public static final String LINE_SEPARATOR_WINDOWS = "\r\n";
/**
* The system line separator string.
*/
public static final String LINE_SEPARATOR;
static {
// avoid security issues
StringWriter buf = new StringWriter(4);
PrintWriter out = new PrintWriter(buf);
out.println();
LINE_SEPARATOR = buf.toString();
}
/**
* The default buffer size to use.
*/
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
/**
* Instances should NOT be constructed in standard programming.
*/
public IOUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* Unconditionally close an <code>Reader</code>.
* <p>
* Equivalent to {@link Reader#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param input the Reader to close, may be null or already closed
*/
public static void closeQuietly(Reader input) {
try {
if (input != null) {
input.close();
}
} catch (IOException ioe) {
// ignore
}
}
/**
* Unconditionally close a <code>Writer</code>.
* <p>
* Equivalent to {@link Writer#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param output the Writer to close, may be null or already closed
*/
public static void closeQuietly(Writer output) {
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// ignore
}
}
/**
* Unconditionally close an <code>InputStream</code>.
* <p>
* Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param input the InputStream to close, may be null or already closed
*/
public static void closeQuietly(InputStream input) {
try {
if (input != null) {
input.close();
}
} catch (IOException ioe) {
// ignore
}
}
/**
* Unconditionally close an <code>OutputStream</code>.
* <p>
* Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
*
* @param output the OutputStream to close, may be null or already closed
*/
public static void closeQuietly(OutputStream output) {
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// ignore
}
}
/**
* Get the contents of a <code>String</code> as a <code>byte[]</code>
* using the default character encoding of the platform.
* <p>
* This is the same as {@link String#getBytes()}.
*
* @param input the <code>String</code> to convert
* @return the requested byte array
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs (never occurs)
* @deprecated Use {@link String#getBytes()}
*/
public static byte[] toByteArray(String input) throws IOException {
return input.getBytes();
}
// read char[]
//-----------------------------------------------------------------------
/**
* Get the contents of an <code>InputStream</code> as a character array
* using the default character encoding of the platform.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
*
* @param is the <code>InputStream</code> to read from
* @return the requested character array
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs
* @since Commons IO 1.1
*/
public static char[] toCharArray(InputStream is) throws IOException {
CharArrayWriter output = new CharArrayWriter();
copy(is, output);
return output.toCharArray();
}
/**
* Get the contents of an <code>InputStream</code> as a character array
* using the specified character encoding.
* <p>
* Character encoding names can be found at
* .
* <p>
* Due to the implementation of OutputStreamWriter, this method performs a
* flush.
* <p>
* This method uses {@link OutputStreamWriter}.
*
* @param input the <code>Reader</code> to read from
* @param output the <code>OutputStream</code> to write to
* @param encoding the encoding to use, null means platform default
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since Commons IO 1.1
*/
public static void copy(Reader input, OutputStream output, String encoding)
throws IOException {
if (encoding == null) {
copy(input, output);
} else {
OutputStreamWriter out = new OutputStreamWriter(output, encoding);
copy(input, out);
// XXX Unless anyone is planning on rewriting OutputStreamWriter,
// we have to flush here.
out.flush();
}
}
// content equals
//-----------------------------------------------------------------------
/**
* Compare the contents of two Streams to determine if they are equal or
* not.
* <p>
* This method buffers the input internally using
* <code>BufferedInputStream</code> if they are not already buffered.
*
* @param input1 the first stream
* @param input2 the second stream
* @return true if the content of the streams are equal or they both don"t
* exist, false otherwise
* @throws NullPointerException if either input is null
* @throws IOException if an I/O error occurs
*/
public static boolean contentEquals(InputStream input1, InputStream input2)
throws IOException {
if (!(input1 instanceof BufferedInputStream)) {
input1 = new BufferedInputStream(input1);
}
if (!(input2 instanceof BufferedInputStream)) {
input2 = new BufferedInputStream(input2);
}
int ch = input1.read();
while (-1 != ch) {
int ch2 = input2.read();
if (ch != ch2) {
return false;
}
ch = input1.read();
}
int ch2 = input2.read();
return (ch2 == -1);
}
/**
* Compare the contents of two Readers to determine if they are equal or
* not.
* <p>
* This method buffers the input internally using
* <code>BufferedReader</code> if they are not already buffered.
*
* @param input1 the first reader
* @param input2 the second reader
* @return true if the content of the readers are equal or they both don"t
* exist, false otherwise
* @throws NullPointerException if either input is null
* @throws IOException if an I/O error occurs
* @since Commons IO 1.1
*/
public static boolean contentEquals(Reader input1, Reader input2)
throws IOException {
if (!(input1 instanceof BufferedReader)) {
input1 = new BufferedReader(input1);
}
if (!(input2 instanceof BufferedReader)) {
input2 = new BufferedReader(input2);
}
int ch = input1.read();
while (-1 != ch) {
int ch2 = input2.read();
if (ch != ch2) {
return false;
}
ch = input1.read();
}
int ch2 = input2.read();
return (ch2 == -1);
}
}
Show the content of a file
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
class ShowFile {
public static void main(String args[]) throws IOException {
int i;
FileInputStream fin;
try {
fin = new FileInputStream(args[0]);
} catch (FileNotFoundException e) {
System.out.println("File Not Found");
return;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Usage: ShowFile File");
return;
}
do {
i = fin.read();
if (i != -1)
System.out.print((char) i);
} while (i != -1);
fin.close();
}
}
Some general utility functions for dealing with Streams
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/*
* StreamUtility.java
*
* Created on October 26, 2002, 4:05 PM
*
* Copyright (C) 2002 Robert Cooper, Temple of the Screaming Penguin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** This class contains some general utility functions for dealing with Streams.
* <cite>by Robert Cooper, Temple of the Screaming Penguin. Distributed under the
* terms of the , 2002
*/
class StreamUtility {
/**
* default read size for stream copy
*/
public static final int DEFAULT_BUFFER_SIZE = 1024;
/** Copies the data from an InputStream object to an OutputStream object.
* @param sourceStream The input stream to be read.
* @param destinationStream The output stream to be written to.
* @return int value of the number of bytes copied.
* @exception IOException from java.io calls.
*/
public static int copyStream(InputStream sourceStream,OutputStream destinationStream) throws IOException {
int bytesRead = 0;
int totalBytes = 0;
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
while(bytesRead >= 0) {
bytesRead = sourceStream.read(buffer,0,buffer.length);
if(bytesRead > 0) {
destinationStream.write(buffer,0,bytesRead);
}
totalBytes += bytesRead;
}
return totalBytes;
}
/**
* Converts little endian bytes to a int
* @param value byte array to read
* @return integer value of the byte array
*/
public static int littleEndianToInt(byte[] value) {
return ByteBuffer.wrap(value).order(ByteOrder.LITTLE_ENDIAN).getInt();
}
/**
* Converts little endian bytes to a long
* @param value byte array to read
* @return long value of the byte array
*/
public static long littleEndianToLong(byte[] value) {
return ByteBuffer.wrap(value).order(ByteOrder.LITTLE_ENDIAN).getLong();
}
/**
* Converts little endian Unicode bytes to a String
* @param value byte array of Unicode Little Endian
* @return String value of the byte array
*/
public static String littleEndianToString(byte[] value) {
return ByteBuffer.wrap(value).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer().toString();
}
/**
* Read an entire stream and return it as a String
*
* @param sourceStream the InputStream to read.
* @return a String containing the contents of the stream.
* @exception IOException from java.io calls.
*/
public static String readStreamAsString(InputStream sourceStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(sourceStream));
ByteArrayOutputStream output = new ByteArrayOutputStream();
copyStream(sourceStream,output);
return output.toString();
}
/**
* This is a quick method to get a subset of a byte array as a new array
* @param start index of the source to begin reading from
* @param count number of bytes to copy
* @param source byte array to read from
* @return byte array of size <code>count</code>
*/
public static byte[] subset(int start,int count,byte[] source) {
byte[] ret = new byte[count];
for(int i = 0; i < count; i++) {
ret[i] = source[start + i];
}
return ret;
}
}
/*
JSPWiki - a JSP-based WikiWiki clone.
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
*/
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
/**
* Generic utilities related to file and stream handling.
*/
// FIXME3.0: This class will move to "util" directory in 3.0
public final class FileUtil
{
/** Size of the buffer used when copying large chunks of data. */
private static final int BUFFER_SIZE = 4096;
/**
* Private constructor prevents instantiation.
*/
private FileUtil()
{}
/**
* Makes a new temporary file and writes content into it. The temporary
* file is created using <code>File.createTempFile()</code>, and the usual
* semantics apply. The files are not deleted automatically in exit.
*
* @param content Initial content of the temporary file.
* @param encoding Encoding to use.
* @return The handle to the new temporary file
* @throws IOException If the content creation failed.
* @see java.io.File#createTempFile(String,String,File)
*/
public static File newTmpFile( String content, String encoding )
throws IOException
{
Writer out = null;
Reader in = null;
File f = null;
try
{
f = File.createTempFile( "jspwiki", null );
in = new StringReader( content );
out = new OutputStreamWriter( new FileOutputStream( f ),
encoding );
copyContents( in, out );
}
finally
{
if( in != null ) in.close();
if( out != null ) out.close();
}
return f;
}
/**
* Creates a new temporary file using the default encoding
* of ISO-8859-1 (Latin1).
*
* @param content The content to put into the file.
* @throws IOException If writing was unsuccessful.
* @return A handle to the newly created file.
* @see #newTmpFile( String, String )
* @see java.io.File#createTempFile(String,String,File)
*/
public static File newTmpFile( String content )
throws IOException
{
return newTmpFile( content, "ISO-8859-1" );
}
/**
* Runs a simple command in given directory.
* The environment is inherited from the parent process (e.g. the
* one in which this Java VM runs).
*
* @return Standard output from the command.
* @param command The command to run
* @param directory The working directory to run the command in
* @throws IOException If the command failed
* @throws InterruptedException If the command was halted
*/
public static String runSimpleCommand( String command, String directory )
throws IOException,
InterruptedException
{
StringBuffer result = new StringBuffer();
System.out.println("Running simple command "+command+" in "+directory);
Process process = Runtime.getRuntime().exec( command, null, new File(directory) );
BufferedReader stdout = null;
BufferedReader stderr = null;
try
{
stdout = new BufferedReader( new InputStreamReader(process.getInputStream()) );
stderr = new BufferedReader( new InputStreamReader(process.getErrorStream()) );
String line;
while( (line = stdout.readLine()) != null )
{
result.append( line+"\n");
}
StringBuffer error = new StringBuffer();
while( (line = stderr.readLine()) != null )
{
error.append( line+"\n");
}
if( error.length() > 0 )
{
System.out.println("Command failed, error stream is: "+error);
}
process.waitFor();
}
finally
{
// we must close all by exec(..) opened streams: http://bugs.sun.ru/bugdatabase/view_bug.do?bug_id=4784692
process.getInputStream().close();
if( stdout != null ) stdout.close();
if( stderr != null ) stderr.close();
}
return result.toString();
}
/**
* Just copies all characters from <I>in</I> to <I>out</I>. The copying
* is performed using a buffer of bytes.
*
* @since 1.5.8
* @param in The reader to copy from
* @param out The reader to copy to
* @throws IOException If reading or writing failed.
*/
public static void copyContents( Reader in, Writer out )
throws IOException
{
char[] buf = new char[BUFFER_SIZE];
int bytesRead = 0;
while ((bytesRead = in.read(buf)) > 0)
{
out.write(buf, 0, bytesRead);
}
out.flush();
}
/**
* Just copies all bytes from <I>in</I> to <I>out</I>. The copying is
* performed using a buffer of bytes.
*
* @since 1.9.31
* @param in The inputstream to copy from
* @param out The outputstream to copy to
* @throws IOException In case reading or writing fails.
*/
public static void copyContents( InputStream in, OutputStream out )
throws IOException
{
byte[] buf = new byte[BUFFER_SIZE];
int bytesRead = 0;
while ((bytesRead = in.read(buf)) > 0)
{
out.write(buf, 0, bytesRead);
}
out.flush();
}
/**
* Reads in file contents.
* <P>
* This method is smart and falls back to ISO-8859-1 if the input stream does not
* seem to be in the specified encoding.
*
* @param input The InputStream to read from.
* @param encoding The encoding to assume at first.
* @return A String, interpreted in the "encoding", or, if it fails, in Latin1.
* @throws IOException If the stream cannot be read or the stream cannot be
* decoded (even) in Latin1
*/
public static String readContents( InputStream input, String encoding )
throws IOException
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
FileUtil.copyContents( input, out );
ByteBuffer bbuf = ByteBuffer.wrap( out.toByteArray() );
Charset cset = Charset.forName( encoding );
CharsetDecoder csetdecoder = cset.newDecoder();
csetdecoder.onMalformedInput( CodingErrorAction.REPORT );
csetdecoder.onUnmappableCharacter( CodingErrorAction.REPORT );
try
{
CharBuffer cbuf = csetdecoder.decode( bbuf );
return cbuf.toString();
}
catch( CharacterCodingException e )
{
Charset latin1 = Charset.forName("ISO-8859-1");
CharsetDecoder l1decoder = latin1.newDecoder();
l1decoder.onMalformedInput( CodingErrorAction.REPORT );
l1decoder.onUnmappableCharacter( CodingErrorAction.REPORT );
try
{
bbuf = ByteBuffer.wrap( out.toByteArray() );
CharBuffer cbuf = l1decoder.decode( bbuf );
return cbuf.toString();
}
catch( CharacterCodingException ex )
{
throw (CharacterCodingException) ex.fillInStackTrace();
}
}
}
/**
* Returns the full contents of the Reader as a String.
*
* @since 1.5.8
* @param in The reader from which the contents shall be read.
* @return String read from the Reader
* @throws IOException If reading fails.
*/
public static String readContents( Reader in )
throws IOException
{
Writer out = null;
try
{
out = new StringWriter();
copyContents( in, out );
return out.toString();
}
finally
{
try
{
out.close();
}
catch( Exception e )
{
System.out.println("Not able to close the stream while reading contents.");
}
}
}
/**
* Returns the class and method name (+a line number) in which the
* Throwable was thrown.
*
* @param t A Throwable to analyze.
* @return A human-readable string stating the class and method. Do not rely
* the format to be anything fixed.
*/
public static String getThrowingMethod( Throwable t )
{
StackTraceElement[] trace = t.getStackTrace();
StringBuffer sb = new StringBuffer();
if( trace == null || trace.length == 0 )
{
sb.append( "[Stack trace not available]" );
}
else
{
sb.append( trace[0].isNativeMethod() ? "native method" : "" );
sb.append( trace[0].getClassName() );
sb.append(".");
sb.append(trace[0].getMethodName()+"(), line "+trace[0].getLineNumber());
}
return sb.toString();
}
}
Utility code for dealing with different endian systems
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Utility code for dealing with different endian systems.
* <p>
* Different computer architectures adopt different conventions for
* byte ordering. In so-called "Little Endian" architectures (eg Intel),
* the low-order byte is stored in memory at the lowest address, and
* subsequent bytes at higher addresses. For "Big Endian" architectures
* (eg Motorola), the situation is reversed.
* This class helps you solve this incompatability.
* <p>
* Origin of code: Excalibur
*
* @author
* @version $Id: EndianUtils.java 539632 2007-05-18 23:37:59Z bayard $
* @see org.apache.rumons.io.input.SwappedDataInputStream
*/
public class EndianUtils {
/**
* Instances should NOT be constructed in standard programming.
*/
public EndianUtils() {
super();
}
// Swapping routines
/**
* Converts a "short" value between endian systems.
* @param value value to convert
* @return the converted value
*/
public static short swapShort(short value) {
return (short) ( ( ( ( value >> 0 ) & 0xff ) << 8 ) +
( ( ( value >> 8 ) & 0xff ) << 0 ) );
}
/**
* Converts a "int" value between endian systems.
* @param value value to convert
* @return the converted value
*/
public static int swapInteger(int value) {
return
( ( ( value >> 0 ) & 0xff ) << 24 ) +
( ( ( value >> 8 ) & 0xff ) << 16 ) +
( ( ( value >> 16 ) & 0xff ) << 8 ) +
( ( ( value >> 24 ) & 0xff ) << 0 );
}
/**
* Converts a "long" value between endian systems.
* @param value value to convert
* @return the converted value
*/
public static long swapLong(long value) {
return
( ( ( value >> 0 ) & 0xff ) << 56 ) +
( ( ( value >> 8 ) & 0xff ) << 48 ) +
( ( ( value >> 16 ) & 0xff ) << 40 ) +
( ( ( value >> 24 ) & 0xff ) << 32 ) +
( ( ( value >> 32 ) & 0xff ) << 24 ) +
( ( ( value >> 40 ) & 0xff ) << 16 ) +
( ( ( value >> 48 ) & 0xff ) << 8 ) +
( ( ( value >> 56 ) & 0xff ) << 0 );
}
/**
* Converts a "float" value between endian systems.
* @param value value to convert
* @return the converted value
*/
public static float swapFloat(float value) {
return Float.intBitsToFloat( swapInteger( Float.floatToIntBits( value ) ) );
}
/**
* Converts a "double" value between endian systems.
* @param value value to convert
* @return the converted value
*/
public static double swapDouble(double value) {
return Double.longBitsToDouble( swapLong( Double.doubleToLongBits( value ) ) );
}
// Swapping read/write routines
/**
* Writes a "short" value to a byte array at a given offset. The value is
* converted to the opposed endian system while writing.
* @param data target byte array
* @param offset starting offset in the byte array
* @param value value to write
*/
public static void writeSwappedShort(byte[] data, int offset, short value) {
data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
}
/**
* Reads a "short" value from a byte array at a given offset. The value is
* converted to the opposed endian system while reading.
* @param data source byte array
* @param offset starting offset in the byte array
* @return the value read
*/
public static short readSwappedShort(byte[] data, int offset) {
return (short)( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
( ( data[ offset + 1 ] & 0xff ) << 8 ) );
}
/**
* Reads an unsigned short (16-bit) value from a byte array at a given
* offset. The value is converted to the opposed endian system while
* reading.
* @param data source byte array
* @param offset starting offset in the byte array
* @return the value read
*/
public static int readSwappedUnsignedShort(byte[] data, int offset) {
return ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
( ( data[ offset + 1 ] & 0xff ) << 8 ) );
}
/**
* Writes a "int" value to a byte array at a given offset. The value is
* converted to the opposed endian system while writing.
* @param data target byte array
* @param offset starting offset in the byte array
* @param value value to write
*/
public static void writeSwappedInteger(byte[] data, int offset, int value) {
data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff );
data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff );
}
/**
* Reads a "int" value from a byte array at a given offset. The value is
* converted to the opposed endian system while reading.
* @param data source byte array
* @param offset starting offset in the byte array
* @return the value read
*/
public static int readSwappedInteger(byte[] data, int offset) {
return ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
( ( data[ offset + 1 ] & 0xff ) << 8 ) +
( ( data[ offset + 2 ] & 0xff ) << 16 ) +
( ( data[ offset + 3 ] & 0xff ) << 24 ) );
}
/**
* Reads an unsigned integer (32-bit) value from a byte array at a given
* offset. The value is converted to the opposed endian system while
* reading.
* @param data source byte array
* @param offset starting offset in the byte array
* @return the value read
*/
public static long readSwappedUnsignedInteger(byte[] data, int offset) {
long low = ( ( ( data[ offset + 0 ] & 0xff ) << 0 ) +
( ( data[ offset + 1 ] & 0xff ) << 8 ) +
( ( data[ offset + 2 ] & 0xff ) << 16 ) );
long high = data[ offset + 3 ] & 0xff;
return (high << 24) + (0xffffffffL & low);
}
/**
* Writes a "long" value to a byte array at a given offset. The value is
* converted to the opposed endian system while writing.
* @param data target byte array
* @param offset starting offset in the byte array
* @param value value to write
*/
public static void writeSwappedLong(byte[] data, int offset, long value) {
data[ offset + 0 ] = (byte)( ( value >> 0 ) & 0xff );
data[ offset + 1 ] = (byte)( ( value >> 8 ) & 0xff );
data[ offset + 2 ] = (byte)( ( value >> 16 ) & 0xff );
data[ offset + 3 ] = (byte)( ( value >> 24 ) & 0xff );
data[ offset + 4 ] = (byte)( ( value >> 32 ) & 0xff );
data[ offset + 5 ] = (byte)( ( value >> 40 ) & 0xff );
data[ offset + 6 ] = (byte)( ( value >> 48 ) & 0xff );
data[ offset + 7 ] = (byte)( ( value >> 56 ) & 0xff );
}
/**
* Reads a "long" value from a byte array at a given offset. The value is
* converted to the opposed endian system while reading.
* @param data source byte array
* @param offset starting offset in the byte array
* @return the value read
*/
public static long readSwappedLong(byte[] data, int offset) {
long low =
( ( data[ offset + 0 ] & 0xff ) << 0 ) +
( ( data[ offset + 1 ] & 0xff ) << 8 ) +
( ( data[ offset + 2 ] & 0xff ) << 16 ) +
( ( data[ offset + 3 ] & 0xff ) << 24 );
long high =
( ( data[ offset + 4 ] & 0xff ) << 0 ) +
( ( data[ offset + 5 ] & 0xff ) << 8 ) +
( ( data[ offset + 6 ] & 0xff ) << 16 ) +
( ( data[ offset + 7 ] & 0xff ) << 24 );
return (high << 32) + (0xffffffffL & low);
}
/**
* Writes a "float" value to a byte array at a given offset. The value is
* converted to the opposed endian system while writing.
* @param data target byte array
* @param offset starting offset in the byte array
* @param value value to write
*/
public static void writeSwappedFloat(byte[] data, int offset, float value) {
writeSwappedInteger( data, offset, Float.floatToIntBits( value ) );
}
/**
* Reads a "float" value from a byte array at a given offset. The value is
* converted to the opposed endian system while reading.
* @param data source byte array
* @param offset starting offset in the byte array
* @return the value read
*/
public static float readSwappedFloat(byte[] data, int offset) {
return Float.intBitsToFloat( readSwappedInteger( data, offset ) );
}
/**
* Writes a "double" value to a byte array at a given offset. The value is
* converted to the opposed endian system while writing.
* @param data target byte array
* @param offset starting offset in the byte array
* @param value value to write
*/
public static void writeSwappedDouble(byte[] data, int offset, double value) {
writeSwappedLong( data, offset, Double.doubleToLongBits( value ) );
}
/**
* Reads a "double" value from a byte array at a given offset. The value is
* converted to the opposed endian system while reading.
* @param data source byte array
* @param offset starting offset in the byte array
* @return the value read
*/
public static double readSwappedDouble(byte[] data, int offset) {
return Double.longBitsToDouble( readSwappedLong( data, offset ) );
}
/**
* Writes a "short" value to an OutputStream. The value is
* converted to the opposed endian system while writing.
* @param output target OutputStream
* @param value value to write
* @throws IOException in case of an I/O problem
*/
public static void writeSwappedShort(OutputStream output, short value)
throws IOException
{
output.write( (byte)( ( value >> 0 ) & 0xff ) );
output.write( (byte)( ( value >> 8 ) & 0xff ) );
}
/**
* Reads a "short" value from an InputStream. The value is
* converted to the opposed endian system while reading.
* @param input source InputStream
* @return the value just read
* @throws IOException in case of an I/O problem
*/
public static short readSwappedShort(InputStream input)
throws IOException
{
return (short)( ( ( read( input ) & 0xff ) << 0 ) +
( ( read( input ) & 0xff ) << 8 ) );
}
/**
* Reads a unsigned short (16-bit) from an InputStream. The value is
* converted to the opposed endian system while reading.
* @param input source InputStream
* @return the value just read
* @throws IOException in case of an I/O problem
*/
public static int readSwappedUnsignedShort(InputStream input)
throws IOException
{
int value1 = read( input );
int value2 = read( input );
return ( ( ( value1 & 0xff ) << 0 ) +
( ( value2 & 0xff ) << 8 ) );
}
/**
* Writes a "int" value to an OutputStream. The value is
* converted to the opposed endian system while writing.
* @param output target OutputStream
* @param value value to write
* @throws IOException in case of an I/O problem
*/
public static void writeSwappedInteger(OutputStream output, int value)
throws IOException
{
output.write( (byte)( ( value >> 0 ) & 0xff ) );
output.write( (byte)( ( value >> 8 ) & 0xff ) );
output.write( (byte)( ( value >> 16 ) & 0xff ) );
output.write( (byte)( ( value >> 24 ) & 0xff ) );
}
/**
* Reads a "int" value from an InputStream. The value is
* converted to the opposed endian system while reading.
* @param input source InputStream
* @return the value just read
* @throws IOException in case of an I/O problem
*/
public static int readSwappedInteger(InputStream input)
throws IOException
{
int value1 = read( input );
int value2 = read( input );
int value3 = read( input );
int value4 = read( input );
return ( ( value1 & 0xff ) << 0 ) +
( ( value2 & 0xff ) << 8 ) +
( ( value3 & 0xff ) << 16 ) +
( ( value4 & 0xff ) << 24 );
}
/**
* Reads a unsigned integer (32-bit) from an InputStream. The value is
* converted to the opposed endian system while reading.
* @param input source InputStream
* @return the value just read
* @throws IOException in case of an I/O problem
*/
public static long readSwappedUnsignedInteger(InputStream input)
throws IOException
{
int value1 = read( input );
int value2 = read( input );
int value3 = read( input );
int value4 = read( input );
long low = ( ( ( value1 & 0xff ) << 0 ) +
( ( value2 & 0xff ) << 8 ) +
( ( value3 & 0xff ) << 16 ) );
long high = value4 & 0xff;
return (high << 24) + (0xffffffffL & low);
}
/**
* Writes a "long" value to an OutputStream. The value is
* converted to the opposed endian system while writing.
* @param output target OutputStream
* @param value value to write
* @throws IOException in case of an I/O problem
*/
public static void writeSwappedLong(OutputStream output, long value)
throws IOException
{
output.write( (byte)( ( value >> 0 ) & 0xff ) );
output.write( (byte)( ( value >> 8 ) & 0xff ) );
output.write( (byte)( ( value >> 16 ) & 0xff ) );
output.write( (byte)( ( value >> 24 ) & 0xff ) );
output.write( (byte)( ( value >> 32 ) & 0xff ) );
output.write( (byte)( ( value >> 40 ) & 0xff ) );
output.write( (byte)( ( value >> 48 ) & 0xff ) );
output.write( (byte)( ( value >> 56 ) & 0xff ) );
}
/**
* Reads a "long" value from an InputStream. The value is
* converted to the opposed endian system while reading.
* @param input source InputStream
* @return the value just read
* @throws IOException in case of an I/O problem
*/
public static long readSwappedLong(InputStream input)
throws IOException
{
byte[] bytes = new byte[8];
for ( int i=0; i<8; i++ ) {
bytes[i] = (byte) read( input );
}
return readSwappedLong( bytes, 0 );
}
/**
* Writes a "float" value to an OutputStream. The value is
* converted to the opposed endian system while writing.
* @param output target OutputStream
* @param value value to write
* @throws IOException in case of an I/O problem
*/
public static void writeSwappedFloat(OutputStream output, float value)
throws IOException
{
writeSwappedInteger( output, Float.floatToIntBits( value ) );
}
/**
* Reads a "float" value from an InputStream. The value is
* converted to the opposed endian system while reading.
* @param input source InputStream
* @return the value just read
* @throws IOException in case of an I/O problem
*/
public static float readSwappedFloat(InputStream input)
throws IOException
{
return Float.intBitsToFloat( readSwappedInteger( input ) );
}
/**
* Writes a "double" value to an OutputStream. The value is
* converted to the opposed endian system while writing.
* @param output target OutputStream
* @param value value to write
* @throws IOException in case of an I/O problem
*/
public static void writeSwappedDouble(OutputStream output, double value)
throws IOException
{
writeSwappedLong( output, Double.doubleToLongBits( value ) );
}
/**
* Reads a "double" value from an InputStream. The value is
* converted to the opposed endian system while reading.
* @param input source InputStream
* @return the value just read
* @throws IOException in case of an I/O problem
*/
public static double readSwappedDouble(InputStream input)
throws IOException
{
return Double.longBitsToDouble( readSwappedLong( input ) );
}
/**
* Reads the next byte from the input stream.
* @param input the stream
* @return the byte
* @throws IOException if the end of file is reached
*/
private static int read(InputStream input)
throws IOException
{
int value = input.read();
if( -1 == value ) {
throw new EOFException( "Unexpected EOF reached" );
}
return value;
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.io.InputStreamReader;
/**
* Utility functions related to Streams.
*
* @author
* @version $Id: Streams.java 516448 2007-03-09 16:25:47Z ate $
*/
public class Streams
{
static final int BLOCK_SIZE=4096;
public static void drain(InputStream r,OutputStream w) throws IOException
{
byte[] bytes=new byte[BLOCK_SIZE];
try
{
int length=r.read(bytes);
while(length!=-1)
{
if(length!=0)
{
w.write(bytes,0,length);
}
length=r.read(bytes);
}
}
finally
{
bytes=null;
}
}
public static void drain(Reader r,Writer w) throws IOException
{
char[] bytes=new char[BLOCK_SIZE];
try
{
int length=r.read(bytes);
while(length!=-1)
{
if(length!=0)
{
w.write(bytes,0,length);
}
length=r.read(bytes);
}
}
finally
{
bytes=null;
}
}
public static void drain(Reader r,OutputStream os) throws IOException
{
Writer w=new OutputStreamWriter(os);
drain(r,w);
w.flush();
}
public static void drain(InputStream is, Writer w) throws IOException
{
Reader r = new InputStreamReader(is);
drain(r,w);
w.flush();
}
public static byte[] drain(InputStream r) throws IOException
{
ByteArrayOutputStream bytes=new ByteArrayOutputStream();
drain(r,bytes);
return bytes.toByteArray();
}
public static String getAsString(InputStream is)
{
int c=0;
char lineBuffer[]=new char[128], buf[]=lineBuffer;
int room= buf.length, offset=0;
try
{
loop: while (true)
{
// read chars into a buffer which grows as needed
switch (c = is.read() )
{
case -1: break loop;
default: if (--room < 0)
{
buf = new char[offset + 128];
room = buf.length - offset - 1;
System.arraycopy(lineBuffer, 0,
buf, 0, offset);
lineBuffer = buf;
}
buf[offset++] = (char) c;
break;
}
}
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
if ((c == -1) && (offset == 0))
{
return null;
}
return String.copyValueOf(buf, 0, offset);
}
}
Utility methods for handling streams
//The contents of this file are subject to the Mozilla Public License Version 1.1
//(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.mozilla.org/MPL/
//
//Software distributed under the License is distributed on an "AS IS" basis,
//WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
//for the specific language governing rights and
//limitations under the License.
//
//The Original Code is "The Columba Project"
//
//The Initial Developers of the Original Code are Frederik Dietz and Timo Stich.
//Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
//
//All Rights Reserved.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Contains utility methods for handling streams.
*/
public class StreamUtils {
private static final int BUFFERSIZE = 8000;
/**
* Copies length bytes from an InputStream to an OutputStream.
*
* @param in
* InputStream from wihch the bytes are to copied.
* @param out
* OutputStream in which the bytes are copied.
* @param length
* The number of bytes to copy
* @return Number of bytes which are copied.
* @throws IOException
* If the streams are unavailable.
*/
public static int streamCopy(InputStream in, OutputStream out, int length)
throws IOException {
byte[] buffer = new byte[BUFFERSIZE];
int read;
int copied = 0;
while ((read = in
.read(buffer, 0, Math.min(BUFFERSIZE, length - copied))) > 0) {
out.write(buffer, 0, read);
copied += read;
}
return copied;
}
/**
* Copies all bytes from an InputStream to an OutputStream. The buffer size
* is set to 8000 bytes.
*
* @param _isInput
* InputStream from wihch the bytes are to copied.
* @param _osOutput
* OutputStream in which the bytes are copied.
* @return Number of bytes which are copied.
* @throws IOException
* If the Streams are unavailable.
*/
public static long streamCopy(InputStream in, OutputStream out)
throws IOException {
byte[] buffer = new byte[BUFFERSIZE];
int read;
long copied = 0;
while ((read = in.read(buffer)) > 0) {
out.write(buffer, 0, read);
copied += read;
}
return copied;
}
/**
* Reads a InputStream of chars into a StringBuffer.
*
* @param in
* the InputStream to read from
* @return the interpreted InputStream
* @throws IOException
*/
public static StringBuffer readCharacterStream(InputStream in)
throws IOException {
StringBuffer result = new StringBuffer(in.available());
int read = in.read();
while (read > 0) {
result.append((char) read);
read = in.read();
}
in.close();
return result;
}
public static byte[] readInByteArray(InputStream in) throws IOException {
byte[] result = new byte[in.available()];
in.read(result);
in.close();
return result;
}
/**
* Copies all bytes from the given InputStream into an internal
* ByteArrayOutputStream and returnes a new InputStream with all bytes from
* the ByteArrayOutputStream. The data are real copied so this method
* "clones" the given Inputstream and returns a new InputStream with same
* data.
*
* @param from
* InputStream from which all data are to copy
* @return a new InputStream with all data from the given InputStream
* @throws IOException
*/
public static InputStream streamClone(InputStream from) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
streamCopy(from, out);
return new ByteArrayInputStream(out.toByteArray());
}
}
Various utility methods that have something to do with I/O
/**
* The utillib library.
* More information is available at http://www.jinchess.ru/.
* Copyright (C) 2002 Alexander Maryanovsky.
* All rights reserved.
*
* The utillib library is free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The utillib library is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with utillib library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.Properties;
/**
* Various utility methods that have something to do with I/O.
*/
public class IOUtilities{
/**
* Maps URLs to byte arrays of the data loaded from them.
*/
private final static Hashtable urlCache = new Hashtable();
/**
* Returns a DataOutputStream object based on the given OutputStream.
* If the given OutputStream is already an instance of DataOutputStream,
* the same (given) OutputStream is casted to DataOutputStream and returned,
* otherwise, a new wrapper DataOutputStream is created and returned.
*/
public static DataOutputStream maybeCreateDataOutputStream(OutputStream out){
if (out instanceof DataOutputStream)
return (DataOutputStream)out;
else
return new DataOutputStream(out);
}
/**
* Returns a DataInputStream object based on the given InputStream.
* If the given InputStream is already an instance of DataInputStream,
* the same (given) InputStream is casted to DataInputStream and returned,
* otherwise, a new wrapper DataInputStream is created and returned.
*/
public static DataInputStream maybeCreateDataInputStream(InputStream in){
if (in instanceof DataInputStream)
return (DataInputStream)in;
else
return new DataInputStream(in);
}
/**
* Copies all the files of the given source directory into the given
* destination directory, optionally recursively.
*/
public static void copyDir(File source, File destination, boolean recurse) throws IOException{
if (!source.exists())
throw new IllegalArgumentException("The source directory ("+source+") doesn"t exist");
if (!source.isDirectory())
throw new IllegalArgumentException("The source ("+source+") is a file, not a directory");
if (!destination.exists())
throw new IllegalArgumentException("The destination directory ("+destination+") doesn"t exist");
if (!destination.isDirectory())
throw new IllegalArgumentException("The destination ("+destination+") is a file, not a directory");
String [] filenames = source.list();
for (int i=0; i<filenames.length; i++){
String filename = filenames[i];
File file = new File(source, filename);
if (file.isDirectory()){
if (recurse){
File destSubDir = new File(destination, filename);
if (!destSubDir.exists())
if (!destSubDir.mkdirs())
throw new IOException("Unable to create directory "+destSubDir);
copyDir(file, destSubDir, true);
}
}
else{
InputStream in = null;
OutputStream out = null;
try{
in = new FileInputStream(file);
out = new FileOutputStream(new File(destination, filename));
pump(in, out);
} finally{
if (in!=null)
in.close();
if (out!=null)
out.close();
}
}
}
}
/**
* Removes the given directory and all files within it, recursively. Returns
* <code>true</code> if successful, <code>false</code> otherwise. Note that if
* it return <code>false</code>, some (or all) the files in the directory may
* already be deleted.
*/
public static boolean rmdir(File dir){
if (!dir.isDirectory())
throw new IllegalArgumentException();
String [] filenames = dir.list();
for (int i = 0; i < filenames.length; i++){
File file = new File(dir, filenames[i]);
if (file.isDirectory()){
if (!rmdir(file))
return false;
}
else if (!file.delete())
return false;
}
return dir.delete();
}
/**
* Writes the bytes read from the given input stream into the given output
* stream until the end of the input stream is reached. Returns the amount of
* bytes actually read/written.
*/
public static int pump(InputStream in, OutputStream out) throws IOException{
return pump(in, out, new byte[2048]);
}
/**
* Writes up to the given amount of bytes read from the given input stream
* into the given output stream until the end of the input stream is reached.
* Returns the amount of bytes actually read/written.
*/
public static int pump(InputStream in, OutputStream out, int amount) throws IOException{
return pump(in, out, amount, new byte[2048]);
}
/**
* Writes the bytes read from the given input stream into the given output
* stream until the end of the input stream is reached. Returns the amount of
* bytes actually read/written. Uses the given byte array as the buffer.
*/
public static int pump(InputStream in, OutputStream out, byte [] buf) throws IOException{
if (buf.length==0)
throw new IllegalArgumentException("Cannot use a 0 length buffer");
int count;
int amountRead = 0;
while ((count = in.read(buf))!=-1){
out.write(buf,0,count);
amountRead += count;
}
return amountRead;
}
/**
* Writes up to the given amount of bytes read from the given input stream
* into the given output stream until the end of the input stream is reached.
* Returns the amount of bytes actually read/written. Uses the given byte array
* as the buffer.
*/
public static int pump(InputStream in, OutputStream out, int amount, byte [] buf) throws IOException{
if (buf.length == 0)
throw new IllegalArgumentException("Cannot use a 0 length buffer");
int amountRead = 0;
while (amount > 0){
int amountToRead = amount > buf.length ? buf.length : amount;
int count = in.read(buf, 0, amountToRead);
if (count==-1)
break;
out.write(buf,0,count);
amount -= count;
amountRead += count;
}
return amountRead;
}
/**
* Reads from the given InputStream until its end and returns a byte array
* of the contents. The input stream is not <code>close</code>d by this
* method.
*/
public static byte [] readToEnd(InputStream in) throws IOException{
byte [] buf = new byte[2048];
int amountRead = 0;
int count = 0;
while ((count = in.read(buf, amountRead, buf.length-amountRead)) > 0){
amountRead += count;
if (amountRead == buf.length){
byte [] oldBuf = buf;
buf = new byte[oldBuf.length*2];
System.arraycopy(oldBuf, 0, buf, 0, amountRead);
}
}
byte [] arr = new byte[amountRead];
System.arraycopy(buf, 0, arr, 0, amountRead);
return arr;
}
/**
* Reads the specified amount of bytes from the specified input stream and
* returns the resulting array. Throws an <code>EOFException</code> if the
* stream ends before the specified amount of bytes is read.
*/
public static byte [] read(InputStream in, int amount) throws IOException{
ByteArrayOutputStream buf = new ByteArrayOutputStream(amount);
if (pump(in, buf, amount) != amount)
throw new EOFException();
return buf.toByteArray();
}
/**
* Loads and returns data from the specified URL.
*/
public static byte [] load(URL url, boolean allowCache) throws IOException{
InputStream in = inputStreamForURL(url, allowCache);
try{
return readToEnd(in);
} finally{
try{
in.close();
} catch (IOException e){}
}
}
/**
* Reads all the information from the given InputStream and returns it as
* plain text by using the default system encoding. Note that this method
* doesn"t close the given InputStream, that is left to the user.
*/
public static String loadText(InputStream in) throws IOException{
return new String(readToEnd(in));
}
/**
* Loads the text from the given URL and returns it as a string.
*
* @throws IOException if the given URL does not exist or an I/O error occurs
* while accessing it.
*/
public static String loadText(URL url, boolean allowCache) throws IOException{
return new String(load(url, allowCache));
}
/**
* Loads the given text file from the local drive, converts it to a String and
* returns the String.
*
* @throws IOException if the file does not exist or loading failed.
*/
public static String loadTextFile(File file) throws IOException{
if (!file.exists())
throw new IOException("File does not exist");
InputStream in = new FileInputStream(file);
String text = loadText(in);
in.close();
return text;
}
/**
* Loads a text file with the given name from the local drive, converts it to
* a String and returns the String.
*
* @throws IOException if the file does not exist or loading failed.
*/
public static String loadTextFile(String filename) throws IOException{
return loadTextFile(new File(filename));
}
/**
* Compares the 2 given sub arrays. Returns true if they are equal, false
* otherwise.
*
* @throws ArrayIndexOutOfBounds if
* <UL>
* <LI> <code>offset1</code> or <code>offset2</code> are negative.
* <LI> length is negative.
* <LI> <code>offset1+length</code> is bigger than <code>arr1.length</code>
* <LI> <code>offset2+length</code> is bigger than <code>arr2.length</code>
* </UL>
*/
public static boolean equal(byte [] arr1, int offset1, byte [] arr2, int offset2, int length){
if ((offset1<0)||(offset2<0)||(length<0)||(offset1+length>arr1.length)||(offset2+length>arr2.length))
throw new ArrayIndexOutOfBoundsException();
for (int i=0;i<length;i++){
if (arr1[offset1+i]!=arr2[offset2+i])
return false;
}
return true;
}
/**
* Returns a <code>URL</code> corresponding to the specified <code>File</code>
* or <code>null</code> if the <code>File</code> cannot be converted into a
* <code>URL</code>.
* NOTE: This is copied from the JDK1.3 source, File.java
*/
public static URL fileToURL(File file){
try{
String path = file.getAbsolutePath();
if (File.separatorChar != "/")
path = path.replace(File.separatorChar, "/");
if (!path.startsWith("/"))
path = "/" + path;
if (!path.endsWith("/") && file.isDirectory())
path = path + "/";
return new URL("file", "", path);
} catch (MalformedURLException e){
return null;
}
}
/**
* Creates and returns a new <code>java.util.Properties</code> object loaded
* from the specified <code>InputStream</code>.
*/
public static Properties loadProperties(InputStream in) throws IOException{
return loadProperties(in, new Properties());
}
/**
* Loads properties from the specified <code>InputStream</code> into the
* specified <code>Properties</code> object. Returns the passed
* <code>Properties</code> object.
*/
public static Properties loadProperties(InputStream in, Properties props) throws IOException{
if (in == null)
return null;
props.load(in);
return props;
}
/**
* Similar to the {@link #loadProperties(InputStream)} method, but closes
* the specified <code>InputStream</code> at the end of its operation.
*/
public static Properties loadPropertiesAndClose(InputStream in) throws IOException{
return loadPropertiesAndClose(in, new Properties());
}
/**
* Similar to the {@link #loadProperties(InputStream, Properties)} method,
* but closes the specified <code>InputStream</code> at the end of its
* operation.
*/
public static Properties loadPropertiesAndClose(InputStream in, Properties props) throws IOException{
try{
return loadProperties(in, props);
} finally{
try{
in.close();
} catch (IOException e){}
}
}
/**
* Creates and returns a new <code>java.util.Properties</code> object loaded
* from the specified <code>File</code>.
*/
public static Properties loadProperties(File file) throws IOException{
return loadPropertiesAndClose(new FileInputStream(file));
}
/**
* Creates and returns a new <code>java.util.Properties</code> object loaded
* from the specified <code>URL</code>.
* <code>allowCache</code> specifies whether the data may be retrieved from
* the cache instead of being actually retrieved.
*/
public static Properties loadProperties(URL url, boolean allowCache) throws IOException{
return loadProperties(url, allowCache, new Properties());
}
/**
* Loads properties from the specified <code>URL</code> into the specified
* </code>Properties</code> object. Returns the passed
* <code>Properties</code> object.
* <code>allowCache</code> specifies whether the data may be retrieved from
* the cache instead of being actually retrieved.
*/
public static Properties loadProperties(URL url, boolean allowCache, Properties props) throws IOException{
return loadPropertiesAndClose(inputStreamForURL(url, allowCache), props);
}
/**
* Loads and caches the contents of the specified URL. Calls to any of the
* methods that load from URLs in this class will use the cached data. Calling
* this method with an already cached URL will cause it to be loaded again. If
* an <code>IOException</code> occurs while loading the data, the cache
* remains unchanged.
*/
public static void cacheURL(URL url) throws IOException{
cacheData(url, load(url, false));
}
/**
* Forces the data mapped to the specified URL to be the specified data.
* This method is useful when one part of an application wants to generate
* or specify data for another part.
*/
public static void cacheData(URL url, byte [] data){
urlCache.put(url, data);
}
/**
* Returns whether the specified URL is cached.
*/
public static boolean isURLCached(URL url){
return urlCache.containsKey(url);
}
/**
* Returns an <code>InpuStream</code> for reading the data at the specified
* URL. If <code>allowCache</code> is <code>true</code>, and the URL is cached,
* a <code>ByteArrayInpuStream</code> with the cached data is returned.
*/
public static InputStream inputStreamForURL(URL url, boolean allowCache) throws IOException{
byte [] cached = null;
if (allowCache)
cached = (byte [])urlCache.get(url);
return cached == null ? url.openStream() : new ByteArrayInputStream(cached);
}
/**
* Loads data from the specified URLs asynchronously in a background thread.
* Once all the data is loaded, it is passed to the specified
* <code>DataReceiver</code>. <code>id</code> is a convenience allowing the
* receiver to identify the data - it is merely passed back to the receiver.
*/
public static void loadAsynchronously(URL [] urls, Object id, DataReceiver receiver, boolean allowCache){
Thread asyncReader =
new Thread(new UrlDataReader((URL[])urls.clone(), id, receiver, allowCache),
"AsyncThread-" + (++UrlDataReader.threadCount));
asyncReader.setDaemon(true);
asyncReader.start();
}
/**
* Similar to <code>loadAsynchronously</code>, but returns only when all the
* data has been loaded and passed off to the receiver.
*/
public static void loadSynchronously(URL [] urls, Object id, DataReceiver receiver, boolean allowCache){
new UrlDataReader((URL[])urls.clone(), id, receiver, allowCache).run();
}
/**
* The callback interface for asynchronous reading of data.
*/
public static interface DataReceiver{
/**
* Gets called when all the data is loaded.
* The <code>IOException</code> array holds the exceptions thrown while
* loading. The indices in all the arrays correspond.
*/
void dataRead(URL [] urls, Object id, byte [][] data, IOException [] exceptions);
}
/**
* Reads data from URLs.
*/
private static class UrlDataReader implements Runnable{
/**
* The number of <code>Threads</code> running <code>UrlDataReader</code>s
* already created.
*/
public static int threadCount = 0;
/**
* The URLs to load data from.
*/
private final URL [] urls;
/**
* The identifier of this download.
*/
private final Object id;
/**
* The callback <code>DataReceiver</code>.
*/
private final DataReceiver receiver;
/**
* Whether it is allowed for the data to be retrieved from cache.
*/
private final boolean allowCache;
/**
* The data.
*/
private final byte [][] data;
/**
* The <code>IOExceptions</code> thrown while loading the data.
*/
private final IOException [] exceptions;
/**
* Creates a new <code>UrlDataReader</code> with the specified id, to load
* data from the specified URLs and report back to the specified
* <code>DataReceiver</code>.
*/
public UrlDataReader(URL [] urls, Object id, DataReceiver receiver, boolean allowCache){
this.urls = urls;
this.id = id;
this.receiver = receiver;
this.allowCache = allowCache;
this.data = new byte[urls.length][];
this.exceptions = new IOException[urls.length];
}
/**
* Reads the data and reports back to the receiver.
*/
public void run(){
for (int i = 0; i < urls.length; i++){
try{
data[i] = load(urls[i], allowCache);
} catch (IOException e){
exceptions[i] = e;
}
}
receiver.dataRead(urls, id, data, exceptions);
}
}
}