public byte[] readBytes(int length) throws IOException {
        if (length < 1) {
            return ClickHouseByteBuffer.EMPTY_BYTES;
        }
        ensureOpen();

        byte[] bytes = new byte[length];
        int offset = 0;
        while (offset < length) {
            int read = read(bytes, offset, length - offset);
            if (read == -1) {
                closeQuietly();
                throw offset == 0 ? new EOFException()
                        : new StreamCorruptedException(ClickHouseUtils.format(ERROR_INCOMPLETE_READ, offset, length));
            } else {
                offset += read;
            }
        }

        return bytes;
    }
Reads {@code length} bytes from the input stream. It behaves in the same
way as {@link java.io.DataInput#readFully(byte[])}, except it will throw
{@link IOException} when the input stream has been closed.

@param length number of bytes to read
@return byte array and its length should be {@code length}
@throws IOException when failed to read value from input stream, not able to
                    retrieve all bytes, or reached end of the stream
clickhouse-data/src/main/java/com/clickhouse/data/ClickHouseInputStream.java