Java: Memory efficient ByteArrayOutputStream

前端 未结 9 715
一个人的身影
一个人的身影 2021-02-04 06:15

I\'ve got a 40MB file in the disk and I need to \"map\" it into memory using a byte array.

At first, I thought writing the file to a ByteArrayOutputStream would be the b

9条回答
  •  情深已故
    2021-02-04 06:23

    I'm thinking I could just extend ByteArrayOutputStream and rewrite this method, so to return the original array directly. Is there any potential danger here, given the stream and the byte array won't be used more than once?

    You shouldn't change the specified behavior of the existing method, but it's perfectly fine to add a new method. Here's an implementation:

    /** Subclasses ByteArrayOutputStream to give access to the internal raw buffer. */
    public class ByteArrayOutputStream2 extends java.io.ByteArrayOutputStream {
        public ByteArrayOutputStream2() { super(); }
        public ByteArrayOutputStream2(int size) { super(size); }
    
        /** Returns the internal buffer of this ByteArrayOutputStream, without copying. */
        public synchronized byte[] buf() {
            return this.buf;
        }
    }
    

    An alternative but hackish way of getting the buffer from any ByteArrayOutputStream is to use the fact that its writeTo(OutputStream) method passes the buffer directly to the provided OutputStream:

    /**
     * Returns the internal raw buffer of a ByteArrayOutputStream, without copying.
     */
    public static byte[] getBuffer(ByteArrayOutputStream bout) {
        final byte[][] result = new byte[1][];
        try {
            bout.writeTo(new OutputStream() {
                @Override
                public void write(byte[] buf, int offset, int length) {
                    result[0] = buf;
                }
    
                @Override
                public void write(int b) {}
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return result[0];
    }
    

    (That works, but I'm not sure if it's useful, given that subclassing ByteArrayOutputStream is simpler.)

    However, from the rest of your question it sounds like all you want is a plain byte[] of the complete contents of the file. As of Java 7, the simplest and fastest way to do that is call Files.readAllBytes. In Java 6 and below, you can use DataInputStream.readFully, as in Peter Lawrey's answer. Either way, you will get an array that is allocated once at the correct size, without the repeated reallocation of ByteArrayOutputStream.

提交回复
热议问题