Java/File Input Output/Byte Read Write
Содержание
- 1 Binary Dump OutputStream
- 2 Buffered copying between source(InputStream, Reader, String and byte[]) and destinations (OutputStream, Writer, String and byte[]).
- 3 Byte Reader with FileInputStream
- 4 Byte Writer with FileOutputStream
- 5 Compare binary files
- 6 Convert 4 hex digits to an int, and return the number of converted bytes.
- 7 Count the number of bytes written to the output stream.
- 8 Get bytes from InputStream
- 9 Reads bytes available from one InputStream and returns these bytes in a byte array.
- 10 Write and read compressed forms of numbers to DataOutput and DataInput interfaces.
Binary Dump OutputStream
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2003 The Apache Software Foundation. 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.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation", "Tapestry"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* or "Tapestry", nor may "Apache" or "Tapestry" appear in their
* name, without prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS"" AND ANY EXPRESSED 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 TAPESTRY CONTRIBUTOR COMMUNITY
* 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.
*
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
/**
* A kind of super-formatter. It is sent a stream of binary data and
* formats it in a human-readable dump format which is forwarded to
* its output stream.
*
* <p>Currently, output is in hex though options to change that may
* be introduced.
*
* @author Howard Lewis Ship
* @version $Id: BinaryDumpOutputStream.java,v 1.1 2003/03/05 22:59:31 hlship Exp $
*
**/
public class BinaryDumpOutputStream extends OutputStream
{
private PrintWriter out;
private boolean locked = false;
private boolean showOffset = true;
private int bytesPerLine = 16;
private int spacingInterval = 4;
private char substituteChar = ".";
private String offsetSeperator = ": ";
private int offset = 0;
private int lineCount = 0;
private int bytesSinceSpace = 0;
private char[] ascii = null;
private boolean showAscii = true;
private String asciiBegin = " |";
private String asciiEnd = "|";
private static final char[] HEX =
{
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"a",
"b",
"c",
"d",
"e",
"f" };
/**
* Creates a <code>PrintWriter</code> for <code>System.out</code>.
*
**/
public BinaryDumpOutputStream()
{
this(new PrintWriter(System.out, true));
}
public BinaryDumpOutputStream(PrintWriter out)
{
this.out = out;
}
public BinaryDumpOutputStream(Writer out)
{
this.out = new PrintWriter(out);
}
public void close() throws IOException
{
if (out != null)
{
if (lineCount > 0)
finishFinalLine();
out.close();
}
out = null;
}
private void finishFinalLine()
{
// Since we only finish the final line after at least one byte has
// been written to it, we don"t need to worry about
// the offset.
while (lineCount < bytesPerLine)
{
// After every <n> bytes, emit a space.
if (spacingInterval > 0 && bytesSinceSpace == spacingInterval)
{
out.print(" ");
bytesSinceSpace = 0;
}
// Two spaces to substitute for the two hex digits.
out.print(" ");
if (showAscii)
ascii[lineCount] = " ";
lineCount++;
bytesSinceSpace++;
}
if (showAscii)
{
out.print(asciiBegin);
out.print(ascii);
out.print(asciiEnd);
}
out.println();
}
/**
* Forwards the <code>flush()</code> to the <code>PrintWriter</code>.
*
**/
public void flush() throws IOException
{
out.flush();
}
public String getAsciiBegin()
{
return asciiBegin;
}
public String getAsciiEnd()
{
return asciiEnd;
}
public int getBytesPerLine()
{
return bytesPerLine;
}
public String getOffsetSeperator()
{
return offsetSeperator;
}
public boolean getShowAscii()
{
return showAscii;
}
public char getSubstituteChar()
{
return substituteChar;
}
public void setAsciiBegin(String value)
{
if (locked)
throw new IllegalStateException();
asciiBegin = value;
}
public void setAsciiEnd(String value)
{
if (locked)
throw new IllegalStateException();
asciiEnd = value;
}
public void setBytesPerLine(int value)
{
if (locked)
throw new IllegalStateException();
bytesPerLine = value;
ascii = null;
}
public void setOffsetSeperator(String value)
{
if (locked)
throw new IllegalStateException();
offsetSeperator = value;
}
public void setShowAscii(boolean value)
{
if (locked)
throw new IllegalStateException();
showAscii = value;
}
/**
* Sets the character used in the ASCII dump that substitutes for characters
* outside the range of 32..126.
*
**/
public void setSubstituteChar(char value)
{
if (locked)
throw new IllegalStateException();
substituteChar = value;
}
public void write(int b) throws IOException
{
char letter;
if (showAscii && ascii == null)
ascii = new char[bytesPerLine];
// Prevent further customization after output starts being written.
locked = true;
if (lineCount == bytesPerLine)
{
if (showAscii)
{
out.print(asciiBegin);
out.print(ascii);
out.print(asciiEnd);
}
out.println();
bytesSinceSpace = 0;
lineCount = 0;
offset += bytesPerLine;
}
if (lineCount == 0 && showOffset)
{
writeHex(offset, 4);
out.print(offsetSeperator);
}
// After every <n> bytes, emit a space.
if (spacingInterval > 0 && bytesSinceSpace == spacingInterval)
{
out.print(" ");
bytesSinceSpace = 0;
}
writeHex(b, 2);
if (showAscii)
{
if (b < 32 | b > 127)
letter = substituteChar;
else
letter = (char) b;
ascii[lineCount] = letter;
}
lineCount++;
bytesSinceSpace++;
}
private void writeHex(int value, int digits)
{
int i;
int nybble;
for (i = 0; i < digits; i++)
{
nybble = (value >> 4 * (digits - i - 1)) & 0x0f;
out.print(HEX[nybble]);
}
}
}
Buffered copying between source(InputStream, Reader, String and byte[]) and destinations (OutputStream, Writer, String and byte[]).
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* 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.
*/
import java.io.ByteArrayInputStream;
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.Writer;
/**
* <p>
* This class provides static utility methods for 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.
* @throws IOException In case of an I/O problem
*/
public static void copy(InputStream input, Writer output, String encoding) throws IOException
{
InputStreamReader in = new InputStreamReader(input, encoding);
copy(in, output);
}
/**
* Serialize chars from a <code>Reader</code> to bytes on an
* <code>OutputStream</code>, and flush the <code>OutputStream</code>.
* @param input the <code>Reader</code> to read from
* @param output the <code>OutputStream</code> to write to
* @throws IOException In case of an I/O problem
*/
public static void copy(Reader input, OutputStream output) throws IOException
{
OutputStreamWriter out = new OutputStreamWriter(output);
copy(input, out);
// XXX Unless anyone is planning on rewriting OutputStreamWriter, we have to flush here.
out.flush();
}
/**
* Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
* flush the <code>OutputStream</code>.
* @param input the <code>String</code> to read from
* @param output the <code>OutputStream</code> to write to
* @throws IOException In case of an I/O problem
*/
public static void copy(String input, OutputStream output) throws IOException
{
StringReader in = new StringReader(input);
OutputStreamWriter out = new OutputStreamWriter(output);
copy(in, out);
// XXX Unless anyone is planning on rewriting OutputStreamWriter, we have to flush here.
out.flush();
}
/**
* Copy chars from a <code>String</code> to a <code>Writer</code>.
* @param input the <code>String</code> to read from
* @param output the <code>Writer</code> to write to
* @throws IOException In case of an I/O problem
*/
public static void copy(String input, Writer output) throws IOException
{
output.write(input);
}
/**
* The name says it all.
*/
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
}
Byte Reader with FileInputStream
import java.io.FileInputStream;
import java.io.IOException;
public class ByteReader {
public static void main(String[] arguments) {
try {
FileInputStream file = new FileInputStream("class.dat");
boolean eof = false;
int count = 0;
while (!eof) {
int input = file.read();
System.out.print(input + " ");
if (input == -1)
eof = true;
else
count++;
}
file.close();
System.out.println("\nBytes read: " + count);
} catch (IOException e) {
System.out.println("Error - " + e.toString());
}
}
}
Byte Writer with FileOutputStream
import java.io.FileOutputStream;
import java.io.IOException;
public class ByteWriter {
public static void main(String[] arguments) {
int[] data = { 137, 89, 82, 181, 50, 220, 103, 20, 0, 59 };
try {
FileOutputStream file = new FileOutputStream("pic.dat");
for (int i = 0; i < data.length; i++)
file.write(data[i]);
file.close();
} catch (IOException e) {
System.out.println("Error - " + e.toString());
}
}
}
Compare binary files
/**
* Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
*
* Project: OpenSubsystems
*
* $Id: FileUtils.java,v 1.12 2007/02/01 07:18:32 bastafidli Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
/**
* Collection of methods to make work with files easier.
*
* @version $Id: FileUtils.java,v 1.12 2007/02/01 07:18:32 bastafidli Exp $
* @author Miro Halas
* @code.reviewer Miro Halas
* @code.reviewed 1.7 2006/05/21 03:45:37 bastafidli
*/
public class FileUtils
{
// Configuration settings ///////////////////////////////////////////////////
/**
* Default 10 digit file storage distribution array. This means that if I
* want to name file as 10 digit number e.g. number 123 as 0000000123 or
* number 123456789 as 01234567890. Then the path constructed from number
* 1234567890 using distribution 2/2/2/4 would be 12/34/56/0123456789
*/
public static final int[] DEFAULT_STRORAGE_TREE_DISTRIBUTION = {2, 2, 2, 4};
/**
* How big buffer to use to process files.
*/
public static final int BUFFER_SIZE = 65536;
// Cached values ////////////////////////////////////////////////////////////
/**
* Temporary directory to use. It is guarantee that it ends with \ (or /)
*/
protected static String s_strTempDirectory;
// Constructors /////////////////////////////////////////////////////////////
/**
* Move file to a new location. If the destination is on different volume,
* this file will be copied and then original file will be deleted.
* If the destination already exists, this method renames it with different
* name and leaves it in that directory and moves the new file along side
* the renamed one.
*
* @param flCurrent - file to move
* @param flDestination - destination file
* @throws IOException - error message
* @throws OSSException - error message
*/
public static void moveFile(
File flCurrent,
File flDestination
) throws IOException
{
// Make sure that the source exist, it might be already moved from
// a directory and we just don"t know about it
if (flCurrent.exists())
{
// Next check if the destination file exists
if (flDestination.exists())
{
// If the destination exists, that means something went wrong
// Rename the destination file under temporaty name and try to
// move the new file instead of it
renameToTemporaryName(flDestination, "old");
}
// Make sure the directory exists and if not create it
File flFolder;
flFolder = flDestination.getParentFile();
if ((flFolder != null) && (!flFolder.exists()))
{
if (!flFolder.mkdirs())
{
// Do not throw the exception if the directory already exists
// because it was created meanwhile for example by a different
// thread
if (!flFolder.exists())
{
throw new IOException("Cannot create directory " + flFolder);
}
}
}
// Now everything should exist so try to rename the file first
// After testing, this renames files even between volumes C to H
// so we don"t have to do anything else on Windows but we still
// have to handle erro on Unix
if (!flCurrent.renameTo(flDestination))
{
// Try to copy and delete since the rename doesn"t work on Solaris
// between file systems
copyFile(flCurrent, flDestination);
// Now delete the file
if (!flCurrent.delete())
{
// Delete the destination file first since we haven"t really moved
// the file
flDestination.delete();
throw new IOException("Cannot delete already copied file " + flCurrent);
}
}
}
}
/**
* Copy the current file to the destination file.
*
* @param flCurrent - source file
* @param flDestination - destination file
* @throws IOException - error message
* @throws OSSException - error message
*/
public static void copyFile(
File flCurrent,
File flDestination
) throws IOException
{
// Make sure the directory exists and if not create it
File flFolder;
flFolder = flDestination.getParentFile();
if ((flFolder != null) && (!flFolder.exists()))
{
if (!flFolder.mkdirs())
{
// Do not throw the exception if the directory already exists
// because it was created meanwhile for example by a different
// thread
if (!flFolder.exists())
{
throw new IOException("Cannot create directory " + flFolder);
}
}
}
// FileChannel srcChannel = null;
// FileChannel dstChannel = null;
FileInputStream finInput = null;
//MHALAS: This code is not working reliably on Solaris 8 with 1.4.1_01
// Getting exceptions from native code
/*
// Create channel on the source
srcChannel = new FileInputStream(flCurrent).getChannel();
// Create channel on the destination
dstChannel = new FileOutputStream(flDestination).getChannel();
// Copy file contents from source to destination
dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
Don"t forget to close the channels if you enable this code again
*/
try
{
finInput = new FileInputStream(flCurrent);
}
catch (IOException ioExec)
{
if (finInput != null)
{
try
{
finInput.close();
}
catch (Throwable thr)
{
}
}
throw ioExec;
}
FileUtils.copyStreamToFile(finInput, flDestination);
}
/**
* Rename the file to temporaty name with given prefix
*
* @param flFileToRename - file to rename
* @param strPrefix - prefix to use
* @throws IOException - error message
*/
public static void renameToTemporaryName(
File flFileToRename,
String strPrefix
) throws IOException
{
assert strPrefix != null : "Prefix cannot be null.";
String strParent;
StringBuffer sbBuffer = new StringBuffer();
File flTemp;
int iIndex = 0;
strParent = flFileToRename.getParent();
// Generate new name for the file in a deterministic way
do
{
iIndex++;
sbBuffer.delete(0, sbBuffer.length());
if (strParent != null)
{
sbBuffer.append(strParent);
sbBuffer.append(File.separatorChar);
}
sbBuffer.append(strPrefix);
sbBuffer.append("_");
sbBuffer.append(iIndex);
sbBuffer.append("_");
sbBuffer.append(flFileToRename.getName());
flTemp = new File(sbBuffer.toString());
}
while (flTemp.exists());
// Now we should have unique name
if (!flFileToRename.renameTo(flTemp))
{
throw new IOException("Cannot rename " + flFileToRename.getAbsolutePath()
+ " to " + flTemp.getAbsolutePath());
}
}
/**
* Delete all files and directories in directory but do not delete the
* directory itself.
*
* @param strDir - string that specifies directory to delete
* @return boolean - sucess flag
*/
public static boolean deleteDirectoryContent(
String strDir
)
{
return ((strDir != null) && (strDir.length() > 0))
? deleteDirectoryContent(new File(strDir)) : false;
}
/**
* Delete all files and directories in directory but do not delete the
* directory itself.
*
* @param fDir - directory to delete
* @return boolean - sucess flag
*/
public static boolean deleteDirectoryContent(
File fDir
)
{
boolean bRetval = false;
if (fDir != null && fDir.isDirectory())
{
File[] files = fDir.listFiles();
if (files != null)
{
bRetval = true;
boolean dirDeleted;
for (int index = 0; index < files.length; index++)
{
if (files[index].isDirectory())
{
// TODO: Performance: Implement this as a queue where you add to
// the end and take from the beginning, it will be more efficient
// than the recursion
dirDeleted = deleteDirectoryContent(files[index]);
if (dirDeleted)
{
bRetval = bRetval && files[index].delete();
}
else
{
bRetval = false;
}
}
else
{
bRetval = bRetval && files[index].delete();
}
}
}
}
return bRetval;
}
/**
* Deletes all files and subdirectories under the specified directory including
* the specified directory
*
* @param strDir - string that specifies directory to be deleted
* @return boolean - true if directory was successfully deleted
*/
public static boolean deleteDir(
String strDir
)
{
return ((strDir != null) && (strDir.length() > 0))
? deleteDir(new File(strDir)) : false;
}
/**
* Deletes all files and subdirectories under the specified directory including
* the specified directory
*
* @param fDir - directory to be deleted
* @return boolean - true if directory was successfully deleted
*/
public static boolean deleteDir(
File fDir
)
{
boolean bRetval = false;
if (fDir != null && fDir.exists())
{
bRetval = deleteDirectoryContent(fDir);
if (bRetval)
{
bRetval = bRetval && fDir.delete();
}
}
return bRetval;
}
/**
* Compare binary files. Both files must be files (not directories) and exist.
*
* @param first - first file
* @param second - second file
* @return boolean - true if files are binery equal
* @throws IOException - error in function
*/
public boolean isFileBinaryEqual(
File first,
File second
) throws IOException
{
// TODO: Test: Missing test
boolean retval = false;
if ((first.exists()) && (second.exists())
&& (first.isFile()) && (second.isFile()))
{
if (first.getCanonicalPath().equals(second.getCanonicalPath()))
{
retval = true;
}
else
{
FileInputStream firstInput = null;
FileInputStream secondInput = null;
BufferedInputStream bufFirstInput = null;
BufferedInputStream bufSecondInput = null;
try
{
firstInput = new FileInputStream(first);
secondInput = new FileInputStream(second);
bufFirstInput = new BufferedInputStream(firstInput, BUFFER_SIZE);
bufSecondInput = new BufferedInputStream(secondInput, BUFFER_SIZE);
int firstByte;
int secondByte;
while (true)
{
firstByte = bufFirstInput.read();
secondByte = bufSecondInput.read();
if (firstByte != secondByte)
{
break;
}
if ((firstByte < 0) && (secondByte < 0))
{
retval = true;
break;
}
}
}
finally
{
try
{
if (bufFirstInput != null)
{
bufFirstInput.close();
}
}
finally
{
if (bufSecondInput != null)
{
bufSecondInput.close();
}
}
}
}
}
return retval;
}
/**
* Get path which represents temporary directory. It is guarantee that it
* ends with \ (or /).
*
* @return String
*/
public static String getTemporaryDirectory(
)
{
return s_strTempDirectory;
}
/**
* Copy any input stream to output file. Once the data will be copied
* the stream will be closed.
*
* @param input - InputStream to copy from
* @param output - File to copy to
* @throws IOException - error in function
* @throws OSSMultiException - double error in function
*/
public static void copyStreamToFile(
InputStream input,
File output
) throws IOException
{
FileOutputStream foutOutput = null;
// open input file as stream safe - it can throw some IOException
try
{
foutOutput = new FileOutputStream(output);
}
catch (IOException ioExec)
{
if (foutOutput != null)
{
try
{
foutOutput.close();
}
catch (IOException ioExec2)
{
}
}
throw ioExec;
}
// all streams including os are closed in copyStreamToStream function
// in any case
copyStreamToStream(input, foutOutput);
}
/**
* Copy any input stream to output stream. Once the data will be copied
* both streams will be closed.
*
* @param input - InputStream to copy from
* @param output - OutputStream to copy to
* @throws IOException - io error in function
* @throws OSSMultiException - double error in function
*/
public static void copyStreamToStream(
InputStream input,
OutputStream output
) throws IOException
{
InputStream is = null;
OutputStream os = null;
int ch;
try
{
if (input instanceof BufferedInputStream)
{
is = input;
}
else
{
is = new BufferedInputStream(input);
}
if (output instanceof BufferedOutputStream)
{
os = output;
}
else
{
os = new BufferedOutputStream(output);
}
while ((ch = is.read()) != -1)
{
os.write(ch);
}
os.flush();
}
finally
{
IOException exec1 = null;
IOException exec2 = null;
try
{
// because this close can throw exception we do next close in
// finally statement
if (os != null)
{
try
{
os.close();
}
catch (IOException exec)
{
exec1 = exec;
}
}
}
finally
{
if (is != null)
{
try
{
is.close();
}
catch (IOException exec)
{
exec2 = exec;
}
}
}
if ((exec1 != null) && (exec2 != null))
{
throw exec1;
}
else if (exec1 != null)
{
throw exec1;
}
else if (exec2 != null)
{
throw exec2;
}
}
}
}
Convert 4 hex digits to an int, and return the number of converted bytes.
/*
* 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;
/**
* Library of utility methods useful in dealing with converting byte arrays to
* and from strings of hexadecimal digits.
*
* @author Craig R. McClanahan
*/
public final class HexUtils {
// Code from Ajp11, from Apache"s JServ
// Table for HEX to DEC byte translation
public static final int[] DEC = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 00, 01, 02, 03, 04, 05, 06, 07, 8, 9, -1, -1, -1, -1, -1,
-1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, };
/**
* Convert 4 hex digits to an int, and return the number of converted bytes.
*
* @param hex
* Byte array containing exactly four hexadecimal digits
*
* @exception IllegalArgumentException
* if an invalid hexadecimal digit is included
*/
public static int convert2Int(byte[] hex) {
// Code from Ajp11, from Apache"s JServ
// assert b.length==4
// assert valid data
int len;
if (hex.length < 4)
return 0;
if (DEC[hex[0]] < 0)
throw new IllegalArgumentException("hexUtil.bad");
len = DEC[hex[0]];
len = len << 4;
if (DEC[hex[1]] < 0)
throw new IllegalArgumentException("hexUtil.bad");
len += DEC[hex[1]];
len = len << 4;
if (DEC[hex[2]] < 0)
throw new IllegalArgumentException("hexUtil.bad");
len += DEC[hex[2]];
len = len << 4;
if (DEC[hex[3]] < 0)
throw new IllegalArgumentException("hexUtil.bad");
len += DEC[hex[3]];
return len;
}
}
Count the number of bytes written to the output stream.
/*
* 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.
*/
//Revised from Apache cocoon
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* This class is like the {@link java.io.BufferedOutputStream} but it
* extends it with a logic to count the number of bytes written to
* the output stream.
*
* @version $Id: BufferedOutputStream.java 587751 2007-10-24 02:41:36Z vgritsenko $
* @since 2.1
*/
public final class BufferedOutputStream extends FilterOutputStream {
protected byte buf[];
protected int count;
/**
* Creates a new buffered output stream to write data to the
* specified underlying output stream with a default 8192-byte
* buffer size.
*
* @param out the underlying output stream.
*/
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}
/**
* Creates a new buffered output stream to write data to the
* specified underlying output stream with the specified buffer
* size.
*
* @param out the underlying output stream.
* @param size the buffer size.
* @exception IllegalArgumentException if size <= 0.
*/
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
this.buf = new byte[size];
}
/**
* Writes the specified byte to this buffered output stream.
*
* @param b the byte to be written.
* @exception IOException if an I/O error occurs.
*/
public void write(int b) throws IOException {
if (this.count >= this.buf.length) {
this.incBuffer();
}
this.buf[count++] = (byte)b;
}
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this buffered output stream.
*
* <p> Ordinarily this method stores bytes from the given array into this
* stream"s buffer, flushing the buffer to the underlying output stream as
* needed. If the requested length is at least as large as this stream"s
* buffer, however, then this method will flush the buffer and write the
* bytes directly to the underlying output stream. Thus redundant
* <code>BufferedOutputStream</code>s will not copy data unnecessarily.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @exception IOException if an I/O error occurs.
*/
public void write(byte b[], int off, int len) throws IOException {
while (len > buf.length - count) {
this.incBuffer();
}
System.arraycopy(b, off, buf, count, len);
count += len;
}
/**
* Flushes this buffered output stream.
* We don"t flush here, flushing is done during closing.
*
* @exception IOException if an I/O error occurs.
*/
public void flush() throws IOException {
// nothing
}
/**
* Closes this buffered output stream.
* Flush before closing.
*
* @exception IOException if an I/O error occurs.
*/
public void close() throws IOException {
realFlush();
super.close ();
}
/**
* Flushes this buffered output stream.
*/
public void realFlush() throws IOException {
this.writeBuffer();
this.out.flush();
}
/**
* Write the buffer
*/
private void writeBuffer()
throws IOException {
if (this.count > 0) {
this.out.write(this.buf, 0, this.count);
this.clearBuffer();
}
}
/**
* Increment the buffer
*/
private void incBuffer() {
// currently we double the buffer size
// this is not so fast but is a very simple logic
byte[] newBuf = new byte[this.buf.length * 2];
System.arraycopy(this.buf, 0, newBuf, 0, this.buf.length);
this.buf = newBuf;
}
/**
* Clear/reset the buffer
*/
public void clearBuffer() {
this.count = 0;
}
/**
* Return the size of the current buffer
*/
public int getCount() {
return this.count;
}
}
Get bytes from InputStream
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the "License"). You may not use this file except
* in compliance with the License.
*
* You can obtain a copy of the license at
* glassfish/bootstrap/legal/CDDLv1.0.txt or
* https://glassfish.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* HEADER in each file and include the License file at
* glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
* add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your
* own identifying information: Portions Copyright [yyyy]
* [name of copyright owner]
*/
/*
* @(#)ASCIIUtility.java 1.10 05/08/29
*
* Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
*/
public class Utils {
public static byte[] getBytes(InputStream is) throws IOException {
int len;
int size = 1024;
byte[] buf;
if (is instanceof ByteArrayInputStream) {
size = is.available();
buf = new byte[size];
len = is.read(buf, 0, size);
} else {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
buf = new byte[size];
while ((len = is.read(buf, 0, size)) != -1)
bos.write(buf, 0, len);
buf = bos.toByteArray();
}
return buf;
}
}
Reads bytes available from one InputStream and returns these bytes in a byte array.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Main {
/**
*
* @param in The InputStream to read the bytes from.
* @return A byte array containing the bytes that were read.
* @throws IOException If I/O error occurred.
*/
public static final byte[] readFully(InputStream in)
throws IOException
{
ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
transfer(in, out);
out.close();
return out.toByteArray();
}
/**
* Transfers all bytes that can be read from <tt>in</tt> to <tt>out</tt>.
*
* @param in The InputStream to read data from.
* @param out The OutputStream to write data to.
* @return The total number of bytes transfered.
*/
public static final long transfer(InputStream in, OutputStream out)
throws IOException
{
long totalBytes = 0;
int bytesInBuf = 0;
byte[] buf = new byte[4096];
while ((bytesInBuf = in.read(buf)) != -1) {
out.write(buf, 0, bytesInBuf);
totalBytes += bytesInBuf;
}
return totalBytes;
}
}
Write and read compressed forms of numbers to DataOutput and DataInput interfaces.
/*
Derby - Class org.apache.derby.iapi.services.io.rupressedNumber
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.DataInput;
import java.io.DataOutput;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Static methods to write and read compressed forms of numbers to DataOut and
* DataIn interfaces. Format written is platform independent like the Data*
* interfaces and must remain fixed once a product is shipped. If a different
* format is required then write a new set of methods, e.g. writeInt2. The
* formats defined by stored format identifiers are implicitly dependent on
* these formats not changing.
*/
public abstract class CompressedNumber {
// the maximum number of bytes written out for an int
public static final int MAX_INT_STORED_SIZE = 4;
// the maximum number of bytes written out for a long
public static final int MAX_LONG_STORED_SIZE = 8;
// largest int stored compressed in 1 byte
public static final int MAX_COMPRESSED_INT_ONE_BYTE = 0x3f;
// largest int stored compressed in 2 bytes
public static final int MAX_COMPRESSED_INT_TWO_BYTES = 0x3fff;
/**
* Write a compressed integer only supporting signed values. Formats are (with
* x representing value bits):
*
* <PRE>
*
* 1 Byte - 00xxxxxx Represents the value <= 63 (0x3f) 2 Byte - 01xxxxxx
* xxxxxxxx Represents the value > 63 && <= 16383 (0x3fff) 4 byte - 1xxxxxxx
* xxxxxxxx xxxxxxxx xxxxxxxx Represents the value > 16383 && <= MAX_INT
*
* </PRE>
*
*
* @exception IOException
* value is negative or an exception was thrown by a method on
* out.
*/
public static final int writeInt(DataOutput out, int value) throws IOException {
if (value < 0)
throw new IOException();
if (value <= 0x3f) {
out.writeByte(value);
return 1;
}
if (value <= 0x3fff) {
out.writeByte(0x40 | (value >>> 8));
out.writeByte(value & 0xff);
return 2;
}
out.writeByte(((value >>> 24) | 0x80) & 0xff);
out.writeByte((value >>> 16) & 0xff);
out.writeByte((value >>> 8) & 0xff);
out.writeByte((value) & 0xff);
return 4;
}
/**
* Write a compressed integer directly to an OutputStream.
*
* @exception IOException
* an exception was thrown by a method on in.
*/
public static final int writeInt(OutputStream out, int value) throws IOException {
if (value < 0)
throw new IOException();
if (value <= 0x3f) {
out.write(value);
return 1;
}
if (value <= 0x3fff) {
out.write(0x40 | (value >>> 8));
out.write(value & 0xff);
return 2;
}
out.write(((value >>> 24) | 0x80) & 0xff);
out.write((value >>> 16) & 0xff);
out.write((value >>> 8) & 0xff);
out.write((value) & 0xff);
return 4;
}
/**
* Read an integer previously written by writeInt().
*
* @exception IOException
* an exception was thrown by a method on in.
*/
public static final int readInt(DataInput in) throws IOException {
int value = in.readUnsignedByte();
if ((value & ~0x3f) == 0) {
// length is stored in this byte, we also know that the 0x80 bit
// was not set, so no need to mask off the sign extension from
// the byte to int conversion.
// account for 1 byte stored length of field + 1 for all returns
return (value);
} else if ((value & 0x80) == 0) {
// length is stored in 2 bytes. only use low 6 bits from 1st byte.
// top 8 bits of 2 byte length is stored in this byte, we also
// know that the 0x80 bit was not set, so no need to mask off the
// sign extension from the 1st byte to int conversion. Need to
// mask the byte in data[offset + 1] to account for possible sign
// extension.
return (((value & 0x3f) << 8) | in.readUnsignedByte());
} else {
// top 8 bits of 4 byte length is stored in this byte, we also
// know that the 0x80 bit was set, so need to mask off the
// sign extension from the 1st byte to int conversion. Need to
// mask the bytes from the next 3 bytes data[offset + 1,2,3] to
// account for possible sign extension.
//
return (((value & 0x7f) << 24) | (in.readUnsignedByte() << 16) | (in.readUnsignedByte() << 8) | (in
.readUnsignedByte()));
}
}
/**
* Read an integer previously written by writeInt().
*
* @exception IOException
* an exception was thrown by a method on in.
*/
public static final int readInt(InputStream in) throws IOException {
int value = InputStreamUtil.readUnsignedByte(in);
if ((value & ~0x3f) == 0) {
return (value);
} else if ((value & 0x80) == 0) {
return (((value & 0x3f) << 8) | InputStreamUtil.readUnsignedByte(in));
} else {
return (((value & 0x7f) << 24) | (InputStreamUtil.readUnsignedByte(in) << 16)
| (InputStreamUtil.readUnsignedByte(in) << 8) | (InputStreamUtil.readUnsignedByte(in)));
}
}
public static final int readInt(byte[] data, int offset) {
int value = data[offset++];
if ((value & ~0x3f) == 0) {
// length is stored in this byte, we also know that the 0x80 bit
// was not set, so no need to mask off the sign extension from
// the byte to int conversion.
return (value);
} else if ((value & 0x80) == 0) {
// length is stored in 2 bytes. only use low 6 bits from 1st byte.
// top 8 bits of 2 byte length is stored in this byte, we also
// know that the 0x80 bit was not set, so no need to mask off the
// sign extension from the 1st byte to int conversion. Need to
// mask the byte in data[offset + 1] to account for possible sign
// extension.
return (((value & 0x3f) << 8) | (data[offset] & 0xff));
} else {
// top 8 bits of 4 byte length is stored in this byte, we also
// know that the 0x80 bit was set, so need to mask off the
// sign extension from the 1st byte to int conversion. Need to
// mask the bytes from the next 3 bytes data[offset + 1,2,3] to
// account for possible sign extension.
//
return (((value & 0x7f) << 24) | ((data[offset++] & 0xff) << 16)
| ((data[offset++] & 0xff) << 8) | ((data[offset] & 0xff)));
}
}
/**
* Skip an integer previously written by writeInt().
*
* @exception IOException
* an exception was thrown by a method on in.
*/
/**
* Return the number of bytes that would be written by a writeInt call
*/
public static final int sizeInt(int value) {
if (value <= 0x3f) {
return 1;
}
if (value <= 0x3fff) {
return 2;
}
return 4;
}
/**
* Write a compressed long only supporting signed values.
*
* Formats are (with x representing value bits):
*
* <PRE>
*
* 2 byte - 00xxxxxx xxxxxxxx Represents the value <= 16383 (0x3fff) 4 byte -
* 01xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Represents the value > 16383 && <=
* 0x3fffffff 8 byte - 1xxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
* xxxxxxxx xxxxxxxx Represents the value > 0x3fffffff && <= MAX_LONG
*
* </PRE>
*
*
* @exception IOException
* value is negative or an exception was thrown by a method on
* out.
*/
public static final int writeLong(DataOutput out, long value) throws IOException {
if (value < 0)
throw new IOException();
if (value <= 0x3fff) {
out.writeByte((int) ((value >>> 8) & 0xff));
out.writeByte((int) ((value) & 0xff));
return 2;
}
if (value <= 0x3fffffff) {
out.writeByte((int) (((value >>> 24) | 0x40) & 0xff));
out.writeByte((int) ((value >>> 16) & 0xff));
out.writeByte((int) ((value >>> 8) & 0xff));
out.writeByte((int) ((value) & 0xff));
return 4;
}
out.writeByte((int) (((value >>> 56) | 0x80) & 0xff));
out.writeByte((int) ((value >>> 48) & 0xff));
out.writeByte((int) ((value >>> 40) & 0xff));
out.writeByte((int) ((value >>> 32) & 0xff));
out.writeByte((int) ((value >>> 24) & 0xff));
out.writeByte((int) ((value >>> 16) & 0xff));
out.writeByte((int) ((value >>> 8) & 0xff));
out.writeByte((int) ((value) & 0xff));
return 8;
}
/**
* Write a compressed integer only supporting signed values.
*
* @exception IOException
* value is negative or an exception was thrown by a method on
* out.
*/
public static final int writeLong(OutputStream out, long value) throws IOException {
if (value < 0)
throw new IOException();
if (value <= 0x3fff) {
out.write((int) ((value >>> 8) & 0xff));
out.write((int) ((value) & 0xff));
return 2;
}
if (value <= 0x3fffffff) {
out.write((int) (((value >>> 24) | 0x40) & 0xff));
out.write((int) ((value >>> 16) & 0xff));
out.write((int) ((value >>> 8) & 0xff));
out.write((int) ((value) & 0xff));
return 4;
}
out.write((int) (((value >>> 56) | 0x80) & 0xff));
out.write((int) ((value >>> 48) & 0xff));
out.write((int) ((value >>> 40) & 0xff));
out.write((int) ((value >>> 32) & 0xff));
out.write((int) ((value >>> 24) & 0xff));
out.write((int) ((value >>> 16) & 0xff));
out.write((int) ((value >>> 8) & 0xff));
out.write((int) ((value) & 0xff));
return 8;
}
/**
* Read a long previously written by writeLong().
*
* @exception IOException
* an exception was thrown by a method on in.
*/
public static final long readLong(DataInput in) throws IOException {
int int_value = in.readUnsignedByte();
if ((int_value & ~0x3f) == 0) {
// test for small case first - assuming this is usual case.
// this is stored in 2 bytes.
return ((int_value << 8) | in.readUnsignedByte());
} else if ((int_value & 0x80) == 0) {
// value is stored in 4 bytes. only use low 6 bits from 1st byte.
return (((int_value & 0x3f) << 24) | (in.readUnsignedByte() << 16)
| (in.readUnsignedByte() << 8) | (in.readUnsignedByte()));
} else {
// value is stored in 8 bytes. only use low 7 bits from 1st byte.
return ((((long) (int_value & 0x7f)) << 56) | (((long) in.readUnsignedByte()) << 48)
| (((long) in.readUnsignedByte()) << 40) | (((long) in.readUnsignedByte()) << 32)
| (((long) in.readUnsignedByte()) << 24) | (((long) in.readUnsignedByte()) << 16)
| (((long) in.readUnsignedByte()) << 8) | (((long) in.readUnsignedByte())));
}
}
/**
* Read a long previously written by writeLong().
*
* @exception IOException
* an exception was thrown by a method on in.
*/
public static final long readLong(InputStream in) throws IOException {
int int_value = InputStreamUtil.readUnsignedByte(in);
if ((int_value & ~0x3f) == 0) {
// test for small case first - assuming this is usual case.
// this is stored in 2 bytes.
return ((int_value << 8) | InputStreamUtil.readUnsignedByte(in));
} else if ((int_value & 0x80) == 0) {
// value is stored in 4 bytes. only use low 6 bits from 1st byte.
return (((int_value & 0x3f) << 24) | (InputStreamUtil.readUnsignedByte(in) << 16)
| (InputStreamUtil.readUnsignedByte(in) << 8) | (InputStreamUtil.readUnsignedByte(in)));
} else {
// value is stored in 8 bytes. only use low 7 bits from 1st byte.
long value = int_value;
return ((((long) (value & 0x7f)) << 56)
| (((long) InputStreamUtil.readUnsignedByte(in)) << 48)
| (((long) InputStreamUtil.readUnsignedByte(in)) << 40)
| (((long) InputStreamUtil.readUnsignedByte(in)) << 32)
| (((long) InputStreamUtil.readUnsignedByte(in)) << 24)
| (((long) InputStreamUtil.readUnsignedByte(in)) << 16)
| (((long) InputStreamUtil.readUnsignedByte(in)) << 8) | (((long) InputStreamUtil
.readUnsignedByte(in))));
}
}
public static final long readLong(byte[] data, int offset) {
int int_value = data[offset++];
if ((int_value & ~0x3f) == 0) {
// test for small case first - assuming this is usual case.
// this is stored in 2 bytes.
return ((int_value << 8) | (data[offset] & 0xff));
} else if ((int_value & 0x80) == 0) {
// value is stored in 4 bytes. only use low 6 bits from 1st byte.
return (((int_value & 0x3f) << 24) | ((data[offset++] & 0xff) << 16)
| ((data[offset++] & 0xff) << 8) | ((data[offset] & 0xff)));
} else {
// value is stored in 8 bytes. only use low 6 bits from 1st byte.
return ((((long) (int_value & 0x7f)) << 56) | (((long) (data[offset++] & 0xff)) << 48)
| (((long) (data[offset++] & 0xff)) << 40) | (((long) (data[offset++] & 0xff)) << 32)
| (((long) (data[offset++] & 0xff)) << 24) | (((long) (data[offset++] & 0xff)) << 16)
| (((long) (data[offset++] & 0xff)) << 8) | (((long) (data[offset] & 0xff))));
}
}
public static final int sizeLong(long value) {
if (value <= 0x3fff) {
return 2;
}
if (value <= 0x3fffffff) {
return 4;
}
return 8;
}
}
/*
*
* Derby - Class org.apache.derby.iapi.services.io.InputStreamUtil
*
* 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.
*
*/
/**
* Utility methods for InputStream that are stand-ins for a small subset of
* DataInput methods. This avoids pushing a DataInputStream just to get this
* functionality.
*/
final class InputStreamUtil {
private static final int SKIP_FRAGMENT_SIZE = Integer.MAX_VALUE;
/**
* Read an unsigned byte from an InputStream, throwing an EOFException if the
* end of the input is reached.
*
* @exception IOException
* if an I/O error occurs.
* @exception EOFException
* if the end of the stream is reached
*
* @see DataInput#readUnsignedByte
*
*/
public static int readUnsignedByte(InputStream in) throws IOException {
int b = in.read();
if (b < 0)
throw new EOFException();
return b;
}
/**
* Read a number of bytes into an array.
*
* @exception IOException
* if an I/O error occurs.
* @exception EOFException
* if the end of the stream is reached
*
* @see DataInput#readFully
*
*/
public static void readFully(InputStream in, byte b[], int offset, int len) throws IOException {
do {
int bytesRead = in.read(b, offset, len);
if (bytesRead < 0)
throw new EOFException();
len -= bytesRead;
offset += bytesRead;
} while (len != 0);
}
/**
* Read a number of bytes into an array. Keep reading in a loop until len
* bytes are read or EOF is reached or an exception is thrown. Return the
* number of bytes read. (InputStream.read(byte[],int,int) does not guarantee
* to read len bytes even if it can do so without reaching EOF or raising an
* exception.)
*
* @exception IOException
* if an I/O error occurs.
*/
public static int readLoop(InputStream in, byte b[], int offset, int len) throws IOException {
int firstOffset = offset;
do {
int bytesRead = in.read(b, offset, len);
if (bytesRead <= 0)
break;
len -= bytesRead;
offset += bytesRead;
} while (len != 0);
return offset - firstOffset;
}
/**
* Skips until EOF, returns number of bytes skipped.
*
* @param is
* InputStream to be skipped.
* @return number of bytes skipped in fact.
* @throws IOException
* if IOException occurs. It doesn"t contain EOFException.
* @throws NullPointerException
* if the param "is" equals null.
*/
public static long skipUntilEOF(InputStream is) throws IOException {
if (is == null)
throw new NullPointerException();
long bytes = 0;
while (true) {
long r = skipPersistent(is, SKIP_FRAGMENT_SIZE);
bytes += r;
if (r < SKIP_FRAGMENT_SIZE)
return bytes;
}
}
/**
* Skips requested number of bytes, throws EOFException if there is too few
* bytes in the stream.
*
* @param is
* InputStream to be skipped.
* @param skippedBytes
* number of bytes to skip. if skippedBytes <= zero, do nothing.
* @throws EOFException
* if EOF meets before requested number of bytes are skipped.
* @throws IOException
* if IOException occurs. It doesn"t contain EOFException.
* @throws NullPointerException
* if the param "is" equals null.
*/
public static void skipFully(InputStream is, long skippedBytes) throws IOException {
if (is == null)
throw new NullPointerException();
if (skippedBytes <= 0)
return;
long bytes = skipPersistent(is, skippedBytes);
if (bytes < skippedBytes)
throw new EOFException();
}
/**
* Tries harder to skip the requested number of bytes.
* <p>
* Note that even if the method fails to skip the requested number of bytes,
* it will not throw an exception. If this happens, the caller can be sure
* that end-of-stream has been reached.
*
* @param in
* byte stream
* @param bytesToSkip
* the number of bytes to skip
* @return The number of bytes skipped.
* @throws IOException
* if reading from the stream fails
*/
public static final long skipPersistent(InputStream in, long bytesToSkip) throws IOException {
long skipped = 0;
while (skipped < bytesToSkip) {
long skippedNow = in.skip(bytesToSkip - skipped);
if (skippedNow == 0) {
if (in.read() == -1) {
// EOF, return what we have and leave it up to caller to
// decide what to do about it.
break;
} else {
skippedNow = 1; // Added to count below.
}
}
skipped += skippedNow;
}
return skipped;
}
}