📄 circularbytebuffer.java
字号:
/* * Circular Byte Buffer * Copyright (C) 2002 Stephen Ostermiller * http://ostermiller.org/contact.pl?regarding=Java+Utilities * * 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; either version 2 of the License, or * (at your option) any later version. * * 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. * * See COPYING.TXT for details. */package com.Ostermiller.util;import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;/** * Implements the Circular Buffer producer/consumer model for bytes. * More information about this class is available from <a target="_top" href= * "http://ostermiller.org/utils/CircularByteBuffer.html">ostermiller.org</a>. * <p> * Using this class is a simpler alternative to using a PipedInputStream * and a PipedOutputStream. PipedInputStreams and PipedOutputStreams don't support the * mark operation, don't allow you to control buffer sizes that they use, * and have a more complicated API that requires a instantiating two * classes and connecting them. * <p> * This class is thread safe. * * @see CircularCharBuffer * @see CircularObjectBuffer * * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities * @since ostermillerutils 1.00.00 */public class CircularByteBuffer { /** * The default size for a circular byte buffer. * * @since ostermillerutils 1.00.00 */ private final static int DEFAULT_SIZE = 1024; /** * A buffer that will grow as things are added. * * @since ostermillerutils 1.00.00 */ public final static int INFINITE_SIZE = -1; /** * The circular buffer. * <p> * The actual capacity of the buffer is one less than the actual length * of the buffer so that an empty and a full buffer can be * distinguished. An empty buffer will have the markPostion and the * writePosition equal to each other. A full buffer will have * the writePosition one less than the markPostion. * <p> * There are three important indexes into the buffer: * The readPosition, the writePosition, and the markPosition. * If the InputStream has never been marked, the readPosition and * the markPosition should always be the same. The bytes * available to be read go from the readPosition to the writePosition, * wrapping around the end of the buffer. The space available for writing * goes from the write position to one less than the markPosition, * wrapping around the end of the buffer. The bytes that have * been saved to support a reset() of the InputStream go from markPosition * to readPosition, wrapping around the end of the buffer. * * @since ostermillerutils 1.00.00 */ protected byte[] buffer; /** * Index of the first byte available to be read. * * @since ostermillerutils 1.00.00 */ protected volatile int readPosition = 0; /** * Index of the first byte available to be written. * * @since ostermillerutils 1.00.00 */ protected volatile int writePosition = 0; /** * Index of the first saved byte. (To support stream marking.) * * @since ostermillerutils 1.00.00 */ protected volatile int markPosition = 0; /** * Number of bytes that have to be saved * to support mark() and reset() on the InputStream. * * @since ostermillerutils 1.00.00 */ protected volatile int markSize = 0; /** * If this buffer is infinite (should resize itself when full) * * @since ostermillerutils 1.00.00 */ protected volatile boolean infinite = false; /** * True if a write to a full buffer should block until the buffer * has room, false if the write method should throw an IOException * * @since ostermillerutils 1.00.00 */ protected boolean blockingWrite = true; /** * The InputStream that can empty this buffer. * * @since ostermillerutils 1.00.00 */ protected InputStream in = new CircularByteBufferInputStream(); /** * true if the close() method has been called on the InputStream * * @since ostermillerutils 1.00.00 */ protected boolean inputStreamClosed = false; /** * The OutputStream that can fill this buffer. * * @since ostermillerutils 1.00.00 */ protected OutputStream out = new CircularByteBufferOutputStream(); /** * true if the close() method has been called on the OutputStream * * @since ostermillerutils 1.00.00 */ protected boolean outputStreamClosed = false; /** * Make this buffer ready for reuse. The contents of the buffer * will be cleared and the streams associated with this buffer * will be reopened if they had been closed. * * @since ostermillerutils 1.00.00 */ public void clear(){ synchronized (this){ readPosition = 0; writePosition = 0; markPosition = 0; outputStreamClosed = false; inputStreamClosed = false; } } /** * Retrieve a OutputStream that can be used to fill * this buffer. * <p> * Write methods may throw a BufferOverflowException if * the buffer is not large enough. A large enough buffer * size must be chosen so that this does not happen or * the caller must be prepared to catch the exception and * try again once part of the buffer has been consumed. * * * @return the producer for this buffer. * * @since ostermillerutils 1.00.00 */ public OutputStream getOutputStream(){ return out; } /** * Retrieve a InputStream that can be used to empty * this buffer. * <p> * This InputStream supports marks at the expense * of the buffer size. * * @return the consumer for this buffer. * * @since ostermillerutils 1.00.00 */ public InputStream getInputStream(){ return in; } /** * Get number of bytes that are available to be read. * <p> * Note that the number of bytes available plus * the number of bytes free may not add up to the * capacity of this buffer, as the buffer may reserve some * space for other purposes. * * @return the size in bytes of this buffer * * @since ostermillerutils 1.00.00 */ public int getAvailable(){ synchronized (this){ return available(); } } /** * Get the number of bytes this buffer has free for * writing. * <p> * Note that the number of bytes available plus * the number of bytes free may not add up to the * capacity of this buffer, as the buffer may reserve some * space for other purposes. * * @return the available space in bytes of this buffer * * @since ostermillerutils 1.00.00 */ public int getSpaceLeft(){ synchronized (this){ return spaceLeft(); } } /** * Get the capacity of this buffer. * <p> * Note that the number of bytes available plus * the number of bytes free may not add up to the * capacity of this buffer, as the buffer may reserve some * space for other purposes. * * @return the size in bytes of this buffer * * @since ostermillerutils 1.00.00 */ public int getSize(){ synchronized (this){ return buffer.length; } } /** * double the size of the buffer * * @since ostermillerutils 1.00.00 */ private void resize(){ byte[] newBuffer = new byte[buffer.length * 2]; int marked = marked(); int available = available(); if (markPosition <= writePosition){ // any space between the mark and // the first write needs to be saved. // In this case it is all in one piece. int length = writePosition - markPosition; System.arraycopy(buffer, markPosition, newBuffer, 0, length); } else { int length1 = buffer.length - markPosition; System.arraycopy(buffer, markPosition, newBuffer, 0, length1); int length2 = writePosition; System.arraycopy(buffer, 0, newBuffer, length1, length2); } buffer = newBuffer; markPosition = 0; readPosition = marked; writePosition = marked + available; } /** * Space available in the buffer which can be written. * * @since ostermillerutils 1.00.00 */ private int spaceLeft(){ if (writePosition < markPosition){ // any space between the first write and // the mark except one byte is available. // In this case it is all in one piece. return (markPosition - writePosition - 1); } else { // space at the beginning and end. return ((buffer.length - 1) - (writePosition - markPosition)); } } /** * Bytes available for reading. * * @since ostermillerutils 1.00.00 */ private int available(){ if (readPosition <= writePosition){ // any space between the first read and // the first write is available. In this case i // is all in one piece. return (writePosition - readPosition); } else { // space at the beginning and end. return (buffer.length - (readPosition - writePosition)); } } /** * Bytes saved for supporting marks. * * @since ostermillerutils 1.00.00 */ private int marked(){ if (markPosition <= readPosition){ // any space between the markPosition and // the first write is marked. In this case i // is all in one piece. return (readPosition - markPosition); } else { // space at the beginning and end. return (buffer.length - (markPosition - readPosition)); } } /** * If we have passed the markSize reset the * mark so that the space can be used. * * @since ostermillerutils 1.00.00 */ private void ensureMark(){ if (marked() >= markSize){ markPosition = readPosition; markSize = 0; } } /** * Create a new buffer with a default capacity. * Writing to a full buffer will block until space * is available rather than throw an exception. * * @since ostermillerutils 1.00.00 */ public CircularByteBuffer(){ this (DEFAULT_SIZE, true); } /** * Create a new buffer with given capacity. * Writing to a full buffer will block until space * is available rather than throw an exception. * <p> * Note that the buffer may reserve some bytes for * special purposes and capacity number of bytes may * not be able to be written to the buffer. * <p> * Note that if the buffer is of INFINITE_SIZE it will * neither block or throw exceptions, but rather grow * without bound. * * @param size desired capacity of the buffer in bytes or CircularByteBuffer.INFINITE_SIZE. * * @since ostermillerutils 1.00.00 */ public CircularByteBuffer(int size){ this (size, true); } /** * Create a new buffer with a default capacity and * given blocking behavior. * * @param blockingWrite true writing to a full buffer should block * until space is available, false if an exception should * be thrown instead. * * @since ostermillerutils 1.00.00 */ public CircularByteBuffer(boolean blockingWrite){ this (DEFAULT_SIZE, blockingWrite); } /** * Create a new buffer with the given capacity and * blocking behavior. * <p> * Note that the buffer may reserve some bytes for * special purposes and capacity number of bytes may * not be able to be written to the buffer. * <p> * Note that if the buffer is of INFINITE_SIZE it will * neither block or throw exceptions, but rather grow * without bound. * * @param size desired capacity of the buffer in bytes or CircularByteBuffer.INFINITE_SIZE. * @param blockingWrite true writing to a full buffer should block * until space is available, false if an exception should * be thrown instead. * * @since ostermillerutils 1.00.00 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -