mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
fix code
This commit is contained in:
parent
c2262bc40e
commit
0d52562180
@ -1,7 +1,5 @@
|
|||||||
package cn.hutool.core.collection.iter;
|
package cn.hutool.core.collection.iter;
|
||||||
|
|
||||||
import cn.hutool.core.collection.iter.ComputeIter;
|
|
||||||
import cn.hutool.core.collection.iter.IterableIter;
|
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
@ -49,7 +47,7 @@ public class LineIter extends ComputeIter<String> implements IterableIter<String
|
|||||||
* @throws IllegalArgumentException reader为null抛出此异常
|
* @throws IllegalArgumentException reader为null抛出此异常
|
||||||
*/
|
*/
|
||||||
public LineIter(final InputStream in, final Charset charset) throws IllegalArgumentException {
|
public LineIter(final InputStream in, final Charset charset) throws IllegalArgumentException {
|
||||||
this(IoUtil.getReader(in, charset));
|
this(IoUtil.toReader(in, charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,7 +58,7 @@ public class LineIter extends ComputeIter<String> implements IterableIter<String
|
|||||||
*/
|
*/
|
||||||
public LineIter(final Reader reader) throws IllegalArgumentException {
|
public LineIter(final Reader reader) throws IllegalArgumentException {
|
||||||
Assert.notNull(reader, "Reader must not be null");
|
Assert.notNull(reader, "Reader must not be null");
|
||||||
this.bufferedReader = IoUtil.getReader(reader);
|
this.bufferedReader = IoUtil.toBuffered(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
@ -2,7 +2,7 @@ package cn.hutool.core.compress;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.iter.EnumerationIter;
|
import cn.hutool.core.collection.iter.EnumerationIter;
|
||||||
import cn.hutool.core.exceptions.UtilException;
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
import cn.hutool.core.io.FastByteArrayOutputStream;
|
import cn.hutool.core.io.stream.FastByteArrayOutputStream;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
@ -721,7 +721,7 @@ public class ZipUtil {
|
|||||||
* @return 压缩后的字节流
|
* @return 压缩后的字节流
|
||||||
* @throws UtilException IO异常
|
* @throws UtilException IO异常
|
||||||
*/
|
*/
|
||||||
public static byte[] gzip(final String content, final String charset) throws UtilException {
|
public static byte[] gzip(final String content, final Charset charset) throws UtilException {
|
||||||
return gzip(StrUtil.bytes(content, charset));
|
return gzip(StrUtil.bytes(content, charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -840,7 +840,7 @@ public class ZipUtil {
|
|||||||
* @return 压缩后的字节流
|
* @return 压缩后的字节流
|
||||||
* @since 4.1.4
|
* @since 4.1.4
|
||||||
*/
|
*/
|
||||||
public static byte[] zlib(final String content, final String charset, final int level) {
|
public static byte[] zlib(final String content, final Charset charset, final int level) {
|
||||||
return zlib(StrUtil.bytes(content, charset), level);
|
return zlib(StrUtil.bytes(content, charset), level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cn.hutool.core.exceptions;
|
package cn.hutool.core.exceptions;
|
||||||
|
|
||||||
import cn.hutool.core.io.FastByteArrayOutputStream;
|
import cn.hutool.core.io.stream.FastByteArrayOutputStream;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.reflect.ConstructorUtil;
|
import cn.hutool.core.reflect.ConstructorUtil;
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.hutool.core.io;
|
package cn.hutool.core.io;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.stream.BOMInputStream;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -46,9 +47,10 @@ public class BomReader extends Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("NullableProblems")
|
||||||
@Override
|
@Override
|
||||||
public int read(final char[] cbuf, final int off, final int len) throws IOException {
|
public int read(final char[] buffer, final int off, final int len) throws IOException {
|
||||||
return reader.read(cbuf, off, len);
|
return reader.read(buffer, off, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -155,7 +155,7 @@ public class FileTypeUtil {
|
|||||||
* @throws IORuntimeException 读取流引起的异常
|
* @throws IORuntimeException 读取流引起的异常
|
||||||
*/
|
*/
|
||||||
public static String getType(final InputStream in) throws IORuntimeException {
|
public static String getType(final InputStream in) throws IORuntimeException {
|
||||||
return getType(IoUtil.readHex28Upper(in));
|
return getType(readHex28Upper(in));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -262,4 +262,26 @@ public class FileTypeUtil {
|
|||||||
public static String getTypeByPath(final String path) throws IORuntimeException {
|
public static String getTypeByPath(final String path) throws IORuntimeException {
|
||||||
return getType(FileUtil.file(path));
|
return getType(FileUtil.file(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从流中读取前28个byte并转换为16进制,字母部分使用大写
|
||||||
|
*
|
||||||
|
* @param in {@link InputStream}
|
||||||
|
* @return 16进制字符串
|
||||||
|
* @throws IORuntimeException IO异常
|
||||||
|
*/
|
||||||
|
public static String readHex28Upper(final InputStream in) throws IORuntimeException {
|
||||||
|
return IoUtil.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 IoUtil.readHex(in, 28, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import cn.hutool.core.io.file.LineSeparator;
|
|||||||
import cn.hutool.core.io.file.PathUtil;
|
import cn.hutool.core.io.file.PathUtil;
|
||||||
import cn.hutool.core.io.file.Tailer;
|
import cn.hutool.core.io.file.Tailer;
|
||||||
import cn.hutool.core.io.resource.ResourceUtil;
|
import cn.hutool.core.io.resource.ResourceUtil;
|
||||||
|
import cn.hutool.core.io.stream.BOMInputStream;
|
||||||
import cn.hutool.core.io.unit.DataSizeUtil;
|
import cn.hutool.core.io.unit.DataSizeUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.lang.func.SerConsumer;
|
import cn.hutool.core.lang.func.SerConsumer;
|
||||||
@ -58,8 +59,6 @@ import java.util.Objects;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.CRC32;
|
|
||||||
import java.util.zip.Checksum;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件工具类
|
* 文件工具类
|
||||||
@ -1804,8 +1803,8 @@ public class FileUtil extends PathUtil {
|
|||||||
* @return BufferedReader对象
|
* @return BufferedReader对象
|
||||||
* @since 5.5.8
|
* @since 5.5.8
|
||||||
*/
|
*/
|
||||||
public static BufferedReader getBOMReader(final File file) {
|
public static BomReader getBOMReader(final File file) {
|
||||||
return IoUtil.getReader(getBOMInputStream(file));
|
return IoUtil.toBomReader(getBOMInputStream(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1839,7 +1838,7 @@ public class FileUtil extends PathUtil {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public static BufferedReader getReader(final File file, final Charset charset) throws IORuntimeException {
|
public static BufferedReader getReader(final File file, final Charset charset) throws IORuntimeException {
|
||||||
return IoUtil.getReader(getInputStream(file), charset);
|
return IoUtil.toReader(getInputStream(file), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3029,39 +3028,6 @@ public class FileUtil extends PathUtil {
|
|||||||
return FileNameUtil.containsInvalid(fileName);
|
return FileNameUtil.containsInvalid(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算文件CRC32校验码
|
|
||||||
*
|
|
||||||
* @param file 文件,不能为目录
|
|
||||||
* @return CRC32值
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
* @since 4.0.6
|
|
||||||
*/
|
|
||||||
public static long checksumCRC32(final File file) throws IORuntimeException {
|
|
||||||
return checksum(file, new CRC32()).getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算文件校验码
|
|
||||||
*
|
|
||||||
* @param file 文件,不能为目录
|
|
||||||
* @param checksum {@link Checksum}
|
|
||||||
* @return Checksum
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
* @since 4.0.6
|
|
||||||
*/
|
|
||||||
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 IoUtil.checksum(new FileInputStream(file), checksum);
|
|
||||||
} catch (final FileNotFoundException e) {
|
|
||||||
throw new IORuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Web项目下的web root路径<br>
|
* 获取Web项目下的web root路径<br>
|
||||||
* 原理是首先获取ClassPath路径,由于在web项目中ClassPath位于 WEB-INF/classes/下,故向上获取两级目录即可。
|
* 原理是首先获取ClassPath路径,由于在web项目中ClassPath位于 WEB-INF/classes/下,故向上获取两级目录即可。
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
package cn.hutool.core.io;
|
package cn.hutool.core.io;
|
||||||
|
|
||||||
|
import cn.hutool.core.codec.HexUtil;
|
||||||
import cn.hutool.core.collection.iter.LineIter;
|
import cn.hutool.core.collection.iter.LineIter;
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.exceptions.UtilException;
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
|
import cn.hutool.core.io.copy.FileChannelCopier;
|
||||||
import cn.hutool.core.io.copy.ReaderWriterCopier;
|
import cn.hutool.core.io.copy.ReaderWriterCopier;
|
||||||
import cn.hutool.core.io.copy.StreamCopier;
|
import cn.hutool.core.io.copy.StreamCopier;
|
||||||
|
import cn.hutool.core.io.stream.FastByteArrayOutputStream;
|
||||||
|
import cn.hutool.core.io.stream.StreamReader;
|
||||||
|
import cn.hutool.core.io.stream.StreamWriter;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.lang.func.SerConsumer;
|
import cn.hutool.core.lang.func.SerConsumer;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
|
||||||
import cn.hutool.core.codec.HexUtil;
|
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
@ -26,23 +29,17 @@ import java.io.Flushable;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PushbackInputStream;
|
import java.io.PushbackInputStream;
|
||||||
import java.io.PushbackReader;
|
import java.io.PushbackReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.Serializable;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.CharBuffer;
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.zip.CRC32;
|
|
||||||
import java.util.zip.CheckedInputStream;
|
|
||||||
import java.util.zip.Checksum;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IO工具类<br>
|
* IO工具类<br>
|
||||||
@ -52,7 +49,7 @@ import java.util.zip.Checksum;
|
|||||||
*/
|
*/
|
||||||
public class IoUtil extends NioUtil {
|
public class IoUtil extends NioUtil {
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------- Copy start
|
// region -------------------------------------------------------------------------------------- Copy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将Reader中的内容复制到Writer中 使用默认缓存大小,拷贝后不关闭Reader
|
* 将Reader中的内容复制到Writer中 使用默认缓存大小,拷贝后不关闭Reader
|
||||||
@ -96,15 +93,17 @@ public class IoUtil extends NioUtil {
|
|||||||
/**
|
/**
|
||||||
* 将Reader中的内容复制到Writer中,拷贝后不关闭Reader
|
* 将Reader中的内容复制到Writer中,拷贝后不关闭Reader
|
||||||
*
|
*
|
||||||
* @param reader Reader
|
* @param reader Reader,非空
|
||||||
* @param writer Writer
|
* @param writer Writer,非空
|
||||||
* @param bufferSize 缓存大小
|
* @param bufferSize 缓存大小,-1表示默认
|
||||||
* @param count 最大长度
|
* @param count 最大长度,-1表示无限制
|
||||||
* @param streamProgress 进度处理器
|
* @param streamProgress 进度处理器,{@code null}表示无
|
||||||
* @return 传输的byte数
|
* @return 传输的byte数
|
||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public static long copy(final Reader reader, final Writer writer, final int bufferSize, final long count, final StreamProgress streamProgress) throws IORuntimeException {
|
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);
|
return new ReaderWriterCopier(bufferSize, count, streamProgress).copy(reader, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,13 +152,15 @@ public class IoUtil extends NioUtil {
|
|||||||
* @param in 输入流
|
* @param in 输入流
|
||||||
* @param out 输出流
|
* @param out 输出流
|
||||||
* @param bufferSize 缓存大小
|
* @param bufferSize 缓存大小
|
||||||
* @param count 总拷贝长度
|
* @param count 总拷贝长度,-1表示无限制
|
||||||
* @param streamProgress 进度条
|
* @param streamProgress 进度条
|
||||||
* @return 传输的byte数
|
* @return 传输的byte数
|
||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
* @since 5.7.8
|
* @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 {
|
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);
|
return new StreamCopier(bufferSize, count, streamProgress).copy(in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,21 +176,12 @@ public class IoUtil extends NioUtil {
|
|||||||
Assert.notNull(in, "FileInputStream is null!");
|
Assert.notNull(in, "FileInputStream is null!");
|
||||||
Assert.notNull(out, "FileOutputStream is null!");
|
Assert.notNull(out, "FileOutputStream is null!");
|
||||||
|
|
||||||
FileChannel inChannel = null;
|
return FileChannelCopier.of().copy(in, out);
|
||||||
FileChannel outChannel = null;
|
|
||||||
try {
|
|
||||||
inChannel = in.getChannel();
|
|
||||||
outChannel = out.getChannel();
|
|
||||||
return copy(inChannel, outChannel);
|
|
||||||
} finally {
|
|
||||||
close(outChannel);
|
|
||||||
close(inChannel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------- Copy end
|
// endregion -------------------------------------------------------------------------------------- Copy
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------- getReader and getWriter start
|
// region -------------------------------------------------------------------------------------- toReader and toWriter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得一个文件读取器,默认使用 UTF-8 编码
|
* 获得一个文件读取器,默认使用 UTF-8 编码
|
||||||
@ -198,19 +190,8 @@ public class IoUtil extends NioUtil {
|
|||||||
* @return BufferedReader对象
|
* @return BufferedReader对象
|
||||||
* @since 5.1.6
|
* @since 5.1.6
|
||||||
*/
|
*/
|
||||||
public static BufferedReader getUtf8Reader(final InputStream in) {
|
public static BufferedReader toUtf8Reader(final InputStream in) {
|
||||||
return getReader(in, CharsetUtil.UTF_8);
|
return toReader(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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,7 +201,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @return {@link BomReader}
|
* @return {@link BomReader}
|
||||||
* @since 5.7.14
|
* @since 5.7.14
|
||||||
*/
|
*/
|
||||||
public static BomReader getBomReader(final InputStream in) {
|
public static BomReader toBomReader(final InputStream in) {
|
||||||
return new BomReader(in);
|
return new BomReader(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +212,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @param charset 字符集
|
* @param charset 字符集
|
||||||
* @return BufferedReader对象
|
* @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) {
|
if (null == in) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -246,35 +227,6 @@ public class IoUtil extends NioUtil {
|
|||||||
return new BufferedReader(reader);
|
return new BufferedReader(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得{@link BufferedReader}<br>
|
|
||||||
* 如果是{@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}<br>
|
|
||||||
* 如果是{@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
|
* 获得一个Writer,默认编码UTF-8
|
||||||
*
|
*
|
||||||
@ -282,8 +234,8 @@ public class IoUtil extends NioUtil {
|
|||||||
* @return OutputStreamWriter对象
|
* @return OutputStreamWriter对象
|
||||||
* @since 5.1.6
|
* @since 5.1.6
|
||||||
*/
|
*/
|
||||||
public static OutputStreamWriter getUtf8Writer(final OutputStream out) {
|
public static OutputStreamWriter toUtf8Writer(final OutputStream out) {
|
||||||
return getWriter(out, CharsetUtil.UTF_8);
|
return toWriter(out, CharsetUtil.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -293,7 +245,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @param charset 字符集
|
* @param charset 字符集
|
||||||
* @return OutputStreamWriter对象
|
* @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) {
|
if (null == out) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -304,9 +256,9 @@ public class IoUtil extends NioUtil {
|
|||||||
return new OutputStreamWriter(out, charset);
|
return new OutputStreamWriter(out, charset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// -------------------------------------------------------------------------------------- getReader and getWriter end
|
// endregion -------------------------------------------------------------------------------------- toReader and toWriter
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------- read start
|
// region -------------------------------------------------------------------------------------- read
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从流中读取UTF8编码的内容
|
* 从流中读取UTF8编码的内容
|
||||||
@ -353,25 +305,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @since 5.5.3
|
* @since 5.5.3
|
||||||
*/
|
*/
|
||||||
public static FastByteArrayOutputStream read(final InputStream in, final boolean isClose) throws IORuntimeException {
|
public static FastByteArrayOutputStream read(final InputStream in, final boolean isClose) throws IORuntimeException {
|
||||||
final FastByteArrayOutputStream out;
|
return StreamReader.of(in, isClose).read();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -431,28 +365,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @since 5.0.4
|
* @since 5.0.4
|
||||||
*/
|
*/
|
||||||
public static byte[] readBytes(final InputStream in, final boolean isClose) throws IORuntimeException {
|
public static byte[] readBytes(final InputStream in, final boolean isClose) throws IORuntimeException {
|
||||||
if (in instanceof FileInputStream) {
|
return StreamReader.of(in, isClose).readBytes();
|
||||||
// 文件流的长度是可预见的,此时直接读取效率更高
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -464,16 +377,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public static byte[] readBytes(final InputStream in, final int length) throws IORuntimeException {
|
public static byte[] readBytes(final InputStream in, final int length) throws IORuntimeException {
|
||||||
if (null == in) {
|
return StreamReader.of(in, false).readBytes(length);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -489,45 +393,6 @@ public class IoUtil extends NioUtil {
|
|||||||
return HexUtil.encodeHexStr(readBytes(in, length), toLowerCase);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从流中读取对象,即对象的反序列化
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 注意!!! 此方法不会检查反序列化安全,可能存在反序列化漏洞风险!!!
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param <T> 读取对象的类型
|
|
||||||
* @param in 输入流
|
|
||||||
* @return 输出流
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
* @throws UtilException ClassNotFoundException包装
|
|
||||||
*/
|
|
||||||
public static <T> T readObj(final InputStream in) throws IORuntimeException, UtilException {
|
|
||||||
return readObj(in, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从流中读取对象,即对象的反序列化,读取后不关闭流
|
* 从流中读取对象,即对象的反序列化,读取后不关闭流
|
||||||
*
|
*
|
||||||
@ -537,52 +402,13 @@ public class IoUtil extends NioUtil {
|
|||||||
*
|
*
|
||||||
* @param <T> 读取对象的类型
|
* @param <T> 读取对象的类型
|
||||||
* @param in 输入流
|
* @param in 输入流
|
||||||
* @param clazz 读取对象类型
|
* @param acceptClasses 读取对象类型
|
||||||
* @return 输出流
|
* @return 输出流
|
||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
* @throws UtilException ClassNotFoundException包装
|
* @throws UtilException ClassNotFoundException包装
|
||||||
*/
|
*/
|
||||||
public static <T> T readObj(final InputStream in, final Class<T> clazz) throws IORuntimeException, UtilException {
|
public static <T> T readObj(final InputStream in, final Class<?>... acceptClasses) throws IORuntimeException, UtilException {
|
||||||
try {
|
return StreamReader.of(in, false).readObj(acceptClasses);
|
||||||
return readObj((in instanceof ValidateObjectInputStream) ?
|
|
||||||
(ValidateObjectInputStream) in : new ValidateObjectInputStream(in),
|
|
||||||
clazz);
|
|
||||||
} catch (final IOException e) {
|
|
||||||
throw new IORuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从流中读取对象,即对象的反序列化,读取后不关闭流
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 此方法使用了{@link ValidateObjectInputStream}中的黑白名单方式过滤类,用于避免反序列化漏洞<br>
|
|
||||||
* 通过构造{@link ValidateObjectInputStream},调用{@link ValidateObjectInputStream#accept(Class[])}
|
|
||||||
* 或者{@link ValidateObjectInputStream#refuse(Class[])}方法添加可以被序列化的类或者禁止序列化的类。
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param <T> 读取对象的类型
|
|
||||||
* @param in 输入流,使用{@link ValidateObjectInputStream}中的黑白名单方式过滤类,用于避免反序列化漏洞
|
|
||||||
* @param clazz 读取对象类型
|
|
||||||
* @return 输出流
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
* @throws UtilException ClassNotFoundException包装
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> T readObj(final ValidateObjectInputStream in, final Class<T> clazz) throws IORuntimeException, UtilException {
|
|
||||||
if (in == null) {
|
|
||||||
throw new IllegalArgumentException("The InputStream must not be null");
|
|
||||||
}
|
|
||||||
if(null != clazz){
|
|
||||||
in.accept(clazz);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return (T) in.readObject();
|
|
||||||
} catch (final IOException e) {
|
|
||||||
throw new IORuntimeException(e);
|
|
||||||
} catch (final ClassNotFoundException e) {
|
|
||||||
throw new UtilException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -609,7 +435,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public static <T extends Collection<String>> T readLines(final InputStream in, final Charset charset, final T collection) throws IORuntimeException {
|
public static <T extends Collection<String>> T readLines(final InputStream in, final Charset charset, final T collection) throws IORuntimeException {
|
||||||
return readLines(getReader(in, charset), collection);
|
return readLines(toReader(in, charset), collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -648,7 +474,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @since 3.0.9
|
* @since 3.0.9
|
||||||
*/
|
*/
|
||||||
public static void readLines(final InputStream in, final Charset charset, final SerConsumer<String> lineHandler) throws IORuntimeException {
|
public static void readLines(final InputStream in, final Charset charset, final SerConsumer<String> lineHandler) throws IORuntimeException {
|
||||||
readLines(getReader(in, charset), lineHandler);
|
readLines(toReader(in, charset), lineHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -669,7 +495,20 @@ public class IoUtil extends NioUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------- read end
|
// endregion -------------------------------------------------------------------------------------- read
|
||||||
|
|
||||||
|
// region -------------------------------------------------------------------------------------- toStream
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String 转为UTF-8编码的字节流流
|
||||||
|
*
|
||||||
|
* @param content 内容
|
||||||
|
* @return 字节流
|
||||||
|
* @since 4.5.1
|
||||||
|
*/
|
||||||
|
public static ByteArrayInputStream toUtf8Stream(final String content) {
|
||||||
|
return toStream(content, CharsetUtil.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* String 转为流
|
* String 转为流
|
||||||
@ -685,17 +524,6 @@ public class IoUtil extends NioUtil {
|
|||||||
return toStream(StrUtil.bytes(content, charset));
|
return toStream(StrUtil.bytes(content, charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* String 转为UTF-8编码的字节流流
|
|
||||||
*
|
|
||||||
* @param content 内容
|
|
||||||
* @return 字节流
|
|
||||||
* @since 4.5.1
|
|
||||||
*/
|
|
||||||
public static ByteArrayInputStream toUtf8Stream(final String content) {
|
|
||||||
return toStream(content, CharsetUtil.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件转为{@link FileInputStream}
|
* 文件转为{@link FileInputStream}
|
||||||
*
|
*
|
||||||
@ -869,6 +697,19 @@ public class IoUtil extends NioUtil {
|
|||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得{@link PushbackReader}<br>
|
||||||
|
* 如果是{@link PushbackReader}强转返回,否则新建
|
||||||
|
*
|
||||||
|
* @param reader 普通Reader
|
||||||
|
* @param pushBackSize 推后的byte数
|
||||||
|
* @return {@link PushbackReader}
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
public static PushbackReader toPushBackReader(final Reader reader, final int pushBackSize) {
|
||||||
|
return (reader instanceof PushbackReader) ? (PushbackReader) reader : new PushbackReader(reader, pushBackSize);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转换为{@link PushbackInputStream}<br>
|
* 转换为{@link PushbackInputStream}<br>
|
||||||
* 如果传入的输入流已经是{@link PushbackInputStream},强转返回,否则新建一个
|
* 如果传入的输入流已经是{@link PushbackInputStream},强转返回,否则新建一个
|
||||||
@ -918,6 +759,31 @@ public class IoUtil extends NioUtil {
|
|||||||
|
|
||||||
return pushbackInputStream;
|
return pushbackInputStream;
|
||||||
}
|
}
|
||||||
|
// endregion -------------------------------------------------------------------------------------- toStream
|
||||||
|
|
||||||
|
// region ----------------------------------------------------------------------------------------------- write
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将byte[]写到流中,并关闭目标流
|
||||||
|
*
|
||||||
|
* @param out 输出流
|
||||||
|
* @param content 写入的内容
|
||||||
|
* @throws IORuntimeException IO异常
|
||||||
|
*/
|
||||||
|
public static void writeClose(final OutputStream out, final byte[] content) throws IORuntimeException {
|
||||||
|
write(out, true, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将byte[]写到流中,并关闭目标流
|
||||||
|
*
|
||||||
|
* @param out 输出流
|
||||||
|
* @param content 写入的内容
|
||||||
|
* @throws IORuntimeException IO异常
|
||||||
|
*/
|
||||||
|
public static void write(final OutputStream out, final byte[] content) throws IORuntimeException {
|
||||||
|
write(out, false, content);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将byte[]写到流中
|
* 将byte[]写到流中
|
||||||
@ -928,15 +794,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public static void write(final OutputStream out, final boolean isCloseOut, final byte[] content) throws IORuntimeException {
|
public static void write(final OutputStream out, final boolean isCloseOut, final byte[] content) throws IORuntimeException {
|
||||||
try {
|
StreamWriter.of(out, isCloseOut).write(content);
|
||||||
out.write(content);
|
|
||||||
} catch (final IOException e) {
|
|
||||||
throw new IORuntimeException(e);
|
|
||||||
} finally {
|
|
||||||
if (isCloseOut) {
|
|
||||||
close(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -963,35 +821,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @since 3.0.9
|
* @since 3.0.9
|
||||||
*/
|
*/
|
||||||
public static void write(final OutputStream out, final Charset charset, final boolean isCloseOut, final Object... contents) throws IORuntimeException {
|
public static void write(final OutputStream out, final Charset charset, final boolean isCloseOut, final Object... contents) throws IORuntimeException {
|
||||||
OutputStreamWriter osw = null;
|
StreamWriter.of(out, isCloseOut).writeStr(charset, contents);
|
||||||
try {
|
|
||||||
osw = getWriter(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 (isCloseOut) {
|
|
||||||
close(osw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将多部分内容写到流中
|
|
||||||
*
|
|
||||||
* @param out 输出流
|
|
||||||
* @param isCloseOut 写入完毕是否关闭输出流
|
|
||||||
* @param obj 写入的对象内容
|
|
||||||
* @throws IORuntimeException IO异常
|
|
||||||
* @since 5.3.3
|
|
||||||
*/
|
|
||||||
public static void writeObj(final OutputStream out, final boolean isCloseOut, final Serializable obj) throws IORuntimeException {
|
|
||||||
writeObjects(out, isCloseOut, obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1002,24 +832,10 @@ public class IoUtil extends NioUtil {
|
|||||||
* @param contents 写入的内容
|
* @param contents 写入的内容
|
||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public static void writeObjects(final OutputStream out, final boolean isCloseOut, final Serializable... contents) throws IORuntimeException {
|
public static void writeObjects(final OutputStream out, final boolean isCloseOut, final Object... contents) throws IORuntimeException {
|
||||||
ObjectOutputStream osw = null;
|
StreamWriter.of(out, isCloseOut).writeObj(contents);
|
||||||
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 (isCloseOut) {
|
|
||||||
close(osw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// endregion ----------------------------------------------------------------------------------------------- write
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从缓存中刷出数据
|
* 从缓存中刷出数据
|
||||||
@ -1060,7 +876,7 @@ public class IoUtil extends NioUtil {
|
|||||||
* @param obj 可关闭对象
|
* @param obj 可关闭对象
|
||||||
* @since 4.3.2
|
* @since 4.3.2
|
||||||
*/
|
*/
|
||||||
public static void closeIfPosible(final Object obj) {
|
public static void closeIfPossible(final Object obj) {
|
||||||
if (obj instanceof AutoCloseable) {
|
if (obj instanceof AutoCloseable) {
|
||||||
close((AutoCloseable) obj);
|
close((AutoCloseable) obj);
|
||||||
}
|
}
|
||||||
@ -1112,8 +928,8 @@ public class IoUtil extends NioUtil {
|
|||||||
* @since 4.0.6
|
* @since 4.0.6
|
||||||
*/
|
*/
|
||||||
public static boolean contentEquals(Reader input1, Reader input2) throws IORuntimeException {
|
public static boolean contentEquals(Reader input1, Reader input2) throws IORuntimeException {
|
||||||
input1 = getReader(input1);
|
input1 = toBuffered(input1);
|
||||||
input2 = getReader(input2);
|
input2 = toBuffered(input2);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int ch = input1.read();
|
int ch = input1.read();
|
||||||
@ -1143,8 +959,8 @@ public class IoUtil extends NioUtil {
|
|||||||
* @since 4.0.6
|
* @since 4.0.6
|
||||||
*/
|
*/
|
||||||
public static boolean contentEqualsIgnoreEOL(final Reader input1, final Reader input2) throws IORuntimeException {
|
public static boolean contentEqualsIgnoreEOL(final Reader input1, final Reader input2) throws IORuntimeException {
|
||||||
final BufferedReader br1 = getReader(input1);
|
final BufferedReader br1 = toBuffered(input1);
|
||||||
final BufferedReader br2 = getReader(input2);
|
final BufferedReader br2 = toBuffered(input2);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String line1 = br1.readLine();
|
String line1 = br1.readLine();
|
||||||
@ -1159,54 +975,6 @@ public class IoUtil extends NioUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算流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 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, new NullOutputStream());
|
|
||||||
} 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回行遍历器
|
* 返回行遍历器
|
||||||
* <pre>
|
* <pre>
|
||||||
@ -1256,6 +1024,7 @@ public class IoUtil extends NioUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ByteArrayOutputStream} 转换为String
|
* {@link ByteArrayOutputStream} 转换为String
|
||||||
|
*
|
||||||
* @param out {@link ByteArrayOutputStream}
|
* @param out {@link ByteArrayOutputStream}
|
||||||
* @param charset 编码
|
* @param charset 编码
|
||||||
* @return 字符串
|
* @return 字符串
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package cn.hutool.core.io;
|
package cn.hutool.core.io;
|
||||||
|
|
||||||
import cn.hutool.core.io.copy.ChannelCopier;
|
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.lang.Assert;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
@ -60,74 +62,35 @@ public class NioUtil {
|
|||||||
* 拷贝流<br>
|
* 拷贝流<br>
|
||||||
* 本方法不会关闭流
|
* 本方法不会关闭流
|
||||||
*
|
*
|
||||||
* @param in 输入流
|
* @param in 输入流, 非空
|
||||||
* @param out 输出流
|
* @param out 输出流, 非空
|
||||||
* @param bufferSize 缓存大小
|
* @param bufferSize 缓存大小,-1表示默认
|
||||||
* @param count 最大长度
|
* @param count 最大长度,-1表示无限制
|
||||||
* @param streamProgress 进度条
|
* @param streamProgress 进度条,{@code null}表示无进度条
|
||||||
* @return 传输的byte数
|
* @return 传输的byte数
|
||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
* @since 5.7.8
|
* @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 {
|
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);
|
return copy(Channels.newChannel(in), Channels.newChannel(out), bufferSize, count, streamProgress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拷贝文件Channel,使用NIO,拷贝后不会关闭channel
|
* 拷贝文件Channel,使用NIO,拷贝后不会关闭channel
|
||||||
*
|
*
|
||||||
* @param inChannel {@link FileChannel}
|
* @param in {@link FileChannel},非空
|
||||||
* @param outChannel {@link FileChannel}
|
* @param out {@link FileChannel},非空
|
||||||
* @return 拷贝的字节数
|
* @return 拷贝的字节数
|
||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
* @since 5.5.3
|
* @since 5.5.3
|
||||||
*/
|
*/
|
||||||
public static long copy(final FileChannel inChannel, final FileChannel outChannel) throws IORuntimeException {
|
public static long copy(final FileChannel in, final FileChannel out) throws IORuntimeException {
|
||||||
Assert.notNull(inChannel, "In channel is null!");
|
Assert.notNull(in, "In channel is null!");
|
||||||
Assert.notNull(outChannel, "Out channel is null!");
|
Assert.notNull(out, "Out channel is null!");
|
||||||
|
|
||||||
try {
|
return FileChannelCopier.of().copy(in, out);
|
||||||
return copySafely(inChannel, outChannel);
|
|
||||||
} catch (final IOException e) {
|
|
||||||
throw new IORuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件拷贝实现
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* 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());
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -184,6 +147,8 @@ public class NioUtil {
|
|||||||
* @since 5.7.8
|
* @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 {
|
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);
|
return new ChannelCopier(bufferSize, count, streamProgress).copy(in, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package cn.hutool.core.io;
|
package cn.hutool.core.io;
|
||||||
|
|
||||||
import cn.hutool.core.exceptions.UtilException;
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
import cn.hutool.core.io.FastByteArrayOutputStream;
|
import cn.hutool.core.io.stream.FastByteArrayOutputStream;
|
||||||
import cn.hutool.core.io.IoUtil;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
101
hutool-core/src/main/java/cn/hutool/core/io/checksum/ChecksumUtil.java
Executable file
101
hutool-core/src/main/java/cn/hutool/core/io/checksum/ChecksumUtil.java
Executable file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ package cn.hutool.core.io.copy;
|
|||||||
import cn.hutool.core.io.IORuntimeException;
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.io.StreamProgress;
|
import cn.hutool.core.io.StreamProgress;
|
||||||
import cn.hutool.core.lang.Assert;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -59,9 +58,6 @@ public class ChannelCopier extends IoCopier<ReadableByteChannel, WritableByteCha
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long copy(final ReadableByteChannel source, final WritableByteChannel target) {
|
public long copy(final ReadableByteChannel source, final WritableByteChannel target) {
|
||||||
Assert.notNull(source, "InputStream is null !");
|
|
||||||
Assert.notNull(target, "OutputStream is null !");
|
|
||||||
|
|
||||||
final StreamProgress progress = this.progress;
|
final StreamProgress progress = this.progress;
|
||||||
if (null != progress) {
|
if (null != progress) {
|
||||||
progress.start();
|
progress.start();
|
||||||
|
129
hutool-core/src/main/java/cn/hutool/core/io/copy/FileChannelCopier.java
Executable file
129
hutool-core/src/main/java/cn/hutool/core/io/copy/FileChannelCopier.java
Executable file
@ -0,0 +1,129 @@
|
|||||||
|
package cn.hutool.core.io.copy;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link FileChannel} 数据拷贝封装<br>
|
||||||
|
*
|
||||||
|
* <pre>{@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());
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @author z8g
|
||||||
|
*/
|
||||||
|
public class FileChannelCopier extends IoCopier<FileChannel, FileChannel> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建{@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件拷贝实现
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 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());
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,7 @@ public class StreamCopier extends IoCopier<InputStream, OutputStream> {
|
|||||||
* 构造
|
* 构造
|
||||||
*
|
*
|
||||||
* @param bufferSize 缓存大小
|
* @param bufferSize 缓存大小
|
||||||
* @param count 拷贝总数
|
* @param count 拷贝总数,-1表示无限制
|
||||||
*/
|
*/
|
||||||
public StreamCopier(final int bufferSize, final long count) {
|
public StreamCopier(final int bufferSize, final long count) {
|
||||||
this(bufferSize, count, null);
|
this(bufferSize, count, null);
|
||||||
@ -47,7 +47,7 @@ public class StreamCopier extends IoCopier<InputStream, OutputStream> {
|
|||||||
* 构造
|
* 构造
|
||||||
*
|
*
|
||||||
* @param bufferSize 缓存大小
|
* @param bufferSize 缓存大小
|
||||||
* @param count 拷贝总数
|
* @param count 拷贝总数,-1表示无限制
|
||||||
* @param progress 进度条
|
* @param progress 进度条
|
||||||
*/
|
*/
|
||||||
public StreamCopier(final int bufferSize, final long count, final StreamProgress progress) {
|
public StreamCopier(final int bufferSize, final long count, final StreamProgress progress) {
|
||||||
|
@ -228,7 +228,7 @@ public class FileReader extends FileWrapper {
|
|||||||
* @throws IORuntimeException IO异常
|
* @throws IORuntimeException IO异常
|
||||||
*/
|
*/
|
||||||
public BufferedReader getReader() throws IORuntimeException {
|
public BufferedReader getReader() throws IORuntimeException {
|
||||||
return IoUtil.getReader(getInputStream(), this.charset);
|
return IoUtil.toReader(getInputStream(), this.charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -416,7 +416,7 @@ public class PathUtil {
|
|||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
public static BufferedReader getReader(final Path path, final Charset charset) throws IORuntimeException {
|
public static BufferedReader getReader(final Path path, final Charset charset) throws IORuntimeException {
|
||||||
return IoUtil.getReader(getInputStream(path), charset);
|
return IoUtil.toReader(getInputStream(path), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,7 +75,7 @@ public class CharSequenceResource implements Resource, Serializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BufferedReader getReader(final Charset charset) {
|
public BufferedReader getReader(final Charset charset) {
|
||||||
return IoUtil.getReader(new StringReader(this.data.toString()));
|
return IoUtil.toBuffered(new StringReader(this.data.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,7 +65,7 @@ public class FileObjectResource implements Resource {
|
|||||||
@Override
|
@Override
|
||||||
public BufferedReader getReader(final Charset charset) {
|
public BufferedReader getReader(final Charset charset) {
|
||||||
try {
|
try {
|
||||||
return IoUtil.getReader(this.fileObject.openReader(false));
|
return IoUtil.toBuffered(this.fileObject.openReader(false));
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new IORuntimeException(e);
|
throw new IORuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.hutool.core.io.resource;
|
package cn.hutool.core.io.resource;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8,7 +9,6 @@ import java.util.Collection;
|
|||||||
* 此资源为一个利用游标自循环资源,只有调用{@link #next()} 方法才会获取下一个资源,使用完毕后调用{@link #reset()}方法重置游标
|
* 此资源为一个利用游标自循环资源,只有调用{@link #next()} 方法才会获取下一个资源,使用完毕后调用{@link #reset()}方法重置游标
|
||||||
*
|
*
|
||||||
* @author looly
|
* @author looly
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class MultiFileResource extends MultiResource {
|
public class MultiFileResource extends MultiResource {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ -31,6 +31,15 @@ public class MultiFileResource extends MultiResource{
|
|||||||
add(files);
|
add(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param files 文件资源列表
|
||||||
|
*/
|
||||||
|
public MultiFileResource(final Path... files) {
|
||||||
|
add(files);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加文件资源
|
* 增加文件资源
|
||||||
*
|
*
|
||||||
@ -44,6 +53,19 @@ public class MultiFileResource extends MultiResource{
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加文件资源
|
||||||
|
*
|
||||||
|
* @param files 文件资源
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public MultiFileResource add(final Path... files) {
|
||||||
|
for (final Path file : files) {
|
||||||
|
this.add(new FileResource(file));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加文件资源
|
* 增加文件资源
|
||||||
*
|
*
|
||||||
|
@ -86,7 +86,7 @@ public interface Resource {
|
|||||||
* @return {@link BufferedReader}
|
* @return {@link BufferedReader}
|
||||||
*/
|
*/
|
||||||
default BufferedReader getReader(final Charset charset) {
|
default BufferedReader getReader(final Charset charset) {
|
||||||
return IoUtil.getReader(getStream(), charset);
|
return IoUtil.toReader(getStream(), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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 cn.hutool.core.util.CharsetUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
@ -1,4 +1,4 @@
|
|||||||
package cn.hutool.core.io;
|
package cn.hutool.core.io.stream;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package cn.hutool.core.io;
|
package cn.hutool.core.io.stream;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -10,12 +10,15 @@ import java.io.OutputStream;
|
|||||||
* @author looly
|
* @author looly
|
||||||
* @since 4.0.6
|
* @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}.
|
* 什么也不做,写出到{@code /dev/null}.
|
||||||
@ -24,6 +27,7 @@ public class NullOutputStream extends OutputStream {
|
|||||||
* @param off 开始位置
|
* @param off 开始位置
|
||||||
* @param len 长度
|
* @param len 长度
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("NullableProblems")
|
||||||
@Override
|
@Override
|
||||||
public void write(final byte[] b, final int off, final int len) {
|
public void write(final byte[] b, final int off, final int len) {
|
||||||
// to /dev/null
|
// to /dev/null
|
||||||
@ -45,6 +49,7 @@ public class NullOutputStream extends OutputStream {
|
|||||||
* @param b 写出的数据
|
* @param b 写出的数据
|
||||||
* @throws IOException 不抛出
|
* @throws IOException 不抛出
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("NullableProblems")
|
||||||
@Override
|
@Override
|
||||||
public void write(final byte[] b) throws IOException {
|
public void write(final byte[] b) throws IOException {
|
||||||
// to /dev/null
|
// to /dev/null
|
@ -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.CharsetUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
|
47
hutool-core/src/main/java/cn/hutool/core/io/stream/StrInputStream.java
Executable file
47
hutool-core/src/main/java/cn/hutool/core/io/stream/StrInputStream.java
Executable file
@ -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));
|
||||||
|
}
|
||||||
|
}
|
160
hutool-core/src/main/java/cn/hutool/core/io/stream/StreamReader.java
Executable file
160
hutool-core/src/main/java/cn/hutool/core/io/stream/StreamReader.java
Executable file
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从流中读取对象,即对象的反序列化
|
||||||
|
*
|
||||||
|
* <p>注意!!! 此方法不会检查反序列化安全,可能存在反序列化漏洞风险!!!</p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 此方法使用了{@link ValidateObjectInputStream}中的黑白名单方式过滤类,用于避免反序列化漏洞<br>
|
||||||
|
* 通过构造{@link ValidateObjectInputStream},调用{@link ValidateObjectInputStream#accept(Class[])}
|
||||||
|
* 或者{@link ValidateObjectInputStream#refuse(Class[])}方法添加可以被序列化的类或者禁止序列化的类。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param <T> 读取对象的类型
|
||||||
|
* @param acceptClasses 读取对象类型
|
||||||
|
* @return 输出流
|
||||||
|
* @throws IORuntimeException IO异常
|
||||||
|
* @throws UtilException ClassNotFoundException包装
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
115
hutool-core/src/main/java/cn/hutool/core/io/stream/StreamWriter.java
Executable file
115
hutool-core/src/main/java/cn/hutool/core/io/stream/StreamWriter.java
Executable file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package cn.hutool.core.io;
|
package cn.hutool.core.io.stream;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
|
6
hutool-core/src/main/java/cn/hutool/core/io/stream/package-info.java
Executable file
6
hutool-core/src/main/java/cn/hutool/core/io/stream/package-info.java
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* InputStream和OutputStream相关方法和类封装
|
||||||
|
*
|
||||||
|
* @author looly
|
||||||
|
*/
|
||||||
|
package cn.hutool.core.io.stream;
|
@ -1,6 +1,6 @@
|
|||||||
package cn.hutool.core.net.multipart;
|
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.BufferedInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
@ -465,7 +465,7 @@ public class URLUtil {
|
|||||||
* @since 3.2.1
|
* @since 3.2.1
|
||||||
*/
|
*/
|
||||||
public static BufferedReader getReader(final URL url, final Charset charset) {
|
public static BufferedReader getReader(final URL url, final Charset charset) {
|
||||||
return IoUtil.getReader(getStream(url), charset);
|
return IoUtil.toReader(getStream(url), charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2506,7 +2506,7 @@ public class CharSequenceUtil extends StrChecker {
|
|||||||
* @param charset 编码
|
* @param charset 编码
|
||||||
* @return byteBuffer
|
* @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));
|
return ByteBuffer.wrap(bytes(str, charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cn.hutool.core.io;
|
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 cn.hutool.core.lang.Console;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
@ -12,21 +12,32 @@ import java.io.IOException;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件类型判断单元测试
|
* 文件类型判断单元测试
|
||||||
* @author Looly
|
|
||||||
*
|
*
|
||||||
|
* @author Looly
|
||||||
*/
|
*/
|
||||||
public class FileTypeUtilTest {
|
public class FileTypeUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
public void getTypeTest() {
|
||||||
public void fileTypeUtilTest() {
|
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 File file = FileUtil.file("hutool.jpg");
|
||||||
final String type = FileTypeUtil.getType(file);
|
final String type = FileTypeUtil.getType(file);
|
||||||
Assert.assertEquals("jpg", type);
|
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);
|
final String newType = FileTypeUtil.getType(file);
|
||||||
Assert.assertEquals("new_jpg", newType);
|
Assert.assertEquals("new_jpg", newType);
|
||||||
|
|
||||||
|
FileTypeUtil.removeFileType("ffd8ffe000104a464946");
|
||||||
|
final String type2 = FileTypeUtil.getType(file);
|
||||||
|
Assert.assertEquals("jpg", type2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -49,7 +60,7 @@ public class FileTypeUtilTest {
|
|||||||
@Ignore
|
@Ignore
|
||||||
public void ofdTest() {
|
public void ofdTest() {
|
||||||
final File file = FileUtil.file("e:/test.ofd");
|
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);
|
Console.log(hex);
|
||||||
final String type = FileTypeUtil.getType(file);
|
final String type = FileTypeUtil.getType(file);
|
||||||
Console.log(type);
|
Console.log(type);
|
||||||
@ -72,6 +83,7 @@ public class FileTypeUtilTest {
|
|||||||
final BufferedInputStream inputStream = FileUtil.getInputStream(file);
|
final BufferedInputStream inputStream = FileUtil.getInputStream(file);
|
||||||
inputStream.mark(0);
|
inputStream.mark(0);
|
||||||
final String type = FileTypeUtil.getType(inputStream);
|
final String type = FileTypeUtil.getType(inputStream);
|
||||||
|
Assert.assertEquals("jpg", type);
|
||||||
|
|
||||||
inputStream.reset();
|
inputStream.reset();
|
||||||
}
|
}
|
||||||
@ -87,8 +99,14 @@ public class FileTypeUtilTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getHexTest() {
|
public void readHex28LowerTest() {
|
||||||
final String id3 = HexUtil.encodeHexStr("8BPS");
|
final String s = FileTypeUtil.readHex28Lower(ResourceUtil.getStream("hutool.jpg"));
|
||||||
Console.log(id3);
|
Assert.assertEquals("ffd8ffe000104a46494600010101006000600000ffe1095845786966", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readHex28UpperTest() {
|
||||||
|
final String s = FileTypeUtil.readHex28Upper(ResourceUtil.getStream("hutool.jpg"));
|
||||||
|
Assert.assertEquals("FFD8FFE000104A46494600010101006000600000FFE1095845786966", s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,27 @@
|
|||||||
package cn.hutool.core.io;
|
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.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.lang.func.SerConsumer;
|
||||||
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
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 {
|
public class IoUtilTest {
|
||||||
|
|
||||||
@ -33,4 +47,111 @@ public class IoUtilTest {
|
|||||||
throw new IORuntimeException(e);
|
throw new IORuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void readUtf8LinesTest() {
|
||||||
|
final ArrayList<String> 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<String>) 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
24
hutool-core/src/test/java/cn/hutool/core/io/NioUtilTest.java
Executable file
24
hutool-core/src/test/java/cn/hutool/core/io/NioUtilTest.java
Executable file
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package cn.hutool.crypto;
|
package cn.hutool.crypto;
|
||||||
|
|
||||||
import cn.hutool.core.io.FastByteArrayOutputStream;
|
import cn.hutool.core.io.stream.FastByteArrayOutputStream;
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
import org.bouncycastle.asn1.ASN1Encodable;
|
import org.bouncycastle.asn1.ASN1Encodable;
|
||||||
import org.bouncycastle.asn1.ASN1Encoding;
|
import org.bouncycastle.asn1.ASN1Encoding;
|
||||||
|
@ -122,7 +122,7 @@ public class PemUtil {
|
|||||||
* @since 4.5.2
|
* @since 4.5.2
|
||||||
*/
|
*/
|
||||||
public static PemObject readPemObject(final InputStream keyStream) {
|
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
|
* @since 5.1.6
|
||||||
*/
|
*/
|
||||||
public static void writePemObject(final PemObjectGenerator pemObject, final OutputStream keyStream) {
|
public static void writePemObject(final PemObjectGenerator pemObject, final OutputStream keyStream) {
|
||||||
writePemObject(pemObject, IoUtil.getUtf8Writer(keyStream));
|
writePemObject(pemObject, IoUtil.toUtf8Writer(keyStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cn.hutool.crypto.asymmetric;
|
package cn.hutool.crypto.asymmetric;
|
||||||
|
|
||||||
import cn.hutool.core.codec.BaseN.Base64;
|
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.CipherWrapper;
|
||||||
import cn.hutool.crypto.CryptoException;
|
import cn.hutool.crypto.CryptoException;
|
||||||
import cn.hutool.crypto.KeyUtil;
|
import cn.hutool.crypto.KeyUtil;
|
||||||
|
@ -54,18 +54,6 @@ public interface AsymmetricEncryptor {
|
|||||||
return Base64.encode(encrypt(data, keyType));
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加密
|
* 加密
|
||||||
*
|
*
|
||||||
|
@ -62,17 +62,6 @@ public interface SymmetricEncryptor {
|
|||||||
return Base64.encode(encrypt(data));
|
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));
|
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));
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加密
|
* 加密
|
||||||
*
|
*
|
||||||
|
@ -54,7 +54,7 @@ public class FreemarkerTemplate implements Template, Serializable{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(final Map<?, ?> bindingMap, final OutputStream out) {
|
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())));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ public class ThymeleafTemplate implements Template, Serializable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(final Map<?, ?> bindingMap, final OutputStream out) {
|
public void render(final Map<?, ?> bindingMap, final OutputStream out) {
|
||||||
render(bindingMap, IoUtil.getWriter(out, this.charset));
|
render(bindingMap, IoUtil.toWriter(out, this.charset));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ public class VelocityTemplate implements Template, Serializable {
|
|||||||
if(null == charset) {
|
if(null == charset) {
|
||||||
loadEncoding();
|
loadEncoding();
|
||||||
}
|
}
|
||||||
render(bindingMap, IoUtil.getWriter(out, CharsetUtil.charset(this.charset)));
|
render(bindingMap, IoUtil.toWriter(out, CharsetUtil.charset(this.charset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cn.hutool.http.client;
|
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.io.StreamProgress;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.http.HttpException;
|
import cn.hutool.http.HttpException;
|
||||||
|
120
hutool-http/src/main/java/cn/hutool/http/client/body/FormBody.java
Executable file
120
hutool-http/src/main/java/cn/hutool/http/client/body/FormBody.java
Executable file
@ -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 <T> this类型,用于链式调用
|
||||||
|
* @author looly
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public abstract class FormBody<T extends FormBody<T>> implements RequestBody {
|
||||||
|
/**
|
||||||
|
* 存储表单数据
|
||||||
|
*/
|
||||||
|
protected Map<String, Object> form;
|
||||||
|
/**
|
||||||
|
* 编码
|
||||||
|
*/
|
||||||
|
protected final Charset charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param form 表单
|
||||||
|
* @param charset 编码
|
||||||
|
*/
|
||||||
|
protected FormBody(final Map<String, Object> form, final Charset charset) {
|
||||||
|
this.form = form;
|
||||||
|
this.charset = charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置map类型表单数据
|
||||||
|
*
|
||||||
|
* @param formMap 表单内容
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public T form(final Map<String, Object> formMap) {
|
||||||
|
if (MapUtil.isNotEmpty(formMap)) {
|
||||||
|
formMap.forEach(this::form);
|
||||||
|
}
|
||||||
|
return (T) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置表单数据<br>
|
||||||
|
* 如果传入值为{@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;
|
||||||
|
}
|
||||||
|
}
|
@ -17,32 +17,48 @@ import java.util.Map;
|
|||||||
* @author looly
|
* @author looly
|
||||||
* @since 5.3.5
|
* @since 5.3.5
|
||||||
*/
|
*/
|
||||||
public class MultipartBody implements RequestBody {
|
public class MultipartBody extends FormBody<MultipartBody> {
|
||||||
|
|
||||||
private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary=";
|
private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary=";
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储表单数据
|
|
||||||
*/
|
|
||||||
private final Map<String, Object> form;
|
|
||||||
/**
|
|
||||||
* 编码
|
|
||||||
*/
|
|
||||||
private final Charset charset;
|
|
||||||
/**
|
/**
|
||||||
* 边界
|
* 边界
|
||||||
*/
|
*/
|
||||||
private final String boundary = HttpGlobalConfig.getBoundary();
|
private final String boundary;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据已有表单内容,构建MultipartBody
|
* 根据已有表单内容,构建MultipartBody,使用全局默认的边界符{@link HttpGlobalConfig#getBoundary()}
|
||||||
*
|
*
|
||||||
* @param form 表单
|
* @param form 表单
|
||||||
* @param charset 编码
|
* @param charset 编码
|
||||||
* @return MultipartBody
|
* @return MultipartBody
|
||||||
*/
|
*/
|
||||||
public static MultipartBody of(final Map<String, Object> form, final Charset charset) {
|
public static MultipartBody of(final Map<String, Object> 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<String, Object> form, final Charset charset, final String boundary) {
|
||||||
|
return new MultipartBody(form, charset, boundary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param form 表单
|
||||||
|
* @param charset 编码
|
||||||
|
* @param boundary Multipart边界符
|
||||||
|
*/
|
||||||
|
public MultipartBody(final Map<String, Object> 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;
|
return CONTENT_TYPE_MULTIPART_PREFIX + boundary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造
|
|
||||||
*
|
|
||||||
* @param form 表单
|
|
||||||
* @param charset 编码
|
|
||||||
*/
|
|
||||||
public MultipartBody(final Map<String, Object> form, final Charset charset) {
|
|
||||||
this.form = form;
|
|
||||||
this.charset = charset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写出Multiparty数据,不关闭流
|
* 写出Multiparty数据,不关闭流
|
||||||
*
|
*
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cn.hutool.http.client.body;
|
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 cn.hutool.core.io.IoUtil;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package cn.hutool.http.client.body;
|
package cn.hutool.http.client.body;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.net.url.UrlQuery;
|
import cn.hutool.core.net.url.UrlQuery;
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -12,7 +14,7 @@ import java.util.Map;
|
|||||||
* @author looly
|
* @author looly
|
||||||
* @since 5.7.17
|
* @since 5.7.17
|
||||||
*/
|
*/
|
||||||
public class FormUrlEncodedBody extends BytesBody {
|
public class UrlEncodedFormBody extends FormBody<UrlEncodedFormBody> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建 Http request body
|
* 创建 Http request body
|
||||||
@ -21,8 +23,8 @@ public class FormUrlEncodedBody extends BytesBody {
|
|||||||
* @param charset 编码
|
* @param charset 编码
|
||||||
* @return FormUrlEncodedBody
|
* @return FormUrlEncodedBody
|
||||||
*/
|
*/
|
||||||
public static FormUrlEncodedBody of(final Map<String, Object> form, final Charset charset) {
|
public static UrlEncodedFormBody of(final Map<String, Object> form, final Charset charset) {
|
||||||
return new FormUrlEncodedBody(form, charset);
|
return new UrlEncodedFormBody(form, charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,8 +33,13 @@ public class FormUrlEncodedBody extends BytesBody {
|
|||||||
* @param form 表单
|
* @param form 表单
|
||||||
* @param charset 编码
|
* @param charset 编码
|
||||||
*/
|
*/
|
||||||
public FormUrlEncodedBody(final Map<String, Object> form, final Charset charset) {
|
public UrlEncodedFormBody(final Map<String, Object> form, final Charset charset) {
|
||||||
super(StrUtil.bytes(UrlQuery.of(form, true).build(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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -26,7 +26,7 @@ import cn.hutool.http.meta.HttpStatus;
|
|||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.hutool.http.meta.Method;
|
import cn.hutool.http.meta.Method;
|
||||||
import cn.hutool.http.client.body.BytesBody;
|
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.MultipartBody;
|
||||||
import cn.hutool.http.client.body.RequestBody;
|
import cn.hutool.http.client.body.RequestBody;
|
||||||
import cn.hutool.http.client.cookie.GlobalCookieManager;
|
import cn.hutool.http.client.cookie.GlobalCookieManager;
|
||||||
@ -1311,7 +1311,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
|
|||||||
if (ArrayUtil.isNotEmpty(this.bodyBytes)) {
|
if (ArrayUtil.isNotEmpty(this.bodyBytes)) {
|
||||||
body = BytesBody.of(this.bodyBytes);
|
body = BytesBody.of(this.bodyBytes);
|
||||||
} else {
|
} else {
|
||||||
body = FormUrlEncodedBody.of(this.form, this.charset);
|
body = UrlEncodedFormBody.of(this.form, this.charset);
|
||||||
}
|
}
|
||||||
body.writeClose(this.httpConnection.getOutputStream());
|
body.writeClose(this.httpConnection.getOutputStream());
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cn.hutool.http.client.engine.jdk;
|
package cn.hutool.http.client.engine.jdk;
|
||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
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.FileUtil;
|
||||||
import cn.hutool.core.io.IORuntimeException;
|
import cn.hutool.core.io.IORuntimeException;
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cn.hutool.http.client.engine.okhttp;
|
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.text.StrUtil;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
|
@ -74,7 +74,7 @@ public class JSONTokener {
|
|||||||
* @throws JSONException JSON异常,包装IO异常
|
* @throws JSONException JSON异常,包装IO异常
|
||||||
*/
|
*/
|
||||||
public JSONTokener(final InputStream inputStream, final JSONConfig config) throws JSONException {
|
public JSONTokener(final InputStream inputStream, final JSONConfig config) throws JSONException {
|
||||||
this(IoUtil.getUtf8Reader(inputStream), config);
|
this(IoUtil.toUtf8Reader(inputStream), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -194,7 +194,7 @@ public class GroupedSet extends HashMap<String, LinkedHashSet<String>> {
|
|||||||
super.clear();
|
super.clear();
|
||||||
BufferedReader reader = null;
|
BufferedReader reader = null;
|
||||||
try {
|
try {
|
||||||
reader = IoUtil.getReader(settingStream, charset);
|
reader = IoUtil.toReader(settingStream, charset);
|
||||||
// 分组
|
// 分组
|
||||||
String group;
|
String group;
|
||||||
LinkedHashSet<String> valueSet = null;
|
LinkedHashSet<String> valueSet = null;
|
||||||
|
@ -103,7 +103,7 @@ public class SettingLoader {
|
|||||||
this.groupedMap.clear();
|
this.groupedMap.clear();
|
||||||
BufferedReader reader = null;
|
BufferedReader reader = null;
|
||||||
try {
|
try {
|
||||||
reader = IoUtil.getReader(settingStream, this.charset);
|
reader = IoUtil.toReader(settingStream, this.charset);
|
||||||
// 分组
|
// 分组
|
||||||
String group = null;
|
String group = null;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public class YamlUtil {
|
|||||||
* @return 加载的内容,默认Map
|
* @return 加载的内容,默认Map
|
||||||
*/
|
*/
|
||||||
public static <T> T load(final InputStream in, final Class<T> type) {
|
public static <T> T load(final InputStream in, final Class<T> type) {
|
||||||
return load(IoUtil.getBomReader(in), type);
|
return load(IoUtil.toBomReader(in), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user