简体   繁体   English

从Socket读取一个字节数组

[英]Reading a byte array from Socket

I have already read the sun guide and different similar questions. 我已经阅读了太阳指南和不同的类似问题。 I want to read some unknown number of bytes into an array from Socket. 我想从Socket中读取一些未知数量的字节到数组中。

I have two options either I can use the read(byte) in a loop and add the bytes to byte array or I can use DataInputStream readFully(byte[]) to read all the bytes into byte array. 我有两个选项,我可以在循环中使用read(byte)并将字节添加到byte数组中,或者我可以使用DataInputStream readFully(byte[])将所有字节读入字节数组。 Which one is better and how do I find the size of byte array beforehand for allocation? 哪一个更好,如何预先找到字节数组的大小进行分配? Also, If I use the first approach how to append the bytes in the byte array. 另外,如果我使用第一种方法如何在字节数组中追加字节。

while(in.read(b) ! = -1)
{
 //Add to byte array, but how to append at the end?
}

Can I use StringBuilder to receive the data, append to it and then do toString().getBytes() ? 我可以使用StringBuilder接收数据,附加到它然后执行toString().getBytes()

Read in small chunks and write it into ByteArrayOutputStream 读入小块并将其写入ByteArrayOutputStream

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buffer[] = new byte[1024];
for(int s; (s=in.read(buffer)) != -1; )
{
  baos.write(buffer, 0, s);
}
byte result[] = baos.toByteArray();

I have two options either I can use the read(byte) in a loop and add the bytes to byte array or I can use DataInputStream readFully(byte[]) to read all the bytes into byte array. 我有两个选项,我可以在循环中使用read(byte)并将字节添加到byte数组中,或者我可以使用DataInputStream readFully(byte [])将所有字节读入字节数组。 Which one is better 哪一个更好

Neither really solves your problem, because ... 两者都没有真正解决你的问题,因为......

and how do I find the size of byte array beforehand for allocation? 如何预先找到字节数组的大小进行分配?

... you can't find the size of the byte array beforehand unless: ...除非事先找不到字节数组的大小:

  • the client tells you how many bytes are coming by sending a count before the bytes themselves, or 客户端通过在字节本身之前发送计数来告诉您有多少字节,或者
  • you place a limit on the number of bytes that you are prepared to receive, and use that as the array size. 您对准备接收的字节数进行限制,并将其用作数组大小。

Can I use StringBuilder to receive the data ... 我可以使用StringBuilder来接收数据......

Using a StringBuilder is possible in theory. 理论上可以使用StringBuilder However, it entails converting from bytes to characters and back again ... which is potentially lossy . 但是,它需要从字节转换为字符然后再转换回来......这可能是有损的 You might be able to find an 8-bit character encoding / decoding which isn't lossy ... but I'd not do this. 您可能能够找到一个没有损耗的8位字符编码/解码...但我不会这样做。

I'd simply use a ByteArrayOutputStream as the buffer for accumulate the bytes, and use the toByteArray() to extract them. 我只是使用ByteArrayOutputStream作为累积字节的缓冲区,并使用toByteArray()来提取它们。 You can read bytes from the socket in chunks as shown by @kan's answer. 如@ kan的答案所示,您可以从块中读取套接字中的字节。

Transmit the size first, then the data? 首先传输大小,然后传输数据?

Otherwise, you cannot use an array, but need to use something resizable. 否则,您不能使用数组,但需要使用可调整大小的内容。

You cannot append to arrays in Java - they cannot grow. 您无法在Java中附加到数组 - 它们无法增长。 You can setup a buffer, and remember up to where you are currently using it. 您可以设置缓冲区,并记住您当前使用它的位置。 This is in fact what an ArrayList does: allocate a buffer, and when it's capacity is exceeded, allocate a bigger one and copy the data over. 这实际上是ArrayList的作用:分配缓冲区,当超出容量时,分配一个更大的缓冲区并复制数据。 Repeat. 重复。

This should do the trick. 这应该可以解决问题。 I modified this a while back to fix some dangerous synchronisation bugs in the implementation. 我修改了一段时间以修复实现中的一些危险的同步错误。 It's not part of the Java classpath, but it's efficient and expands dynamically. 它不是Java类路径的一部分,但它是高效的并且动态扩展。 Compared to other solutions, it has a few neat tricks up its sleeve. 与其他解决方案相比,它有一些巧妙的技巧。

/*
 * 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 misc;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import com.Ostermiller.util.CircularCharBuffer;
import com.Ostermiller.util.CircularObjectBuffer;

/**
 * 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 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(){
        synchronized (CircularByteBuffer.this) {
            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; 

            CircularByteBuffer.this.notifyAll();
        }
    }

    /**
     * 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);
        }
        // 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);
        }
        // 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);
        }
        // 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
     */
    public CircularByteBuffer(int size, boolean blockingWrite){
        if (size == INFINITE_SIZE){
            buffer = new byte[DEFAULT_SIZE];
            infinite = true;
        } else {
            buffer = new byte[size];
            infinite = false;
        }
        this.blockingWrite = blockingWrite;
    }

    /**
     * Class for reading from a circular byte buffer.
     *
     * @since ostermillerutils 1.00.00
     */
    protected class CircularByteBufferInputStream extends InputStream {

        /**
         * Returns the number of bytes that can be read (or skipped over) from this
         * input stream without blocking by the next caller of a method for this input
         * stream. The next caller might be the same thread or or another thread.
         *
         * @return the number of bytes that can be read from this input stream without blocking.
         * @throws IOException if the stream is closed.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public int available() throws IOException {
            synchronized (CircularByteBuffer.this){
                if (inputStreamClosed) throw new IOException("InputStream has been closed, it is not ready.");
                return (CircularByteBuffer.this.available());
            }
        }

        /**
         * Close the stream. Once a stream has been closed, further read(), available(),
         * mark(), or reset() invocations will throw an IOException. Closing a
         * previously-closed stream, however, has no effect.
         *
         * @throws IOException never.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public void close() throws IOException {
            synchronized (CircularByteBuffer.this){
                inputStreamClosed = true;
            }
        }

        /**
         * Mark the present position in the stream. Subsequent calls to reset() will
         * attempt to reposition the stream to this point.
         * <p>
         * The readAheadLimit must be less than the size of circular buffer, otherwise
         * this method has no effect.
         *
         * @param readAheadLimit Limit on the number of bytes that may be read while
         *    still preserving the mark. After reading this many bytes, attempting to
         *    reset the stream will fail.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public void mark(int readAheadLimit) {
            synchronized (CircularByteBuffer.this){
                //if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot mark a closed InputStream.");
                if (buffer.length - 1 > readAheadLimit) {
                    markSize = readAheadLimit;
                    markPosition = readPosition;
                }
            }
        }

        /**
         * Tell whether this stream supports the mark() operation.
         *
         * @return true, mark is supported.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public boolean markSupported() {
            return true;
        }

        /**
         * Read a single byte.
         * This method will block until a byte is available, an I/O error occurs,
         * or the end of the stream is reached.
         *
         * @return The byte read, as an integer in the range 0 to 255 (0x00-0xff),
         *     or -1 if the end of the stream has been reached
         * @throws IOException if the stream is closed.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public int read() throws IOException {
            synchronized (CircularByteBuffer.this){
                while (true) {
                    if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream.");
                    int available = CircularByteBuffer.this.available();
                    if (available > 0){
                        int result = buffer[readPosition] & 0xff;
                        readPosition++;
                        if (readPosition == buffer.length){
                            readPosition = 0;
                        }
                        ensureMark();
                        return result;
                    } else if (outputStreamClosed){
                        return -1;
                    } else {
                        try {
                            CircularByteBuffer.this.wait();
                        } catch(Exception x){
                            throw new IOException("Blocking read operation interrupted.");
                        }                       
                    }
                }               
            }
        }

        /**
         * Read bytes into an array.
         * This method will block until some input is available,
         * an I/O error occurs, or the end of the stream is reached.
         *
         * @param cbuf Destination buffer.
         * @return The number of bytes read, or -1 if the end of
         *   the stream has been reached
         * @throws IOException if the stream is closed.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public int read(byte[] cbuf) throws IOException {
            return read(cbuf, 0, cbuf.length);
        }

        /**
         * Read bytes into a portion of an array.
         * This method will block until some input is available,
         * an I/O error occurs, or the end of the stream is reached.
         *
         * @param cbuf Destination buffer.
         * @param off Offset at which to start storing bytes.
         * @param len Maximum number of bytes to read.
         * @return The number of bytes read, or -1 if the end of
         *   the stream has been reached
         * @throws IOException if the stream is closed.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public int read(byte[] cbuf, int off, int len) throws IOException {
            synchronized (CircularByteBuffer.this){
                while (true){
                    if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream.");
                    int available = CircularByteBuffer.this.available();
                    if (available > 0){
                        int length = Math.min(len, available);
                        int firstLen = Math.min(length, buffer.length - readPosition);
                        int secondLen = length - firstLen;
                        System.arraycopy(buffer, readPosition, cbuf, off, firstLen);
                        if (secondLen > 0){
                            System.arraycopy(buffer, 0, cbuf, off+firstLen,  secondLen);
                            readPosition = secondLen;
                        } else {
                            readPosition += length;
                        }
                        if (readPosition == buffer.length) {
                            readPosition = 0;
                        }
                        ensureMark();
                        return length;
                    } else if (outputStreamClosed){
                        return -1;
                    } else {
                        try {
                            CircularByteBuffer.this.wait();
                        } catch(Exception x){
                            throw new IOException("Blocking read operation interrupted.");
                        }
                    }
                }
            }
        }

        /**
         * Reset the stream.
         * If the stream has been marked, then attempt to reposition i
         * at the mark. If the stream has not been marked, or more bytes
         * than the readAheadLimit have been read, this method has no effect.
         *
         * @throws IOException if the stream is closed.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public void reset() throws IOException {
            synchronized (CircularByteBuffer.this){
                if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot reset a closed InputStream.");
                readPosition = markPosition;
            }
        }

        /**
         * Skip bytes.
         * This method will block until some bytes are available,
         * an I/O error occurs, or the end of the stream is reached.
         *
         * @param n The number of bytes to skip
         * @return The number of bytes actually skipped
         * @throws IllegalArgumentException if n is negative.
         * @throws IOException if the stream is closed.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public long skip(long n) throws IOException, IllegalArgumentException {
            synchronized (CircularByteBuffer.this){

                while (true){
                    if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot skip bytes on a closed InputStream.");
                    int available = CircularByteBuffer.this.available();
                    if (available > 0){
                        int length = Math.min((int)n, available);
                        int firstLen = Math.min(length, buffer.length - readPosition);
                        int secondLen = length - firstLen;
                        if (secondLen > 0){
                            readPosition = secondLen;
                        } else {
                            readPosition += length;
                        }
                        if (readPosition == buffer.length) {
                            readPosition = 0;
                        }
                        ensureMark();
                        return length;
                    } else if (outputStreamClosed){
                        return 0;
                    } else {
                        try {
                            CircularByteBuffer.this.wait();
                        } catch(Exception x){
                            throw new IOException("Blocking read operation interrupted.");
                        }
                    }
                }
            }
        }
    }

    /**
     * Class for writing to a circular byte buffer.
     * If the buffer is full, the writes will either block
     * until there is some space available or throw an IOException
     * based on the CircularByteBuffer's preference.
     *
     * @since ostermillerutils 1.00.00
     */
    protected class CircularByteBufferOutputStream extends OutputStream {

        /**
         * Close the stream, flushing it first.
         * This will cause the InputStream associated with this circular buffer
         * to read its last bytes once it empties the buffer.
         * Once a stream has been closed, further write() or flush() invocations
         * will cause an IOException to be thrown. Closing a previously-closed stream,
         * however, has no effect.
         *
         * @throws IOException never.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public void close() throws IOException {
            synchronized (CircularByteBuffer.this){
                if (!outputStreamClosed){
                    flush();
                }
                outputStreamClosed = true;
            }
        }

        /**
         * Flush the stream.
         *
         * @throws IOException if the stream is closed.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public void flush() throws IOException {
            synchronized (CircularByteBuffer.this) {
                // this method needs to do nothing
                CircularByteBuffer.this.notifyAll();
            }
        }

        /**
         * Write an array of bytes.
         * If the buffer allows blocking writes, this method will block until
         * all the data has been written rather than throw an IOException.
         *
         * @param cbuf Array of bytes to be written
         * @throws BufferOverflowException if buffer does not allow blocking writes
         *   and the buffer is full.  If the exception is thrown, no data
         *   will have been written since the buffer was set to be non-blocking.
         * @throws IOException if the stream is closed, or the write is interrupted.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public void write(byte[] cbuf) throws IOException {
            write(cbuf, 0, cbuf.length);
        }

        /**
         * Write a portion of an array of bytes.
         * If the buffer allows blocking writes, this method will block until
         * all the data has been written rather than throw an IOException.
         *
         * @param cbuf Array of bytes
         * @param off Offset from which to start writing bytes
         * @param len - Number of bytes to write
         * @throws BufferOverflowException if buffer does not allow blocking writes
         *   and the buffer is full.  If the exception is thrown, no data
         *   will have been written since the buffer was set to be non-blocking.
         * @throws IOException if the stream is closed, or the write is interrupted.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public void write(byte[] cbuf, int off, int len) throws IOException {
            synchronized (CircularByteBuffer.this){
                while (len > 0){
                    if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot write to a closed OutputStream.");
                    if (inputStreamClosed) throw new IOException("Buffer closed by InputStream; cannot write to a closed buffer.");

                    while (infinite && spaceLeft() < len){
                        resize();
                    }
                    while (!infinite && spaceLeft() < len) {
                        // wait for space to become available
                        try {
                            CircularByteBuffer.this.wait();
                        } catch (InterruptedException e) {

                        }
                    }

                    if (!blockingWrite && spaceLeft() < len) throw new BufferOverflowException();
                    int realLen = Math.min(len, spaceLeft());
                    int firstLen = Math.min(realLen, buffer.length - writePosition);
                    int secondLen = Math.min(realLen - firstLen, buffer.length - markPosition - 1);
                    int written = firstLen + secondLen;
                    if (firstLen > 0){
                        System.arraycopy(cbuf, off, buffer, writePosition, firstLen);
                    }
                    if (secondLen > 0){
                        System.arraycopy(cbuf, off+firstLen, buffer, 0, secondLen);
                        writePosition = secondLen;
                    } else {
                        writePosition += written;
                    }
                    if (writePosition == buffer.length) {
                        writePosition = 0;
                    }
                    off += written;
                    len -= written;
                }

                CircularByteBuffer.this.notifyAll();
            }
        }

        /**
         * Write a single byte.
         * The byte to be written is contained in the 8 low-order bits of the
         * given integer value; the 24 high-order bits are ignored.
         * If the buffer allows blocking writes, this method will block until
         * all the data has been written rather than throw an IOException.
         *
         * @param c number of bytes to be written
         * @throws BufferOverflowException if buffer does not allow blocking writes
         *   and the buffer is full.
         * @throws IOException if the stream is closed, or the write is interrupted.
         *
         * @since ostermillerutils 1.00.00
         */
        @Override public void write(int c) throws IOException {
            boolean written = false;
            synchronized (CircularByteBuffer.this){
                while (!written){
                    if (outputStreamClosed) throw new IOException("OutputStream has been closed; cannot write to a closed OutputStream.");
                    if (inputStreamClosed) throw new IOException("Buffer closed by InputStream; cannot write to a closed buffer.");
                    int spaceLeft = spaceLeft();
                    while (infinite && spaceLeft < 1){
                        resize();
                        spaceLeft = spaceLeft();
                    }
                    if (!blockingWrite && spaceLeft < 1) throw new BufferOverflowException();
                    if (spaceLeft > 0){
                        buffer[writePosition] = (byte)(c & 0xff);
                        writePosition++;
                        if (writePosition == buffer.length) {
                            writePosition = 0;
                        }
                        written = true;
                    }
                }
                if (!written){
                    try {
                        CircularByteBuffer.this.wait(100);
                    } catch(Exception x){
                        throw new IOException("Waiting for available space in buffer interrupted.");
                    }
                }
                CircularByteBuffer.this.notifyAll();
            }
        }
    }
}

Grab the jar from ostermiller.org and add it it your project's libraries for the additional missing classes. ostermiller.org获取jar并将其添加到项目的库中以获取其他缺失的类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM