您的位置:

ioutils的多个方面详解

一、ioutils.write

ioutils.write方法用于将指定字节数组的所有字节写入输出流中。这个方法有四个参数:输出流,要写入的字节数组,开始写入的下标和要写入的字节数。必要时,这个方法会等待输出流变成可用的。

/**
 * 将指定字节数组的所有字节写入输出流中。 注意: 当前方法调用后会调用流的flush()方法,强制将所有缓冲输出到流中。
 *
 * @param data 要写入的字节数组。
 * @param output 写入的输出流。
 * @throws IOException 如果向流中写入字节出错。
 */
public static void write(byte[] data, OutputStream output) throws IOException {
    if (data != null) {
        output.write(data);
    }
}

一般来说,这个方法是很安全的,因为 它对开发者来说非常方便——它做了所有必要的流管理操作,开发者完全不必自己写写缓冲区之类的代码。 实际上,这个方法将自动优化缓存策略,尽可能快地推送字节流到输出流。

二、ioutils.tobytearray内存溢出

ioutils.tobytearray方法用于将指定输入流的字节内容读取到字节数组中。 请注意,此方法会将整个输入流读入内存,这就意味着 如果输入流非常大,那么可能会遇到内存耗尽的问题。

/**
 * 将指定输入流的字节内容读取到字节数组中。 请注意,此方法会将整个输入流读入内存,因此可能会造成内存耗尽的风险。
 *
 * @param input 要读取的输入流
 * @return 读取到的字节数组。
 * @throws IOException 如果读取输入流出错
 */
public static byte[] toByteArray(InputStream input) throws IOException {
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    copy(input, output);
    return output.toByteArray();
}

如果您确定要将大量数据读入字节数组,那么可以考虑分段处理数据。要做到这一点,您可以传递一个带有偏移和长度参数的方法调用。这可以使分段操作成为可能。

三、ioutils.close

ioutils.close方法可以安全而简单地关闭任何可能抛出异常的流对象。使用try-with-resources块调用ioutils.close方法可以确保在所使用的流上正确地关闭所有资源。必须注意的是,如果列表中有多个流对象被打开,那么可以使用该方法将它们同时关闭。

/**
 * 安全地关闭指定的输入输出流。这个方法是安全的:如果流对象为空,它什么也没做。
 *
 * @param outputStream 输出流对象
 * @param inputStream  输入流对象
 */
public static void close(OutputStream outputStream, InputStream inputStream) {
    try {
        if (outputStream != null) {
            outputStream.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }
    } catch (Exception e) {
        // ignore exception.
    }
}

四、ioutils.tostring

ioutils.tostring方法用于将指定输入流的内容转换为字符串。 这个方法还可以允许程序员设置字符编码,以确保所有字节正确地转换为字符串。 如果未设置字符编码,则默认使用UTF-8。

/**
 * 将指定输入流的内容转换为字符串。 这个方法还可以允许程序员设置字符编码,以确保所有字节正确地转换为字符串。
 *
 * @param input 输入流
 * @param charsetName 字符编码, 默认为UTF-8
 * @return 读取到的字符串。
 * @throws IOException 如果读取输入流出错
 */
public static String toString(InputStream input, String charsetName) throws IOException {
    StringBuilderWriter sw = new StringBuilderWriter();
    copy(input, sw, charsetName);
    return sw.toString();
}

这个方法可以用于对网络流和文件流进行编码转换和字符序列操作。建议在我们的应用程序中使用这个方法时使用try-with-resource结构。

五、ioutils.readfully

ioutils.readfully方法用于从指定的输入流中读取完整的字节数组。这个方法保证将读取到指定字节数量的所有字节,并支持在读取到末尾时关闭流。

/**
 * 从输入流中读取完整的字节数据。这个方法保证将读取到指定字节数量的所有字节,并支持在读取到末尾时关闭流。
 *
 * @param input 输入流.
 * @param byteCount 读取的字节数.
 * @return 读取到的字节数组.
 * @throws IOException 如果源流出现故障或无法读取到完整字节.
 */
public static byte[] readFully(InputStream input, int byteCount) throws IOException {
    byte[] result = new byte[byteCount];
    int remaining = byteCount;
    int offset = 0;
    int readCount;
    while (remaining > 0) {
        readCount = input.read(result, offset, remaining);
        if (readCount < 0) {
            break;
        }
        remaining -= readCount;
        offset += readCount;
    }

    if (remaining != 0) {
        throw new EOFException("InputStream ended before reading required bytes");
    }

    return result;
}

使用这个方法的时候,建议加上一个合理的字符编码选择,以便能够在UTF-8或其他字符编码模式中正常读写所需的整字节数量。

六、ioutils.tobytearray

ioutils.tobytearray是ioutils.toByteArray的重载版本,支持设置最大长度。这个方法将读取并返回输入流中的所有可用数据,并且不会关闭流。

/**
 * 将指定输入流的内容完整数据读入到字节数组中。 注意:数据读取后,流不会被关闭。
 *
 * @param input 要读取的输入流
 * @param size  读取的字节数
 * @return 读取的字节数组。
 * @throws IOException 如果读取输入流出错
 */
public static byte[] toByteArray(InputStream input, int size) throws IOException {
    if (size < 0) {
        throw new IllegalArgumentException("Invalid size: " + size);
    }
    byte[] data = new byte[size];
    int offset = 0;
    int readCount;
    while (offset < size) {
        readCount = input.read(data, offset, size - offset);
        if (readCount < 0) {
            break;
        }
        offset += readCount;
    }

    if (offset != size) {
        throw new IOException("Failure creating byte array: expected " + size + " bytes, but read " + offset + " bytes");
    }

    return data;
}

这个方法可以用于读取大对象等情形,但是在读取到末尾之前始终需要处理批量读取所覆盖的字节数。

七、IOUtils.copy

IOUtils.copy方法用于将一个输入流复制到另一个输出流中,并允许在复制过程中选择设置缓冲区的大小。

/**
 * 从一个输入流复制到另一个输出流。缓冲区的大小指定为DEFAULT_BUFFER_SIZE。这个方法保证在复制源流时使用缓冲区。
 *
 * @param input  输入流.
 * @param output 输出流.
 * @throws IOException 如果复制时出现故障.
 */
public static void copy(InputStream input, OutputStream output) throws IOException {
    copy(input, output, DEFAULT_BUFFER_SIZE);
}

/**
 * 从一个输入流复制到另一个输出流。这个方法可以指定输出流的缓冲区大小,以确保优化数据传输速度。
 *
 * @param input  输入流.
 * @param output 输出流.
 * @param bufferSize  缓冲区大小.
 * @throws IOException 如果复制时出现故障.
 */
public static void copy(InputStream input, OutputStream output, int bufferSize) throws IOException {
    byte[] buffer = new byte[bufferSize];
    int count;
    while ((count = input.read(buffer)) != -1) {
        output.write(buffer, 0, count);
    }
}

使用这个方法时,可以根据实际情况选择合适的缓存大小以及输出流的类型。