From 0d525621803acda59eec03ecdcc81de810ca74ff Mon Sep 17 00:00:00 2001
From: Looly
- * 注意!!! 此方法不会检查反序列化安全,可能存在反序列化漏洞风险!!!
- *
@@ -52,7 +49,7 @@ import java.util.zip.Checksum;
*/
public class IoUtil extends NioUtil {
- // -------------------------------------------------------------------------------------- Copy start
+ // region -------------------------------------------------------------------------------------- Copy
/**
* 将Reader中的内容复制到Writer中 使用默认缓存大小,拷贝后不关闭Reader
@@ -96,15 +93,17 @@ public class IoUtil extends NioUtil {
/**
* 将Reader中的内容复制到Writer中,拷贝后不关闭Reader
*
- * @param reader Reader
- * @param writer Writer
- * @param bufferSize 缓存大小
- * @param count 最大长度
- * @param streamProgress 进度处理器
+ * @param reader Reader,非空
+ * @param writer Writer,非空
+ * @param bufferSize 缓存大小,-1表示默认
+ * @param count 最大长度,-1表示无限制
+ * @param streamProgress 进度处理器,{@code null}表示无
* @return 传输的byte数
* @throws IORuntimeException IO异常
*/
public static long copy(final Reader reader, final Writer writer, final int bufferSize, final long count, final StreamProgress streamProgress) throws IORuntimeException {
+ Assert.notNull(reader, "Reader is null !");
+ Assert.notNull(writer, "Writer is null !");
return new ReaderWriterCopier(bufferSize, count, streamProgress).copy(reader, writer);
}
@@ -153,13 +152,15 @@ public class IoUtil extends NioUtil {
* @param in 输入流
* @param out 输出流
* @param bufferSize 缓存大小
- * @param count 总拷贝长度
+ * @param count 总拷贝长度,-1表示无限制
* @param streamProgress 进度条
* @return 传输的byte数
* @throws IORuntimeException IO异常
* @since 5.7.8
*/
public static long copy(final InputStream in, final OutputStream out, final int bufferSize, final long count, final StreamProgress streamProgress) throws IORuntimeException {
+ Assert.notNull(in, "InputStream is null !");
+ Assert.notNull(out, "OutputStream is null !");
return new StreamCopier(bufferSize, count, streamProgress).copy(in, out);
}
@@ -175,42 +176,22 @@ public class IoUtil extends NioUtil {
Assert.notNull(in, "FileInputStream is null!");
Assert.notNull(out, "FileOutputStream is null!");
- FileChannel inChannel = null;
- FileChannel outChannel = null;
- try {
- inChannel = in.getChannel();
- outChannel = out.getChannel();
- return copy(inChannel, outChannel);
- } finally {
- close(outChannel);
- close(inChannel);
- }
+ return FileChannelCopier.of().copy(in, out);
}
- // -------------------------------------------------------------------------------------- Copy end
+ // endregion -------------------------------------------------------------------------------------- Copy
- // -------------------------------------------------------------------------------------- getReader and getWriter start
+ // region -------------------------------------------------------------------------------------- toReader and toWriter
/**
- * 获得一个文件读取器,默认使用UTF-8编码
+ * 获得一个文件读取器,默认使用 UTF-8 编码
*
* @param in 输入流
* @return BufferedReader对象
* @since 5.1.6
*/
- public static BufferedReader getUtf8Reader(final InputStream in) {
- return getReader(in, CharsetUtil.UTF_8);
- }
-
- /**
- * 从{@link BOMInputStream}中获取Reader
- *
- * @param in {@link BOMInputStream}
- * @return {@link BufferedReader}
- * @since 5.5.8
- */
- public static BufferedReader getReader(final BOMInputStream in) {
- return getReader(in, CharsetUtil.charset(in.getCharset()));
+ public static BufferedReader toUtf8Reader(final InputStream in) {
+ return toReader(in, CharsetUtil.UTF_8);
}
/**
@@ -220,7 +201,7 @@ public class IoUtil extends NioUtil {
* @return {@link BomReader}
* @since 5.7.14
*/
- public static BomReader getBomReader(final InputStream in) {
+ public static BomReader toBomReader(final InputStream in) {
return new BomReader(in);
}
@@ -231,7 +212,7 @@ public class IoUtil extends NioUtil {
* @param charset 字符集
* @return BufferedReader对象
*/
- public static BufferedReader getReader(final InputStream in, final Charset charset) {
+ public static BufferedReader toReader(final InputStream in, final Charset charset) {
if (null == in) {
return null;
}
@@ -246,35 +227,6 @@ public class IoUtil extends NioUtil {
return new BufferedReader(reader);
}
- /**
- * 获得{@link BufferedReader}
- * 如果是{@link BufferedReader}强转返回,否则新建。如果提供的Reader为null返回null
- *
- * @param reader 普通Reader,如果为null返回null
- * @return {@link BufferedReader} or null
- * @since 3.0.9
- */
- public static BufferedReader getReader(final Reader reader) {
- if (null == reader) {
- return null;
- }
-
- return (reader instanceof BufferedReader) ? (BufferedReader) reader : new BufferedReader(reader);
- }
-
- /**
- * 获得{@link PushbackReader}
- * 如果是{@link PushbackReader}强转返回,否则新建
- *
- * @param reader 普通Reader
- * @param pushBackSize 推后的byte数
- * @return {@link PushbackReader}
- * @since 3.1.0
- */
- public static PushbackReader getPushBackReader(final Reader reader, final int pushBackSize) {
- return (reader instanceof PushbackReader) ? (PushbackReader) reader : new PushbackReader(reader, pushBackSize);
- }
-
/**
* 获得一个Writer,默认编码UTF-8
*
@@ -282,8 +234,8 @@ public class IoUtil extends NioUtil {
* @return OutputStreamWriter对象
* @since 5.1.6
*/
- public static OutputStreamWriter getUtf8Writer(final OutputStream out) {
- return getWriter(out, CharsetUtil.UTF_8);
+ public static OutputStreamWriter toUtf8Writer(final OutputStream out) {
+ return toWriter(out, CharsetUtil.UTF_8);
}
/**
@@ -293,7 +245,7 @@ public class IoUtil extends NioUtil {
* @param charset 字符集
* @return OutputStreamWriter对象
*/
- public static OutputStreamWriter getWriter(final OutputStream out, final Charset charset) {
+ public static OutputStreamWriter toWriter(final OutputStream out, final Charset charset) {
if (null == out) {
return null;
}
@@ -304,9 +256,9 @@ public class IoUtil extends NioUtil {
return new OutputStreamWriter(out, charset);
}
}
- // -------------------------------------------------------------------------------------- getReader and getWriter end
+ // endregion -------------------------------------------------------------------------------------- toReader and toWriter
- // -------------------------------------------------------------------------------------- read start
+ // region -------------------------------------------------------------------------------------- read
/**
* 从流中读取UTF8编码的内容
@@ -353,25 +305,7 @@ public class IoUtil extends NioUtil {
* @since 5.5.3
*/
public static FastByteArrayOutputStream read(final InputStream in, final boolean isClose) throws IORuntimeException {
- final FastByteArrayOutputStream out;
- if (in instanceof FileInputStream) {
- // 文件流的长度是可预见的,此时直接读取效率更高
- try {
- out = new FastByteArrayOutputStream(in.available());
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- } else {
- out = new FastByteArrayOutputStream();
- }
- try {
- copy(in, out);
- } finally {
- if (isClose) {
- close(in);
- }
- }
- return out;
+ return StreamReader.of(in, isClose).read();
}
/**
@@ -431,28 +365,7 @@ public class IoUtil extends NioUtil {
* @since 5.0.4
*/
public static byte[] readBytes(final InputStream in, final boolean isClose) throws IORuntimeException {
- if (in instanceof FileInputStream) {
- // 文件流的长度是可预见的,此时直接读取效率更高
- final byte[] result;
- try {
- final int available = in.available();
- result = new byte[available];
- final int readLength = in.read(result);
- if (readLength != available) {
- throw new IOException(StrUtil.format("File length is [{}] but read [{}]!", available, readLength));
- }
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- } finally {
- if (isClose) {
- close(in);
- }
- }
- return result;
- }
-
- // 未知bytes总量的流
- return read(in, isClose).toByteArray();
+ return StreamReader.of(in, isClose).readBytes();
}
/**
@@ -464,16 +377,7 @@ public class IoUtil extends NioUtil {
* @throws IORuntimeException IO异常
*/
public static byte[] readBytes(final InputStream in, final int length) throws IORuntimeException {
- if (null == in) {
- return null;
- }
- if (length <= 0) {
- return new byte[0];
- }
-
- final FastByteArrayOutputStream out = new FastByteArrayOutputStream(length);
- copy(in, out, DEFAULT_BUFFER_SIZE, length, null);
- return out.toByteArray();
+ return StreamReader.of(in, false).readBytes(length);
}
/**
@@ -489,45 +393,6 @@ public class IoUtil extends NioUtil {
return HexUtil.encodeHexStr(readBytes(in, length), toLowerCase);
}
- /**
- * 从流中读取前28个byte并转换为16进制,字母部分使用大写
- *
- * @param in {@link InputStream}
- * @return 16进制字符串
- * @throws IORuntimeException IO异常
- */
- public static String readHex28Upper(final InputStream in) throws IORuntimeException {
- return readHex(in, 28, false);
- }
-
- /**
- * 从流中读取前28个byte并转换为16进制,字母部分使用小写
- *
- * @param in {@link InputStream}
- * @return 16进制字符串
- * @throws IORuntimeException IO异常
- */
- public static String readHex28Lower(final InputStream in) throws IORuntimeException {
- return readHex(in, 28, true);
- }
-
- /**
- * 从流中读取对象,即对象的反序列化
- *
- *
- * 此方法使用了{@link ValidateObjectInputStream}中的黑白名单方式过滤类,用于避免反序列化漏洞
- * 通过构造{@link ValidateObjectInputStream},调用{@link ValidateObjectInputStream#accept(Class[])}
- * 或者{@link ValidateObjectInputStream#refuse(Class[])}方法添加可以被序列化的类或者禁止序列化的类。
- *
@@ -1256,12 +1024,13 @@ public class IoUtil extends NioUtil {
/**
* {@link ByteArrayOutputStream} 转换为String
- * @param out {@link ByteArrayOutputStream}
+ *
+ * @param out {@link ByteArrayOutputStream}
* @param charset 编码
* @return 字符串
* @since 5.7.17
*/
- public static String toStr(final ByteArrayOutputStream out, final Charset charset){
+ public static String toStr(final ByteArrayOutputStream out, final Charset charset) {
try {
return out.toString(charset.name());
} catch (final UnsupportedEncodingException e) {
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/NioUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/NioUtil.java
index 56cfa5868..b584444c6 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/NioUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/NioUtil.java
@@ -1,6 +1,8 @@
package cn.hutool.core.io;
import cn.hutool.core.io.copy.ChannelCopier;
+import cn.hutool.core.io.copy.FileChannelCopier;
+import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.text.StrUtil;
@@ -60,74 +62,35 @@ public class NioUtil {
* 拷贝流
* 本方法不会关闭流
*
- * @param in 输入流
- * @param out 输出流
- * @param bufferSize 缓存大小
- * @param count 最大长度
- * @param streamProgress 进度条
+ * @param in 输入流, 非空
+ * @param out 输出流, 非空
+ * @param bufferSize 缓存大小,-1表示默认
+ * @param count 最大长度,-1表示无限制
+ * @param streamProgress 进度条,{@code null}表示无进度条
* @return 传输的byte数
* @throws IORuntimeException IO异常
* @since 5.7.8
*/
public static long copyByNIO(final InputStream in, final OutputStream out, final int bufferSize, final long count, final StreamProgress streamProgress) throws IORuntimeException {
+ Assert.notNull(in, "InputStream channel is null!");
+ Assert.notNull(out, "OutputStream channel is null!");
return copy(Channels.newChannel(in), Channels.newChannel(out), bufferSize, count, streamProgress);
}
/**
* 拷贝文件Channel,使用NIO,拷贝后不会关闭channel
*
- * @param inChannel {@link FileChannel}
- * @param outChannel {@link FileChannel}
+ * @param in {@link FileChannel},非空
+ * @param out {@link FileChannel},非空
* @return 拷贝的字节数
* @throws IORuntimeException IO异常
* @since 5.5.3
*/
- public static long copy(final FileChannel inChannel, final FileChannel outChannel) throws IORuntimeException {
- Assert.notNull(inChannel, "In channel is null!");
- Assert.notNull(outChannel, "Out channel is null!");
+ public static long copy(final FileChannel in, final FileChannel out) throws IORuntimeException {
+ Assert.notNull(in, "In channel is null!");
+ Assert.notNull(out, "Out channel is null!");
- try {
- return copySafely(inChannel, outChannel);
- } catch (final IOException e) {
- throw new IORuntimeException(e);
- }
- }
-
- /**
- * 文件拷贝实现
- *
- *
- * FileChannel#transferTo 或 FileChannel#transferFrom 的实现是平台相关的,需要确保低版本平台的兼容性
- * 例如 android 7以下平台在使用 ZipInputStream 解压文件的过程中,
- * 通过 FileChannel#transferFrom 传输到文件时,其返回值可能小于 totalBytes,不处理将导致文件内容缺失
- *
- * // 错误写法,dstChannel.transferFrom 返回值小于 zipEntry.getSize(),导致解压后文件内容缺失
- * try (InputStream srcStream = zipFile.getInputStream(zipEntry);
- * ReadableByteChannel srcChannel = Channels.newChannel(srcStream);
- * FileOutputStream fos = new FileOutputStream(saveFile);
- * FileChannel dstChannel = fos.getChannel()) {
- * dstChannel.transferFrom(srcChannel, 0, zipEntry.getSize());
- * }
- *
- *
- * @param inChannel 输入通道
- * @param outChannel 输出通道
- * @return 输入通道的字节数
- * @throws IOException 发生IO错误
- * @link http://androidxref.com/6.0.1_r10/xref/libcore/luni/src/main/java/java/nio/FileChannelImpl.java
- * @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/java/sun/nio/ch/FileChannelImpl.java
- * @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/native/FileChannelImpl.c
- * @author z8g
- * @since 5.7.21
- */
- private static long copySafely(final FileChannel inChannel, final FileChannel outChannel) throws IOException {
- final long totalBytes = inChannel.size();
- for (long pos = 0, remaining = totalBytes; remaining > 0; ) { // 确保文件内容不会缺失
- final long writeBytes = inChannel.transferTo(pos, remaining, outChannel); // 实际传输的字节数
- pos += writeBytes;
- remaining -= writeBytes;
- }
- return totalBytes;
+ return FileChannelCopier.of().copy(in, out);
}
/**
@@ -184,6 +147,8 @@ public class NioUtil {
* @since 5.7.8
*/
public static long copy(final ReadableByteChannel in, final WritableByteChannel out, final int bufferSize, final long count, final StreamProgress streamProgress) throws IORuntimeException {
+ Assert.notNull(in, "In channel is null!");
+ Assert.notNull(out, "Out channel is null!");
return new ChannelCopier(bufferSize, count, streamProgress).copy(in, out);
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/SerializeUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/SerializeUtil.java
index 24ae3263d..1cf940bde 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/SerializeUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/SerializeUtil.java
@@ -1,8 +1,7 @@
package cn.hutool.core.io;
import cn.hutool.core.exceptions.UtilException;
-import cn.hutool.core.io.FastByteArrayOutputStream;
-import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.Serializable;
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/ChecksumUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/ChecksumUtil.java
new file mode 100755
index 000000000..a96bc8f66
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/ChecksumUtil.java
@@ -0,0 +1,101 @@
+package cn.hutool.core.io.checksum;
+
+import cn.hutool.core.io.IORuntimeException;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.io.stream.EmptyOutputStream;
+import cn.hutool.core.lang.Assert;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.zip.CRC32;
+import java.util.zip.CheckedInputStream;
+import java.util.zip.Checksum;
+
+/**
+ * 校验码工具
+ *
+ * @author looly
+ */
+public class ChecksumUtil {
+
+ /**
+ * 计算文件CRC32校验码
+ *
+ * @param file 文件,不能为目录
+ * @return CRC32值
+ * @throws IORuntimeException IO异常
+ */
+ public static long checksumCRC32(final File file) throws IORuntimeException {
+ return checksum(file, new CRC32()).getValue();
+ }
+
+ /**
+ * 计算流CRC32校验码,计算后关闭流
+ *
+ * @param in 文件,不能为目录
+ * @return CRC32值
+ * @throws IORuntimeException IO异常
+ * @since 4.0.6
+ */
+ public static long checksumCRC32(final InputStream in) throws IORuntimeException {
+ return checksum(in, new CRC32()).getValue();
+ }
+
+ /**
+ * 计算文件校验码
+ *
+ * @param file 文件,不能为目录
+ * @param checksum {@link Checksum}
+ * @return Checksum
+ * @throws IORuntimeException IO异常
+ */
+ public static Checksum checksum(final File file, final Checksum checksum) throws IORuntimeException {
+ Assert.notNull(file, "File is null !");
+ if (file.isDirectory()) {
+ throw new IllegalArgumentException("Checksums can't be computed on directories");
+ }
+ try {
+ return checksum(new FileInputStream(file), checksum);
+ } catch (final FileNotFoundException e) {
+ throw new IORuntimeException(e);
+ }
+ }
+
+ /**
+ * 计算流的校验码,计算后关闭流
+ *
+ * @param in 流
+ * @param checksum {@link Checksum}
+ * @return Checksum
+ * @throws IORuntimeException IO异常
+ * @since 4.0.10
+ */
+ public static Checksum checksum(InputStream in, Checksum checksum) throws IORuntimeException {
+ Assert.notNull(in, "InputStream is null !");
+ if (null == checksum) {
+ checksum = new CRC32();
+ }
+ try {
+ in = new CheckedInputStream(in, checksum);
+ IoUtil.copy(in, EmptyOutputStream.INSTANCE);
+ } finally {
+ IoUtil.close(in);
+ }
+ return checksum;
+ }
+
+ /**
+ * 计算流的校验码,计算后关闭流
+ *
+ * @param in 流
+ * @param checksum {@link Checksum}
+ * @return Checksum
+ * @throws IORuntimeException IO异常
+ * @since 5.4.0
+ */
+ public static long checksumValue(final InputStream in, final Checksum checksum) {
+ return checksum(in, checksum).getValue();
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/copy/ChannelCopier.java b/hutool-core/src/main/java/cn/hutool/core/io/copy/ChannelCopier.java
index 9ba9eaf30..1909e9943 100755
--- a/hutool-core/src/main/java/cn/hutool/core/io/copy/ChannelCopier.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/copy/ChannelCopier.java
@@ -3,7 +3,6 @@ package cn.hutool.core.io.copy;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress;
-import cn.hutool.core.lang.Assert;
import java.io.IOException;
import java.io.InputStream;
@@ -59,9 +58,6 @@ public class ChannelCopier extends IoCopier
+ *
+ * {@code
+ * FileChannel#transferTo 或 FileChannel#transferFrom 的实现是平台相关的,需要确保低版本平台的兼容性
+ * 例如 android 7以下平台在使用 ZipInputStream 解压文件的过程中,
+ * 通过 FileChannel#transferFrom 传输到文件时,其返回值可能小于 totalBytes,不处理将导致文件内容缺失
+ *
+ * // 错误写法,dstChannel.transferFrom 返回值小于 zipEntry.getSize(),导致解压后文件内容缺失
+ * try (InputStream srcStream = zipFile.getInputStream(zipEntry);
+ * ReadableByteChannel srcChannel = Channels.newChannel(srcStream);
+ * FileOutputStream fos = new FileOutputStream(saveFile);
+ * FileChannel dstChannel = fos.getChannel()) {
+ * dstChannel.transferFrom(srcChannel, 0, zipEntry.getSize());
+ * }
+ * }
+ *
+ * @author z8g
+ */
+public class FileChannelCopier extends IoCopier {
+
+ /**
+ * 创建{@link FileChannel} 拷贝器
+ *
+ * @return FileChannelCopier
+ */
+ public static FileChannelCopier of() {
+ return of(-1);
+ }
+
+ /**
+ * 创建{@link FileChannel} 拷贝器
+ *
+ * @param count 拷贝总数,-1表示无限制
+ * @return FileChannelCopier
+ */
+ public static FileChannelCopier of(final long count) {
+ return new FileChannelCopier(count);
+ }
+
+ /**
+ * 构造
+ *
+ * @param count 拷贝总数,-1表示无限制
+ */
+ public FileChannelCopier(final long count) {
+ super(-1, count, null);
+ }
+
+ /**
+ * 拷贝文件流,使用NIO
+ *
+ * @param in 输入
+ * @param out 输出
+ * @return 拷贝的字节数
+ * @throws IORuntimeException IO异常
+ */
+ public long copy(final FileInputStream in, final FileOutputStream out) throws IORuntimeException {
+ FileChannel inChannel = null;
+ FileChannel outChannel = null;
+ try {
+ inChannel = in.getChannel();
+ outChannel = out.getChannel();
+ return copy(inChannel, outChannel);
+ } finally {
+ IoUtil.close(outChannel);
+ IoUtil.close(inChannel);
+ }
+ }
+
+ @Override
+ public long copy(final FileChannel source, final FileChannel target) {
+ try {
+ return doCopySafely(source, target);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+ }
+
+ /**
+ * 文件拷贝实现
+ *
+ *
+ * FileChannel#transferTo 或 FileChannel#transferFrom 的实现是平台相关的,需要确保低版本平台的兼容性
+ * 例如 android 7以下平台在使用 ZipInputStream 解压文件的过程中,
+ * 通过 FileChannel#transferFrom 传输到文件时,其返回值可能小于 totalBytes,不处理将导致文件内容缺失
+ *
+ * // 错误写法,dstChannel.transferFrom 返回值小于 zipEntry.getSize(),导致解压后文件内容缺失
+ * try (InputStream srcStream = zipFile.getInputStream(zipEntry);
+ * ReadableByteChannel srcChannel = Channels.newChannel(srcStream);
+ * FileOutputStream fos = new FileOutputStream(saveFile);
+ * FileChannel dstChannel = fos.getChannel()) {
+ * dstChannel.transferFrom(srcChannel, 0, zipEntry.getSize());
+ * }
+ *
+ *
+ * @param inChannel 输入通道
+ * @param outChannel 输出通道
+ * @return 输入通道的字节数
+ * @throws IOException 发生IO错误
+ * @link http://androidxref.com/6.0.1_r10/xref/libcore/luni/src/main/java/java/nio/FileChannelImpl.java
+ * @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/java/sun/nio/ch/FileChannelImpl.java
+ * @link http://androidxref.com/7.0.0_r1/xref/libcore/ojluni/src/main/native/FileChannelImpl.c
+ * @author z8g
+ */
+ private long doCopySafely(final FileChannel inChannel, final FileChannel outChannel) throws IOException {
+ long totalBytes = inChannel.size();
+ if (this.count > 0 && this.count < totalBytes) {
+ // 限制拷贝总数
+ totalBytes = count;
+ }
+ for (long pos = 0, remaining = totalBytes; remaining > 0; ) { // 确保文件内容不会缺失
+ final long writeBytes = inChannel.transferTo(pos, remaining, outChannel); // 实际传输的字节数
+ pos += writeBytes;
+ remaining -= writeBytes;
+ }
+ return totalBytes;
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/copy/StreamCopier.java b/hutool-core/src/main/java/cn/hutool/core/io/copy/StreamCopier.java
index 7cbdb1aec..b14f9cd1a 100755
--- a/hutool-core/src/main/java/cn/hutool/core/io/copy/StreamCopier.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/copy/StreamCopier.java
@@ -37,7 +37,7 @@ public class StreamCopier extends IoCopier {
* 构造
*
* @param bufferSize 缓存大小
- * @param count 拷贝总数
+ * @param count 拷贝总数,-1表示无限制
*/
public StreamCopier(final int bufferSize, final long count) {
this(bufferSize, count, null);
@@ -47,7 +47,7 @@ public class StreamCopier extends IoCopier {
* 构造
*
* @param bufferSize 缓存大小
- * @param count 拷贝总数
+ * @param count 拷贝总数,-1表示无限制
* @param progress 进度条
*/
public StreamCopier(final int bufferSize, final long count, final StreamProgress progress) {
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/FileReader.java b/hutool-core/src/main/java/cn/hutool/core/io/file/FileReader.java
index d03744fe4..0b73ad6a4 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/file/FileReader.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/file/FileReader.java
@@ -228,7 +228,7 @@ public class FileReader extends FileWrapper {
* @throws IORuntimeException IO异常
*/
public BufferedReader getReader() throws IORuntimeException {
- return IoUtil.getReader(getInputStream(), this.charset);
+ return IoUtil.toReader(getInputStream(), this.charset);
}
/**
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java
index 75fe5030b..9a7f22a4f 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java
@@ -416,7 +416,7 @@ public class PathUtil {
* @since 4.0.0
*/
public static BufferedReader getReader(final Path path, final Charset charset) throws IORuntimeException {
- return IoUtil.getReader(getInputStream(path), charset);
+ return IoUtil.toReader(getInputStream(path), charset);
}
/**
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/CharSequenceResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/CharSequenceResource.java
index 5c083ae18..ba60257d4 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/resource/CharSequenceResource.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/CharSequenceResource.java
@@ -75,7 +75,7 @@ public class CharSequenceResource implements Resource, Serializable {
@Override
public BufferedReader getReader(final Charset charset) {
- return IoUtil.getReader(new StringReader(this.data.toString()));
+ return IoUtil.toBuffered(new StringReader(this.data.toString()));
}
@Override
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/FileObjectResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/FileObjectResource.java
index 6dc6b8c1a..008528684 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/resource/FileObjectResource.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/FileObjectResource.java
@@ -65,7 +65,7 @@ public class FileObjectResource implements Resource {
@Override
public BufferedReader getReader(final Charset charset) {
try {
- return IoUtil.getReader(this.fileObject.openReader(false));
+ return IoUtil.toBuffered(this.fileObject.openReader(false));
} catch (final IOException e) {
throw new IORuntimeException(e);
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/MultiFileResource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/MultiFileResource.java
index 25920db98..449cbf5b6 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/resource/MultiFileResource.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/MultiFileResource.java
@@ -1,6 +1,7 @@
package cn.hutool.core.io.resource;
import java.io.File;
+import java.nio.file.Path;
import java.util.Collection;
/**
@@ -8,9 +9,8 @@ import java.util.Collection;
* 此资源为一个利用游标自循环资源,只有调用{@link #next()} 方法才会获取下一个资源,使用完毕后调用{@link #reset()}方法重置游标
*
* @author looly
- *
*/
-public class MultiFileResource extends MultiResource{
+public class MultiFileResource extends MultiResource {
private static final long serialVersionUID = 1L;
/**
@@ -31,6 +31,15 @@ public class MultiFileResource extends MultiResource{
add(files);
}
+ /**
+ * 构造
+ *
+ * @param files 文件资源列表
+ */
+ public MultiFileResource(final Path... files) {
+ add(files);
+ }
+
/**
* 增加文件资源
*
@@ -44,6 +53,19 @@ public class MultiFileResource extends MultiResource{
return this;
}
+ /**
+ * 增加文件资源
+ *
+ * @param files 文件资源
+ * @return this
+ */
+ public MultiFileResource add(final Path... files) {
+ for (final Path file : files) {
+ this.add(new FileResource(file));
+ }
+ return this;
+ }
+
/**
* 增加文件资源
*
@@ -59,6 +81,6 @@ public class MultiFileResource extends MultiResource{
@Override
public MultiFileResource add(final Resource resource) {
- return (MultiFileResource)super.add(resource);
+ return (MultiFileResource) super.add(resource);
}
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/Resource.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/Resource.java
index cb7268151..7f4ba5e9a 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/resource/Resource.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/Resource.java
@@ -86,7 +86,7 @@ public interface Resource {
* @return {@link BufferedReader}
*/
default BufferedReader getReader(final Charset charset) {
- return IoUtil.getReader(getStream(), charset);
+ return IoUtil.toReader(getStream(), charset);
}
/**
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/BOMInputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/BOMInputStream.java
similarity index 97%
rename from hutool-core/src/main/java/cn/hutool/core/io/BOMInputStream.java
rename to hutool-core/src/main/java/cn/hutool/core/io/stream/BOMInputStream.java
index a78ed72ca..2aac0e339 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/BOMInputStream.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/BOMInputStream.java
@@ -1,5 +1,6 @@
-package cn.hutool.core.io;
+package cn.hutool.core.io.stream;
+import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.CharsetUtil;
import java.io.IOException;
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/EmptyInputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/EmptyInputStream.java
similarity index 96%
rename from hutool-core/src/main/java/cn/hutool/core/io/EmptyInputStream.java
rename to hutool-core/src/main/java/cn/hutool/core/io/stream/EmptyInputStream.java
index d13c53e43..6afc9ffbf 100755
--- a/hutool-core/src/main/java/cn/hutool/core/io/EmptyInputStream.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/EmptyInputStream.java
@@ -1,4 +1,4 @@
-package cn.hutool.core.io;
+package cn.hutool.core.io.stream;
import java.io.InputStream;
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/NullOutputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/EmptyOutputStream.java
similarity index 72%
rename from hutool-core/src/main/java/cn/hutool/core/io/NullOutputStream.java
rename to hutool-core/src/main/java/cn/hutool/core/io/stream/EmptyOutputStream.java
index 6f48a8041..c6de0ac74 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/NullOutputStream.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/EmptyOutputStream.java
@@ -1,4 +1,4 @@
-package cn.hutool.core.io;
+package cn.hutool.core.io.stream;
import java.io.IOException;
import java.io.OutputStream;
@@ -10,20 +10,24 @@ import java.io.OutputStream;
* @author looly
* @since 4.0.6
*/
-public class NullOutputStream extends OutputStream {
+public class EmptyOutputStream extends OutputStream {
/**
* 单例
*/
- public static final NullOutputStream NULL_OUTPUT_STREAM = new NullOutputStream();
+ public static final EmptyOutputStream INSTANCE = new EmptyOutputStream();
+
+ private EmptyOutputStream() {
+ }
/**
* 什么也不做,写出到{@code /dev/null}.
*
- * @param b 写出的数据
+ * @param b 写出的数据
* @param off 开始位置
* @param len 长度
*/
+ @SuppressWarnings("NullableProblems")
@Override
public void write(final byte[] b, final int off, final int len) {
// to /dev/null
@@ -45,6 +49,7 @@ public class NullOutputStream extends OutputStream {
* @param b 写出的数据
* @throws IOException 不抛出
*/
+ @SuppressWarnings("NullableProblems")
@Override
public void write(final byte[] b) throws IOException {
// to /dev/null
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FastByteArrayOutputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/FastByteArrayOutputStream.java
similarity index 95%
rename from hutool-core/src/main/java/cn/hutool/core/io/FastByteArrayOutputStream.java
rename to hutool-core/src/main/java/cn/hutool/core/io/stream/FastByteArrayOutputStream.java
index a4c4ff06b..4cabf329c 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/FastByteArrayOutputStream.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/FastByteArrayOutputStream.java
@@ -1,5 +1,7 @@
-package cn.hutool.core.io;
+package cn.hutool.core.io.stream;
+import cn.hutool.core.io.FastByteBuffer;
+import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjUtil;
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/stream/StrInputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/StrInputStream.java
new file mode 100755
index 000000000..c98c1fe97
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/StrInputStream.java
@@ -0,0 +1,47 @@
+package cn.hutool.core.io.stream;
+
+import cn.hutool.core.text.StrUtil;
+import cn.hutool.core.util.CharsetUtil;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.Charset;
+
+/**
+ * 基于字符串的InputStream
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class StrInputStream extends ByteArrayInputStream {
+
+ /**
+ * 创建StrInputStream
+ *
+ * @param str 字符串
+ * @return StrInputStream
+ */
+ public static StrInputStream ofUtf8(final CharSequence str) {
+ return of(str, CharsetUtil.UTF_8);
+ }
+
+ /**
+ * 创建StrInputStream
+ *
+ * @param str 字符串
+ * @param charset 编码
+ * @return StrInputStream
+ */
+ public static StrInputStream of(final CharSequence str, final Charset charset) {
+ return new StrInputStream(str, charset);
+ }
+
+ /**
+ * 构造
+ *
+ * @param str 字符串
+ * @param charset 编码
+ */
+ public StrInputStream(final CharSequence str, final Charset charset) {
+ super(StrUtil.bytes(str, charset));
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/stream/StreamReader.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/StreamReader.java
new file mode 100755
index 000000000..b29bae21d
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/StreamReader.java
@@ -0,0 +1,160 @@
+package cn.hutool.core.io.stream;
+
+import cn.hutool.core.exceptions.UtilException;
+import cn.hutool.core.io.IORuntimeException;
+import cn.hutool.core.io.IoUtil;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link InputStream}读取器
+ *
+ * @author looly
+ */
+public class StreamReader {
+
+ /**
+ * 创建读取器
+ *
+ * @param in {@link InputStream}
+ * @param closeAfterRead 读取结束后是否关闭输入流
+ * @return StreamReader
+ */
+ public static StreamReader of(final InputStream in, final boolean closeAfterRead) {
+ return new StreamReader(in, closeAfterRead);
+ }
+
+ private final InputStream in;
+ private final boolean closeAfterRead;
+
+ /**
+ * 构造
+ *
+ * @param in {@link InputStream}
+ * @param closeAfterRead 读取结束后是否关闭输入流
+ */
+ public StreamReader(final InputStream in, final boolean closeAfterRead) {
+ this.in = in;
+ this.closeAfterRead = closeAfterRead;
+ }
+
+ /**
+ * 从流中读取bytes
+ *
+ * @return bytes
+ * @throws IORuntimeException IO异常
+ */
+ public byte[] readBytes() throws IORuntimeException {
+ return readBytes(-1);
+ }
+
+ /**
+ * 读取指定长度的byte数组
+ *
+ * @param length 长度,小于0表示读取全部
+ * @return bytes
+ * @throws IORuntimeException IO异常
+ */
+ public byte[] readBytes(final int length) throws IORuntimeException {
+ final InputStream in = this.in;
+ if (null == in || length == 0) {
+ return new byte[0];
+ }
+
+ //noinspection resource
+ return read(length).toByteArray();
+ }
+
+ /**
+ * 从流中读取内容,读到输出流中,读取完毕后可选是否关闭流
+ *
+ * @return 输出流
+ * @throws IORuntimeException IO异常
+ */
+ public FastByteArrayOutputStream read() throws IORuntimeException {
+ return read(-1);
+ }
+
+ /**
+ * 从流中读取内容,读到输出流中,读取完毕后可选是否关闭流
+ *
+ * @param limit 限制最大拷贝长度,-1表示无限制
+ * @return 输出流
+ * @throws IORuntimeException IO异常
+ */
+ public FastByteArrayOutputStream read(final int limit) throws IORuntimeException {
+ final InputStream in = this.in;
+ final FastByteArrayOutputStream out;
+ if (in instanceof FileInputStream) {
+ // 文件流的长度是可预见的,此时直接读取效率更高
+ try {
+ int length = in.available();
+ if (limit > 0 && limit < length) {
+ length = limit;
+ }
+ out = new FastByteArrayOutputStream(length);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+ } else {
+ out = new FastByteArrayOutputStream();
+ }
+ try {
+ IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE, limit, null);
+ } finally {
+ if (closeAfterRead) {
+ IoUtil.close(in);
+ }
+ }
+ return out;
+ }
+
+ /**
+ * 从流中读取对象,即对象的反序列化
+ *
+ * 注意!!! 此方法不会检查反序列化安全,可能存在反序列化漏洞风险!!!
+ *
+ *
+ * 此方法使用了{@link ValidateObjectInputStream}中的黑白名单方式过滤类,用于避免反序列化漏洞
+ * 通过构造{@link ValidateObjectInputStream},调用{@link ValidateObjectInputStream#accept(Class[])}
+ * 或者{@link ValidateObjectInputStream#refuse(Class[])}方法添加可以被序列化的类或者禁止序列化的类。
+ *
+ *
+ * @param 读取对象的类型
+ * @param acceptClasses 读取对象类型
+ * @return 输出流
+ * @throws IORuntimeException IO异常
+ * @throws UtilException ClassNotFoundException包装
+ */
+ @SuppressWarnings("unchecked")
+ public T readObj(final Class>... acceptClasses) throws IORuntimeException, UtilException {
+ final InputStream in = this.in;
+ if (null == in) {
+ return null;
+ }
+
+ // 转换
+ final ValidateObjectInputStream validateIn;
+ if (in instanceof ValidateObjectInputStream) {
+ validateIn = (ValidateObjectInputStream) in;
+ validateIn.accept(acceptClasses);
+ } else {
+ try {
+ validateIn = new ValidateObjectInputStream(in, acceptClasses);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+ }
+
+ // 读取
+ try {
+ return (T) validateIn.readObject();
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ } catch (final ClassNotFoundException e) {
+ throw new UtilException(e);
+ }
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/stream/StreamWriter.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/StreamWriter.java
new file mode 100755
index 000000000..9cca8f043
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/StreamWriter.java
@@ -0,0 +1,115 @@
+package cn.hutool.core.io.stream;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.IORuntimeException;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.text.StrUtil;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
+
+/**
+ * {@link OutputStream}写出器
+ *
+ * @author looly
+ */
+public class StreamWriter {
+
+ /**
+ * 创建写出器
+ *
+ * @param out {@link OutputStream}
+ * @param closeAfterWrite 写出结束后是否关闭流
+ * @return StreamReader
+ */
+ public static StreamWriter of(final OutputStream out, final boolean closeAfterWrite) {
+ return new StreamWriter(out, closeAfterWrite);
+ }
+
+ private final OutputStream out;
+ private final boolean closeAfterWrite;
+
+ /**
+ * 构造
+ *
+ * @param out {@link OutputStream}
+ * @param closeAfterWrite 写出结束后是否关闭流
+ */
+ public StreamWriter(final OutputStream out, final boolean closeAfterWrite) {
+ this.out = out;
+ this.closeAfterWrite = closeAfterWrite;
+ }
+
+ /**
+ * 将byte[]写到流中
+ *
+ * @param content 写入的内容
+ * @throws IORuntimeException IO异常
+ */
+ public void write(final byte[] content) throws IORuntimeException {
+ final OutputStream out = this.out;
+ try {
+ out.write(content);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ } finally {
+ if (closeAfterWrite) {
+ IoUtil.close(out);
+ }
+ }
+ }
+
+ /**
+ * 将多部分对象写到流中,使用{@link ObjectOutputStream},对象必须实现序列化接口
+ *
+ * @param contents 写入的内容
+ * @throws IORuntimeException IO异常
+ */
+ public void writeObj(final Object... contents) throws IORuntimeException {
+ ObjectOutputStream osw = null;
+ try {
+ osw = out instanceof ObjectOutputStream ? (ObjectOutputStream) out : new ObjectOutputStream(out);
+ for (final Object content : contents) {
+ if (content != null) {
+ osw.writeObject(content);
+ }
+ }
+ osw.flush();
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ } finally {
+ if (closeAfterWrite) {
+ IoUtil.close(osw);
+ }
+ }
+ }
+
+ /**
+ * 将多部分内容写到流中,自动转换为字符串
+ *
+ * @param charset 写出的内容的字符集
+ * @param contents 写入的内容,调用toString()方法,不包括不会自动换行
+ * @throws IORuntimeException IO异常
+ */
+ public void writeStr(final Charset charset, final Object... contents) throws IORuntimeException {
+ OutputStreamWriter osw = null;
+ try {
+ osw = IoUtil.toWriter(out, charset);
+ for (final Object content : contents) {
+ if (content != null) {
+ osw.write(Convert.toStr(content, StrUtil.EMPTY));
+ }
+ }
+ osw.flush();
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ } finally {
+ if (closeAfterWrite) {
+ IoUtil.close(osw);
+ }
+ }
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/ValidateObjectInputStream.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/ValidateObjectInputStream.java
similarity index 98%
rename from hutool-core/src/main/java/cn/hutool/core/io/ValidateObjectInputStream.java
rename to hutool-core/src/main/java/cn/hutool/core/io/stream/ValidateObjectInputStream.java
index 788305cbf..850f381fc 100644
--- a/hutool-core/src/main/java/cn/hutool/core/io/ValidateObjectInputStream.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/ValidateObjectInputStream.java
@@ -1,4 +1,4 @@
-package cn.hutool.core.io;
+package cn.hutool.core.io.stream;
import cn.hutool.core.collection.CollUtil;
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/stream/package-info.java b/hutool-core/src/main/java/cn/hutool/core/io/stream/package-info.java
new file mode 100755
index 000000000..ebf2a5002
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/io/stream/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * InputStream和OutputStream相关方法和类封装
+ *
+ * @author looly
+ */
+package cn.hutool.core.io.stream;
diff --git a/hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartRequestInputStream.java b/hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartRequestInputStream.java
index 333f813e5..0425cc3ba 100644
--- a/hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartRequestInputStream.java
+++ b/hutool-core/src/main/java/cn/hutool/core/net/multipart/MultipartRequestInputStream.java
@@ -1,6 +1,6 @@
package cn.hutool.core.net.multipart;
-import cn.hutool.core.io.FastByteArrayOutputStream;
+import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
diff --git a/hutool-core/src/main/java/cn/hutool/core/net/url/URLUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/url/URLUtil.java
index 163dfcf78..69d1213a4 100644
--- a/hutool-core/src/main/java/cn/hutool/core/net/url/URLUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/net/url/URLUtil.java
@@ -465,7 +465,7 @@ public class URLUtil {
* @since 3.2.1
*/
public static BufferedReader getReader(final URL url, final Charset charset) {
- return IoUtil.getReader(getStream(url), charset);
+ return IoUtil.toReader(getStream(url), charset);
}
/**
diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java
index c4964cd87..6381187bb 100755
--- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java
@@ -2506,7 +2506,7 @@ public class CharSequenceUtil extends StrChecker {
* @param charset 编码
* @return byteBuffer
*/
- public static ByteBuffer byteBuffer(final CharSequence str, final String charset) {
+ public static ByteBuffer byteBuffer(final CharSequence str, final Charset charset) {
return ByteBuffer.wrap(bytes(str, charset));
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/io/FileTypeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/FileTypeUtilTest.java
index f834031c8..b57267d41 100755
--- a/hutool-core/src/test/java/cn/hutool/core/io/FileTypeUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/io/FileTypeUtilTest.java
@@ -1,6 +1,6 @@
package cn.hutool.core.io;
-import cn.hutool.core.codec.HexUtil;
+import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Console;
import org.junit.Assert;
import org.junit.Ignore;
@@ -12,21 +12,32 @@ import java.io.IOException;
/**
* 文件类型判断单元测试
- * @author Looly
*
+ * @author Looly
*/
public class FileTypeUtilTest {
@Test
- @Ignore
- public void fileTypeUtilTest() {
+ public void getTypeTest() {
+ final String type = FileTypeUtil.getType(ResourceUtil.getStream("hutool.jpg"));
+ Assert.assertEquals("jpg", type);
+ }
+
+ @Test
+ public void customTypeTest() {
final File file = FileUtil.file("hutool.jpg");
final String type = FileTypeUtil.getType(file);
Assert.assertEquals("jpg", type);
- FileTypeUtil.putFileType("ffd8ffe000104a464946", "new_jpg");
+ final String oldType = FileTypeUtil.putFileType("ffd8ffe000104a464946", "new_jpg");
+ Assert.assertNull(oldType);
+
final String newType = FileTypeUtil.getType(file);
Assert.assertEquals("new_jpg", newType);
+
+ FileTypeUtil.removeFileType("ffd8ffe000104a464946");
+ final String type2 = FileTypeUtil.getType(file);
+ Assert.assertEquals("jpg", type2);
}
@Test
@@ -49,7 +60,7 @@ public class FileTypeUtilTest {
@Ignore
public void ofdTest() {
final File file = FileUtil.file("e:/test.ofd");
- final String hex = IoUtil.readHex28Upper(FileUtil.getInputStream(file));
+ final String hex = FileTypeUtil.readHex28Upper(FileUtil.getInputStream(file));
Console.log(hex);
final String type = FileTypeUtil.getType(file);
Console.log(type);
@@ -72,13 +83,14 @@ public class FileTypeUtilTest {
final BufferedInputStream inputStream = FileUtil.getInputStream(file);
inputStream.mark(0);
final String type = FileTypeUtil.getType(inputStream);
+ Assert.assertEquals("jpg", type);
inputStream.reset();
}
@Test
@Ignore
- public void webpTest(){
+ public void webpTest() {
// https://gitee.com/dromara/hutool/issues/I5BGTF
final File file = FileUtil.file("d:/test/a.webp");
final BufferedInputStream inputStream = FileUtil.getInputStream(file);
@@ -87,8 +99,14 @@ public class FileTypeUtilTest {
}
@Test
- public void getHexTest() {
- final String id3 = HexUtil.encodeHexStr("8BPS");
- Console.log(id3);
+ public void readHex28LowerTest() {
+ final String s = FileTypeUtil.readHex28Lower(ResourceUtil.getStream("hutool.jpg"));
+ Assert.assertEquals("ffd8ffe000104a46494600010101006000600000ffe1095845786966", s);
+ }
+
+ @Test
+ public void readHex28UpperTest() {
+ final String s = FileTypeUtil.readHex28Upper(ResourceUtil.getStream("hutool.jpg"));
+ Assert.assertEquals("FFD8FFE000104A46494600010101006000600000FFE1095845786966", s);
}
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java
index 9462c3234..dee7b2806 100644
--- a/hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java
@@ -1,13 +1,27 @@
package cn.hutool.core.io;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.collection.iter.LineIter;
import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.io.stream.EmptyOutputStream;
+import cn.hutool.core.io.stream.StrInputStream;
import cn.hutool.core.lang.func.SerConsumer;
+import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
import org.junit.Assert;
import org.junit.Test;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackReader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
public class IoUtilTest {
@@ -33,4 +47,111 @@ public class IoUtilTest {
throw new IORuntimeException(e);
}
}
+
+ @Test
+ public void readUtf8LinesTest() {
+ final ArrayList strings = IoUtil.readUtf8Lines(ResourceUtil.getStream("text.txt"), ListUtil.of());
+ Assert.assertEquals(3, strings.size());
+ }
+
+ @Test
+ public void readUtf8LinesTest2() {
+ IoUtil.readUtf8Lines(ResourceUtil.getStream("text.txt"), (SerConsumer) Assert::assertNotNull);
+ }
+
+ @Test
+ public void toBufferedTest() {
+ final BufferedInputStream stream = IoUtil.toBuffered(
+ new ByteArrayInputStream("hutool".getBytes()), IoUtil.DEFAULT_BUFFER_SIZE);
+
+ Assert.assertNotNull(stream);
+ Assert.assertEquals("hutool", IoUtil.readUtf8(stream));
+ }
+
+ @Test
+ public void toBufferedOfOutTest() {
+ final BufferedOutputStream stream = IoUtil.toBuffered(
+ EmptyOutputStream.INSTANCE, 512);
+
+ Assert.assertNotNull(stream);
+ }
+
+ @Test
+ public void toBufferedOfReaderTest() {
+ final BufferedReader reader = IoUtil.toBuffered(
+ new StringReader("hutool"), 512);
+
+ Assert.assertNotNull(reader);
+
+ Assert.assertEquals("hutool", IoUtil.read(reader));
+ }
+
+ @Test
+ public void toBufferedOfWriterTest() throws IOException {
+ final StringWriter stringWriter = new StringWriter();
+ final BufferedWriter writer = IoUtil.toBuffered(
+ stringWriter, 512);
+
+ Assert.assertNotNull(writer);
+ writer.write("hutool");
+ writer.flush();
+
+ Assert.assertEquals("hutool", stringWriter.toString());
+ }
+
+ @Test
+ public void toBufferedOfWriterTest2() throws IOException {
+ final StringWriter stringWriter = new StringWriter();
+ final BufferedWriter writer = IoUtil.toBuffered(stringWriter);
+
+ Assert.assertNotNull(writer);
+ writer.write("hutool");
+ writer.flush();
+
+ Assert.assertEquals("hutool", stringWriter.toString());
+ }
+
+ @Test
+ public void toPushBackReaderTest() throws IOException {
+ final PushbackReader reader = IoUtil.toPushBackReader(new StringReader("hutool"), 12);
+ final int read = reader.read();
+ Assert.assertEquals('h', read);
+ reader.unread(read);
+
+ Assert.assertEquals("hutool", IoUtil.read(reader));
+ }
+
+ @Test
+ public void toAvailableStreamTest() {
+ final InputStream in = IoUtil.toAvailableStream(StrInputStream.ofUtf8("hutool"));
+ final String read = IoUtil.readUtf8(in);
+ Assert.assertEquals("hutool", read);
+ }
+
+ @Test
+ public void writeCloseTest() {
+ IoUtil.writeClose(EmptyOutputStream.INSTANCE, "hutool".getBytes());
+ }
+
+ @Test
+ public void writeUtf8Test() {
+ IoUtil.writeUtf8(EmptyOutputStream.INSTANCE, false, "hutool");
+ }
+
+ @Test
+ public void closeIfPossibleTest() {
+ IoUtil.closeIfPossible(new Object());
+ }
+
+ @Test
+ public void contentEqualsTest() {
+ final boolean b = IoUtil.contentEquals(new StringReader("hutool"), new StringReader("hutool"));
+ Assert.assertTrue(b);
+ }
+
+ @Test
+ public void lineIterTest() {
+ final LineIter strings = IoUtil.lineIter(ResourceUtil.getStream("text.txt"), CharsetUtil.UTF_8);
+ strings.forEach(Assert::assertNotNull);
+ }
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/io/NioUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/NioUtilTest.java
new file mode 100755
index 000000000..b1d9f4d3e
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/core/io/NioUtilTest.java
@@ -0,0 +1,24 @@
+package cn.hutool.core.io;
+
+import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.io.stream.EmptyOutputStream;
+import cn.hutool.core.text.StrUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+public class NioUtilTest {
+ @Test
+ public void copyByNIOTest() {
+ final long size = NioUtil.copyByNIO(ResourceUtil.getStream("hutool.jpg"), EmptyOutputStream.INSTANCE, NioUtil.DEFAULT_MIDDLE_BUFFER_SIZE, null);
+ Assert.assertEquals(22807, size);
+ }
+
+ @Test
+ public void readUtf8Test() throws IOException {
+ final String s = NioUtil.readUtf8(FileChannel.open(FileUtil.file("text.txt").toPath()));
+ Assert.assertTrue(StrUtil.isNotBlank(s));
+ }
+}
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/ASN1Util.java b/hutool-crypto/src/main/java/cn/hutool/crypto/ASN1Util.java
index d4ff26d90..68b73911b 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/ASN1Util.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/ASN1Util.java
@@ -1,6 +1,6 @@
package cn.hutool.crypto;
-import cn.hutool.core.io.FastByteArrayOutputStream;
+import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.core.io.IORuntimeException;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Encoding;
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java
index c94d7fb60..6017e9966 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java
@@ -122,7 +122,7 @@ public class PemUtil {
* @since 4.5.2
*/
public static PemObject readPemObject(final InputStream keyStream) {
- return readPemObject(IoUtil.getUtf8Reader(keyStream));
+ return readPemObject(IoUtil.toUtf8Reader(keyStream));
}
/**
@@ -189,7 +189,7 @@ public class PemUtil {
* @since 5.1.6
*/
public static void writePemObject(final PemObjectGenerator pemObject, final OutputStream keyStream) {
- writePemObject(pemObject, IoUtil.getUtf8Writer(keyStream));
+ writePemObject(pemObject, IoUtil.toUtf8Writer(keyStream));
}
/**
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricCrypto.java b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricCrypto.java
index 0f18ec68e..4019b3050 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricCrypto.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricCrypto.java
@@ -1,7 +1,7 @@
package cn.hutool.crypto.asymmetric;
import cn.hutool.core.codec.BaseN.Base64;
-import cn.hutool.core.io.FastByteArrayOutputStream;
+import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.crypto.CipherWrapper;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.KeyUtil;
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricEncryptor.java b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricEncryptor.java
index 0a420cee7..02d1922f8 100755
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricEncryptor.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricEncryptor.java
@@ -54,18 +54,6 @@ public interface AsymmetricEncryptor {
return Base64.encode(encrypt(data, keyType));
}
- /**
- * 加密
- *
- * @param data 被加密的字符串
- * @param charset 编码
- * @param keyType 私钥或公钥 {@link KeyType}
- * @return 加密后的bytes
- */
- default byte[] encrypt(final String data, final String charset, final KeyType keyType) {
- return encrypt(StrUtil.bytes(data, charset), keyType);
- }
-
/**
* 加密
*
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricEncryptor.java b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricEncryptor.java
index 3f67517d5..3b3e91e42 100755
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricEncryptor.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricEncryptor.java
@@ -62,17 +62,6 @@ public interface SymmetricEncryptor {
return Base64.encode(encrypt(data));
}
- /**
- * 加密
- *
- * @param data 被加密的字符串
- * @param charset 编码
- * @return 加密后的bytes
- */
- default byte[] encrypt(final String data, final String charset) {
- return encrypt(StrUtil.bytes(data, charset));
- }
-
/**
* 加密
*
@@ -84,17 +73,6 @@ public interface SymmetricEncryptor {
return encrypt(StrUtil.bytes(data, charset));
}
- /**
- * 加密
- *
- * @param data 被加密的字符串
- * @param charset 编码
- * @return 加密后的Hex
- */
- default String encryptHex(final String data, final String charset) {
- return HexUtil.encodeHexStr(encrypt(data, charset));
- }
-
/**
* 加密
*
@@ -106,17 +84,6 @@ public interface SymmetricEncryptor {
return HexUtil.encodeHexStr(encrypt(data, charset));
}
- /**
- * 加密
- *
- * @param data 被加密的字符串
- * @param charset 编码
- * @return 加密后的Base64
- */
- default String encryptBase64(final String data, final String charset) {
- return Base64.encode(encrypt(data, charset));
- }
-
/**
* 加密
*
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerTemplate.java
index 0540ff76b..397f6b0ad 100644
--- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerTemplate.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/freemarker/FreemarkerTemplate.java
@@ -54,7 +54,7 @@ public class FreemarkerTemplate implements Template, Serializable{
@Override
public void render(final Map, ?> bindingMap, final OutputStream out) {
- render(bindingMap, IoUtil.getWriter(out, Charset.forName(this.rawTemplate.getEncoding())));
+ render(bindingMap, IoUtil.toWriter(out, Charset.forName(this.rawTemplate.getEncoding())));
}
}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafTemplate.java
index 3fe35f0e1..a5c382a77 100755
--- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafTemplate.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/thymeleaf/ThymeleafTemplate.java
@@ -63,7 +63,7 @@ public class ThymeleafTemplate implements Template, Serializable {
@Override
public void render(final Map, ?> bindingMap, final OutputStream out) {
- render(bindingMap, IoUtil.getWriter(out, this.charset));
+ render(bindingMap, IoUtil.toWriter(out, this.charset));
}
}
diff --git a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityTemplate.java b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityTemplate.java
index 08db8f269..8191f0665 100755
--- a/hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityTemplate.java
+++ b/hutool-extra/src/main/java/cn/hutool/extra/template/engine/velocity/VelocityTemplate.java
@@ -56,7 +56,7 @@ public class VelocityTemplate implements Template, Serializable {
if(null == charset) {
loadEncoding();
}
- render(bindingMap, IoUtil.getWriter(out, CharsetUtil.charset(this.charset)));
+ render(bindingMap, IoUtil.toWriter(out, CharsetUtil.charset(this.charset)));
}
/**
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/HttpDownloader.java b/hutool-http/src/main/java/cn/hutool/http/client/HttpDownloader.java
index 8bcf252d0..435f8997d 100644
--- a/hutool-http/src/main/java/cn/hutool/http/client/HttpDownloader.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/HttpDownloader.java
@@ -1,6 +1,6 @@
package cn.hutool.http.client;
-import cn.hutool.core.io.FastByteArrayOutputStream;
+import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpException;
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/body/FormBody.java b/hutool-http/src/main/java/cn/hutool/http/client/body/FormBody.java
new file mode 100755
index 000000000..3fd6a6089
--- /dev/null
+++ b/hutool-http/src/main/java/cn/hutool/http/client/body/FormBody.java
@@ -0,0 +1,120 @@
+package cn.hutool.http.client.body;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.resource.FileResource;
+import cn.hutool.core.io.resource.MultiFileResource;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.map.TableMap;
+import cn.hutool.core.text.StrUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjUtil;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.nio.file.Path;
+import java.util.Map;
+
+/**
+ * Form表单形式的消息体
+ *
+ * @param this类型,用于链式调用
+ * @author looly
+ */
+@SuppressWarnings("unchecked")
+public abstract class FormBody> implements RequestBody {
+ /**
+ * 存储表单数据
+ */
+ protected Map form;
+ /**
+ * 编码
+ */
+ protected final Charset charset;
+
+ /**
+ * 构造
+ *
+ * @param form 表单
+ * @param charset 编码
+ */
+ protected FormBody(final Map form, final Charset charset) {
+ this.form = form;
+ this.charset = charset;
+ }
+
+ /**
+ * 设置map类型表单数据
+ *
+ * @param formMap 表单内容
+ * @return this
+ */
+ public T form(final Map formMap) {
+ if (MapUtil.isNotEmpty(formMap)) {
+ formMap.forEach(this::form);
+ }
+ return (T) this;
+ }
+
+ /**
+ * 设置表单数据
+ * 如果传入值为{@code null},则移除这个表单项
+ *
+ * @param name 名,blank则忽略之
+ * @param value 值为{@code null},则移除这个表单项
+ * @return this
+ */
+ public T form(final String name, final Object value) {
+ if (StrUtil.isBlank(name)) {
+ return (T) this; // 忽略非法的form表单项内容;
+ }
+ if(ObjUtil.isNull(value)){
+ this.form.remove(name);
+ }
+
+ if (value instanceof File) {
+ return putToForm(name, new FileResource((File) value));
+ } else if(value instanceof Path){
+ return putToForm(name, new FileResource((Path) value));
+ }
+
+ // 普通值
+ final String strValue;
+ if (value instanceof Iterable) {
+ // 列表对象
+ strValue = CollUtil.join((Iterable>) value, ",");
+ } else if (ArrayUtil.isArray(value)) {
+ final Class> componentType = ArrayUtil.getComponentType(value);
+ // 多文件
+ if (File.class == componentType) {
+ return putToForm(name, new MultiFileResource((File[])value));
+ } else if (Path.class == componentType) {
+ return putToForm(name, new MultiFileResource((Path[])value));
+ }
+ // 数组对象
+ strValue = ArrayUtil.join(value, ",");
+ } else {
+ // 其他对象一律转换为字符串
+ strValue = Convert.toStr(value, null);
+ }
+
+ return putToForm(name, strValue);
+ }
+
+ /**
+ * 将参数加入到form中,如果form为空,新建之。
+ *
+ * @param name 表单属性名
+ * @param value 属性值
+ * @return this
+ */
+ private T putToForm(final String name, final Object value) {
+ if (null != name && null != value) {
+ if (null == this.form) {
+ this.form = new TableMap<>(16);
+ }
+ this.form.put(name, value);
+ }
+ return (T) this;
+ }
+}
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/body/MultipartBody.java b/hutool-http/src/main/java/cn/hutool/http/client/body/MultipartBody.java
index 8382562f6..f3fa4e8fb 100644
--- a/hutool-http/src/main/java/cn/hutool/http/client/body/MultipartBody.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/body/MultipartBody.java
@@ -17,32 +17,48 @@ import java.util.Map;
* @author looly
* @since 5.3.5
*/
-public class MultipartBody implements RequestBody {
+public class MultipartBody extends FormBody {
private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary=";
- /**
- * 存储表单数据
- */
- private final Map form;
- /**
- * 编码
- */
- private final Charset charset;
/**
* 边界
*/
- private final String boundary = HttpGlobalConfig.getBoundary();
+ private final String boundary;
/**
- * 根据已有表单内容,构建MultipartBody
+ * 根据已有表单内容,构建MultipartBody,使用全局默认的边界符{@link HttpGlobalConfig#getBoundary()}
*
* @param form 表单
* @param charset 编码
* @return MultipartBody
*/
public static MultipartBody of(final Map form, final Charset charset) {
- return new MultipartBody(form, charset);
+ return of(form, charset, HttpGlobalConfig.getBoundary());
+ }
+
+ /**
+ * 根据已有表单内容,构建MultipartBody
+ *
+ * @param form 表单
+ * @param charset 编码
+ * @param boundary Multipart边界符
+ * @return MultipartBody
+ */
+ public static MultipartBody of(final Map form, final Charset charset, final String boundary) {
+ return new MultipartBody(form, charset, boundary);
+ }
+
+ /**
+ * 构造
+ *
+ * @param form 表单
+ * @param charset 编码
+ * @param boundary Multipart边界符
+ */
+ public MultipartBody(final Map form, final Charset charset, final String boundary) {
+ super(form, charset);
+ this.boundary = boundary;
}
/**
@@ -54,17 +70,6 @@ public class MultipartBody implements RequestBody {
return CONTENT_TYPE_MULTIPART_PREFIX + boundary;
}
- /**
- * 构造
- *
- * @param form 表单
- * @param charset 编码
- */
- public MultipartBody(final Map form, final Charset charset) {
- this.form = form;
- this.charset = charset;
- }
-
/**
* 写出Multiparty数据,不关闭流
*
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/body/RequestBody.java b/hutool-http/src/main/java/cn/hutool/http/client/body/RequestBody.java
index 94646e1db..8aef7b60a 100644
--- a/hutool-http/src/main/java/cn/hutool/http/client/body/RequestBody.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/body/RequestBody.java
@@ -1,6 +1,6 @@
package cn.hutool.http.client.body;
-import cn.hutool.core.io.FastByteArrayOutputStream;
+import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.core.io.IoUtil;
import java.io.InputStream;
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/body/FormUrlEncodedBody.java b/hutool-http/src/main/java/cn/hutool/http/client/body/UrlEncodedFormBody.java
similarity index 51%
rename from hutool-http/src/main/java/cn/hutool/http/client/body/FormUrlEncodedBody.java
rename to hutool-http/src/main/java/cn/hutool/http/client/body/UrlEncodedFormBody.java
index 4160852c5..109769373 100644
--- a/hutool-http/src/main/java/cn/hutool/http/client/body/FormUrlEncodedBody.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/body/UrlEncodedFormBody.java
@@ -1,8 +1,10 @@
package cn.hutool.http.client.body;
+import cn.hutool.core.io.IoUtil;
import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.core.text.StrUtil;
+import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Map;
@@ -12,7 +14,7 @@ import java.util.Map;
* @author looly
* @since 5.7.17
*/
-public class FormUrlEncodedBody extends BytesBody {
+public class UrlEncodedFormBody extends FormBody {
/**
* 创建 Http request body
@@ -21,8 +23,8 @@ public class FormUrlEncodedBody extends BytesBody {
* @param charset 编码
* @return FormUrlEncodedBody
*/
- public static FormUrlEncodedBody of(final Map form, final Charset charset) {
- return new FormUrlEncodedBody(form, charset);
+ public static UrlEncodedFormBody of(final Map form, final Charset charset) {
+ return new UrlEncodedFormBody(form, charset);
}
/**
@@ -31,8 +33,13 @@ public class FormUrlEncodedBody extends BytesBody {
* @param form 表单
* @param charset 编码
*/
- public FormUrlEncodedBody(final Map form, final Charset charset) {
- super(StrUtil.bytes(UrlQuery.of(form, true).build(charset), charset));
+ public UrlEncodedFormBody(final Map form, final Charset charset) {
+ super(form, charset);
}
+ @Override
+ public void write(final OutputStream out) {
+ final byte[] bytes = StrUtil.bytes(UrlQuery.of(form, true).build(charset), charset);
+ IoUtil.write(out, false, bytes);
+ }
}
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpRequest.java
index 7602c5ed1..092ccfbf6 100755
--- a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpRequest.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpRequest.java
@@ -26,7 +26,7 @@ import cn.hutool.http.meta.HttpStatus;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.meta.Method;
import cn.hutool.http.client.body.BytesBody;
-import cn.hutool.http.client.body.FormUrlEncodedBody;
+import cn.hutool.http.client.body.UrlEncodedFormBody;
import cn.hutool.http.client.body.MultipartBody;
import cn.hutool.http.client.body.RequestBody;
import cn.hutool.http.client.cookie.GlobalCookieManager;
@@ -1311,7 +1311,7 @@ public class HttpRequest extends HttpBase {
if (ArrayUtil.isNotEmpty(this.bodyBytes)) {
body = BytesBody.of(this.bodyBytes);
} else {
- body = FormUrlEncodedBody.of(this.form, this.charset);
+ body = UrlEncodedFormBody.of(this.form, this.charset);
}
body.writeClose(this.httpConnection.getOutputStream());
}
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpResponse.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpResponse.java
index 5bec6c58d..9e362c843 100755
--- a/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpResponse.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/jdk/HttpResponse.java
@@ -1,7 +1,7 @@
package cn.hutool.http.client.engine.jdk;
import cn.hutool.core.convert.Convert;
-import cn.hutool.core.io.FastByteArrayOutputStream;
+import cn.hutool.core.io.stream.FastByteArrayOutputStream;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/okhttp/OkHttpResponse.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/okhttp/OkHttpResponse.java
index 657395901..228dcd7ab 100755
--- a/hutool-http/src/main/java/cn/hutool/http/client/engine/okhttp/OkHttpResponse.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/okhttp/OkHttpResponse.java
@@ -1,6 +1,6 @@
package cn.hutool.http.client.engine.okhttp;
-import cn.hutool.core.io.EmptyInputStream;
+import cn.hutool.core.io.stream.EmptyInputStream;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpUtil;
diff --git a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java
index 0a9d43fe0..a3ecf3c9f 100755
--- a/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java
+++ b/hutool-json/src/main/java/cn/hutool/json/JSONTokener.java
@@ -74,7 +74,7 @@ public class JSONTokener {
* @throws JSONException JSON异常,包装IO异常
*/
public JSONTokener(final InputStream inputStream, final JSONConfig config) throws JSONException {
- this(IoUtil.getUtf8Reader(inputStream), config);
+ this(IoUtil.toUtf8Reader(inputStream), config);
}
/**
diff --git a/hutool-setting/src/main/java/cn/hutool/setting/GroupedSet.java b/hutool-setting/src/main/java/cn/hutool/setting/GroupedSet.java
index ae9f68990..40d595e2a 100644
--- a/hutool-setting/src/main/java/cn/hutool/setting/GroupedSet.java
+++ b/hutool-setting/src/main/java/cn/hutool/setting/GroupedSet.java
@@ -194,7 +194,7 @@ public class GroupedSet extends HashMap> {
super.clear();
BufferedReader reader = null;
try {
- reader = IoUtil.getReader(settingStream, charset);
+ reader = IoUtil.toReader(settingStream, charset);
// 分组
String group;
LinkedHashSet valueSet = null;
diff --git a/hutool-setting/src/main/java/cn/hutool/setting/SettingLoader.java b/hutool-setting/src/main/java/cn/hutool/setting/SettingLoader.java
index 38530cafd..4735fe91f 100755
--- a/hutool-setting/src/main/java/cn/hutool/setting/SettingLoader.java
+++ b/hutool-setting/src/main/java/cn/hutool/setting/SettingLoader.java
@@ -103,7 +103,7 @@ public class SettingLoader {
this.groupedMap.clear();
BufferedReader reader = null;
try {
- reader = IoUtil.getReader(settingStream, this.charset);
+ reader = IoUtil.toReader(settingStream, this.charset);
// 分组
String group = null;
diff --git a/hutool-setting/src/main/java/cn/hutool/setting/yaml/YamlUtil.java b/hutool-setting/src/main/java/cn/hutool/setting/yaml/YamlUtil.java
index d8a74a12f..df49e38c8 100755
--- a/hutool-setting/src/main/java/cn/hutool/setting/yaml/YamlUtil.java
+++ b/hutool-setting/src/main/java/cn/hutool/setting/yaml/YamlUtil.java
@@ -50,7 +50,7 @@ public class YamlUtil {
* @return 加载的内容,默认Map
*/
public static T load(final InputStream in, final Class type) {
- return load(IoUtil.getBomReader(in), type);
+ return load(IoUtil.toBomReader(in), type);
}
/**