add IoCopier

This commit is contained in:
Looly
2021-08-11 23:30:47 +08:00
parent 9dd7b0a904
commit c54f2a154a
19 changed files with 440 additions and 171 deletions

View File

@@ -3,6 +3,8 @@ package cn.hutool.core.io;
import cn.hutool.core.collection.LineIter;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.io.copy.ReaderWriterCopier;
import cn.hutool.core.io.copy.StreamCopier;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
@@ -86,28 +88,21 @@ public class IoUtil extends NioUtil {
* @throws IORuntimeException IO异常
*/
public static long copy(Reader reader, Writer writer, int bufferSize, StreamProgress streamProgress) throws IORuntimeException {
char[] buffer = new char[bufferSize];
long size = 0;
int readSize;
if (null != streamProgress) {
streamProgress.start();
}
try {
while ((readSize = reader.read(buffer, 0, bufferSize)) != EOF) {
writer.write(buffer, 0, readSize);
size += readSize;
writer.flush();
if (null != streamProgress) {
streamProgress.progress(size);
}
}
} catch (Exception e) {
throw new IORuntimeException(e);
}
if (null != streamProgress) {
streamProgress.finish();
}
return size;
return copy(reader, writer, bufferSize, -1, streamProgress);
}
/**
* 将Reader中的内容复制到Writer中拷贝后不关闭Reader
*
* @param reader Reader
* @param writer Writer
* @param bufferSize 缓存大小
* @param streamProgress 进度处理器
* @return 传输的byte数
* @throws IORuntimeException IO异常
*/
public static long copy(Reader reader, Writer writer, int bufferSize, int count, StreamProgress streamProgress) throws IORuntimeException {
return new ReaderWriterCopier(bufferSize, count, streamProgress).copy(reader, writer);
}
/**
@@ -146,33 +141,23 @@ public class IoUtil extends NioUtil {
* @throws IORuntimeException IO异常
*/
public static long copy(InputStream in, OutputStream out, int bufferSize, StreamProgress streamProgress) throws IORuntimeException {
Assert.notNull(in, "InputStream is null !");
Assert.notNull(out, "OutputStream is null !");
if (bufferSize <= 0) {
bufferSize = DEFAULT_BUFFER_SIZE;
}
return copy(in, out, bufferSize, -1, streamProgress);
}
byte[] buffer = new byte[bufferSize];
if (null != streamProgress) {
streamProgress.start();
}
long size = 0;
try {
for (int readSize; (readSize = in.read(buffer)) != EOF; ) {
out.write(buffer, 0, readSize);
size += readSize;
if (null != streamProgress) {
streamProgress.progress(size);
}
}
out.flush();
} catch (IOException e) {
throw new IORuntimeException(e);
}
if (null != streamProgress) {
streamProgress.finish();
}
return size;
/**
* 拷贝流,拷贝后不关闭流
*
* @param in 输入流
* @param out 输出流
* @param bufferSize 缓存大小
* @param count 总拷贝长度
* @param streamProgress 进度条
* @return 传输的byte数
* @throws IORuntimeException IO异常
* @since 5.7.8
*/
public static long copy(InputStream in, OutputStream out, int bufferSize, int count, StreamProgress streamProgress) throws IORuntimeException {
return new StreamCopier(bufferSize, count, streamProgress).copy(in, out);
}
/**
@@ -390,14 +375,14 @@ public class IoUtil extends NioUtil {
*/
public static FastByteArrayOutputStream read(InputStream in, boolean isClose) throws IORuntimeException {
final FastByteArrayOutputStream out;
if(in instanceof FileInputStream){
if (in instanceof FileInputStream) {
// 文件流的长度是可预见的,此时直接读取效率更高
try {
out = new FastByteArrayOutputStream(in.available());
} catch (IOException e) {
throw new IORuntimeException(e);
}
} else{
} else {
out = new FastByteArrayOutputStream();
}
try {
@@ -434,7 +419,7 @@ public class IoUtil extends NioUtil {
final CharBuffer buffer = CharBuffer.allocate(DEFAULT_BUFFER_SIZE);
try {
while (-1 != reader.read(buffer)) {
builder.append(buffer.flip().toString());
builder.append(buffer.flip());
}
} catch (IOException e) {
throw new IORuntimeException(e);
@@ -828,7 +813,7 @@ public class IoUtil extends NioUtil {
/**
* 转换为{@link BufferedInputStream}
*
* @param in {@link InputStream}
* @param in {@link InputStream}
* @param bufferSize buffer size
* @return {@link BufferedInputStream}
* @since 5.6.1
@@ -853,7 +838,7 @@ public class IoUtil extends NioUtil {
/**
* 转换为{@link BufferedOutputStream}
*
* @param out {@link OutputStream}
* @param out {@link OutputStream}
* @param bufferSize buffer size
* @return {@link BufferedOutputStream}
* @since 5.6.1
@@ -878,7 +863,7 @@ public class IoUtil extends NioUtil {
/**
* 转换为{@link BufferedReader}
*
* @param reader {@link Reader}
* @param reader {@link Reader}
* @param bufferSize buffer size
* @return {@link BufferedReader}
* @since 5.6.1
@@ -903,7 +888,7 @@ public class IoUtil extends NioUtil {
/**
* 转换为{@link BufferedWriter}
*
* @param writer {@link Writer}
* @param writer {@link Writer}
* @param bufferSize buffer size
* @return {@link BufferedWriter}
* @since 5.6.1
@@ -1291,7 +1276,7 @@ public class IoUtil extends NioUtil {
* while (it.hasNext()) {
* String line = it.nextLine();
* // do something with line
* }
* }
* } finally {
* it.close();
* }
@@ -1301,7 +1286,7 @@ public class IoUtil extends NioUtil {
* @return {@link LineIter}
* @since 5.6.1
*/
public static LineIter lineIter(Reader reader){
public static LineIter lineIter(Reader reader) {
return new LineIter(reader);
}
@@ -1314,18 +1299,18 @@ public class IoUtil extends NioUtil {
* while (it.hasNext()) {
* String line = it.nextLine();
* // do something with line
* }
* }
* } finally {
* it.close();
* }
* </pre>
*
* @param in {@link InputStream}
* @param in {@link InputStream}
* @param charset 编码
* @return {@link LineIter}
* @since 5.6.1
*/
public static LineIter lineIter(InputStream in, Charset charset){
public static LineIter lineIter(InputStream in, Charset charset) {
return new LineIter(in, charset);
}
}

View File

@@ -2,8 +2,8 @@ package cn.hutool.core.io;
/**
* Stream进度条
* @author Looly
*
* @author Looly
*/
public interface StreamProgress {
@@ -14,6 +14,7 @@ public interface StreamProgress {
/**
* 进行中
*
* @param progressSize 已经进行的大小
*/
void progress(long progressSize);

View File

@@ -0,0 +1,60 @@
package cn.hutool.core.io.copy;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress;
/**
* IO拷贝抽象可自定义包括缓存、进度条等信息<br>
* 此对象非线程安全
*
* @param <S> 拷贝源类型如InputStream、Reader等
* @param <T> 拷贝目标类型如OutputStream、Writer等
* @author looly
* @since 5.7.8
*/
public abstract class IoCopier<S, T> {
protected final int bufferSize;
/**
* 拷贝总数
*/
protected final long count;
/**
* 进度条
*/
protected StreamProgress progress;
/**
* 构造
*
* @param bufferSize 缓存大小,&lt; 0 表示默认{@link IoUtil#DEFAULT_BUFFER_SIZE}
* @param count 拷贝总数
* @param progress 进度条
*/
public IoCopier(int bufferSize, long count, StreamProgress progress) {
this.bufferSize = bufferSize > 0 ? bufferSize : IoUtil.DEFAULT_BUFFER_SIZE;
this.count = count;
this.progress = progress;
}
/**
* 执行拷贝
*
* @param source 拷贝源如InputStream、Reader等
* @param target 拷贝目标如OutputStream、Writer等
* @return 拷贝的实际长度
*/
public abstract long copy(S source, T target);
/**
* 缓存大小,取默认缓存和目标长度最小值
* @return 缓存大小
*/
protected int bufferSize(long count) {
if(count < 0){
count = Long.MAX_VALUE;
}
return Math.min(this.bufferSize, (int)count);
}
}

View File

@@ -0,0 +1,114 @@
package cn.hutool.core.io.copy;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.lang.Assert;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
/**
* {@link Reader} 向 {@link Writer} 拷贝
*
* @author looly
* @since 5.7.8
*/
public class ReaderWriterCopier extends IoCopier<Reader, Writer> {
/**
* 构造
*/
public ReaderWriterCopier() {
this(IoUtil.DEFAULT_BUFFER_SIZE);
}
/**
* 构造
*
* @param bufferSize 缓存大小
*/
public ReaderWriterCopier(int bufferSize) {
this(bufferSize, -1);
}
/**
* 构造
*
* @param bufferSize 缓存大小
* @param count 拷贝总数
*/
public ReaderWriterCopier(int bufferSize, long count) {
this(bufferSize, count, null);
}
/**
* 构造
*
* @param bufferSize 缓存大小
* @param count 拷贝总数
* @param progress 进度条
*/
public ReaderWriterCopier(int bufferSize, long count, StreamProgress progress) {
super(bufferSize, count, progress);
}
@Override
public long copy(Reader source, Writer target) {
Assert.notNull(source, "InputStream is null !");
Assert.notNull(target, "OutputStream is null !");
final StreamProgress progress = this.progress;
if (null != progress) {
progress.start();
}
final long size;
try {
size = doCopy(source, target, new char[bufferSize(this.count)], progress);
target.flush();
} catch (IOException e) {
throw new IORuntimeException(e);
}
if (null != progress) {
progress.finish();
}
return size;
}
/**
* 执行拷贝,如果限制最大长度,则按照最大长度读取,否则一直读取直到遇到-1
*
* @param source {@link InputStream}
* @param target {@link OutputStream}
* @param buffer 缓存
* @param progress 进度条
* @return 拷贝总长度
* @throws IOException IO异常
*/
private long doCopy(Reader source, Writer target, char[] buffer, StreamProgress progress) throws IOException {
long numToRead = this.count > 0 ? this.count : Long.MAX_VALUE;
long total = 0;
int read;
while (numToRead > 0) {
read = source.read(buffer, 0, bufferSize(numToRead));
if (read < 0) {
// 提前读取到末尾
break;
}
target.write(buffer, 0, read);
numToRead -= read;
total += read;
if (null != progress) {
progress.progress(total);
}
}
return total;
}
}

View File

@@ -0,0 +1,112 @@
package cn.hutool.core.io.copy;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.lang.Assert;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* {@link InputStream} 向 {@link OutputStream} 拷贝
*
* @author looly
* @since 5.7.8
*/
public class StreamCopier extends IoCopier<InputStream, OutputStream> {
/**
* 构造
*/
public StreamCopier() {
this(IoUtil.DEFAULT_BUFFER_SIZE);
}
/**
* 构造
*
* @param bufferSize 缓存大小
*/
public StreamCopier(int bufferSize) {
this(bufferSize, -1);
}
/**
* 构造
*
* @param bufferSize 缓存大小
* @param count 拷贝总数
*/
public StreamCopier(int bufferSize, long count) {
this(bufferSize, count, null);
}
/**
* 构造
*
* @param bufferSize 缓存大小
* @param count 拷贝总数
* @param progress 进度条
*/
public StreamCopier(int bufferSize, long count, StreamProgress progress) {
super(bufferSize, count, progress);
}
@Override
public long copy(InputStream source, OutputStream target) {
Assert.notNull(source, "InputStream is null !");
Assert.notNull(target, "OutputStream is null !");
final StreamProgress progress = this.progress;
if (null != progress) {
progress.start();
}
final long size;
try {
size = doCopy(source, target, new byte[bufferSize(this.count)], progress);
target.flush();
} catch (IOException e) {
throw new IORuntimeException(e);
}
if (null != progress) {
progress.finish();
}
return size;
}
/**
* 执行拷贝,如果限制最大长度,则按照最大长度读取,否则一直读取直到遇到-1
*
* @param source {@link InputStream}
* @param target {@link OutputStream}
* @param buffer 缓存
* @param progress 进度条
* @return 拷贝总长度
* @throws IOException IO异常
*/
private long doCopy(InputStream source, OutputStream target, byte[] buffer, StreamProgress progress) throws IOException {
long numToRead = this.count > 0 ? this.count : Long.MAX_VALUE;
long total = 0;
int read;
while (numToRead > 0) {
read = source.read(buffer, 0, bufferSize(numToRead));
if (read < 0) {
// 提前读取到末尾
break;
}
target.write(buffer, 0, read);
numToRead -= read;
total += read;
if (null != progress) {
progress.progress(total);
}
}
return total;
}
}

View File

@@ -0,0 +1,7 @@
/**
* IO流拷贝相关封装相关封装
*
* @author looly
* @since 5.7.8
*/
package cn.hutool.core.io.copy;

View File

@@ -78,8 +78,7 @@ public class Snowflake implements Serializable {
* 构造使用自动生成的工作节点ID和数据中心ID
*/
public Snowflake() {
this(IdUtil.getWorkerId(IdUtil.getDataCenterId(MAX_DATA_CENTER_ID), MAX_WORKER_ID)
, IdUtil.getDataCenterId(MAX_DATA_CENTER_ID));
this(IdUtil.getWorkerId(IdUtil.getDataCenterId(MAX_DATA_CENTER_ID), MAX_WORKER_ID));
}
/**

View File

@@ -14,6 +14,12 @@ import java.security.cert.X509Certificate;
*/
public class DefaultTrustManager extends X509ExtendedTrustManager {
/**
* 默认的全局单例默认信任管理器,,默认信任所有客户端和服务端证书
* @since 5.7.8
*/
public static DefaultTrustManager INSTANCE = new DefaultTrustManager();
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;

View File

@@ -13,46 +13,24 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* {@link SSLContext}构建器
* {@link SSLContext}构建器,可以自定义:<br>
* <ul>
* <li>协议protocol默认TLS</li>
* <li>{@link KeyManager},默认空</li>
* <li>{@link TrustManager},默认{@link DefaultTrustManager},即信任全部</li>
* <li>{@link SecureRandom}</li>
* </ul>
*
* 构建后可获得{@link SSLContext},通过调用{@link SSLContext#getSocketFactory()}获取{@link javax.net.ssl.SSLSocketFactory}
*
* @author Looly
* @since 5.5.2
*/
public class SSLContextBuilder {
/**
* Supports some version of SSL; may support other versions
*/
public static final String SSL = "SSL";
/**
* Supports SSL version 2 or later; may support other versions
*/
public static final String SSLv2 = "SSLv2";
/**
* Supports SSL version 3; may support other versions
*/
public static final String SSLv3 = "SSLv3";
/**
* Supports some version of TLS; may support other versions
*/
public static final String TLS = "TLS";
/**
* Supports RFC 2246: TLS version 1.0 ; may support other versions
*/
public static final String TLSv1 = "TLSv1";
/**
* Supports RFC 4346: TLS version 1.1 ; may support other versions
*/
public static final String TLSv11 = "TLSv1.1";
/**
* Supports RFC 5246: TLS version 1.2 ; may support other versions
*/
public static final String TLSv12 = "TLSv1.2";
public class SSLContextBuilder implements SSLProtocols {
private String protocol = TLS;
private KeyManager[] keyManagers;
private TrustManager[] trustManagers = {new DefaultTrustManager()};
private TrustManager[] trustManagers = {DefaultTrustManager.INSTANCE};
private SecureRandom secureRandom = new SecureRandom();
@@ -136,7 +114,7 @@ public class SSLContextBuilder {
* @return {@link SSLContext}
* @throws IORuntimeException 包装 GeneralSecurityException异常
*/
public SSLContext buildQuietly() throws IORuntimeException{
public SSLContext buildQuietly() throws IORuntimeException {
try {
return build();
} catch (GeneralSecurityException e) {

View File

@@ -0,0 +1,40 @@
package cn.hutool.core.net;
/**
* SSL或TLS协议
*
* @author looly
* @since 5.7.8
*/
public interface SSLProtocols {
/**
* Supports some version of SSL; may support other versions
*/
String SSL = "SSL";
/**
* Supports SSL version 2 or later; may support other versions
*/
String SSLv2 = "SSLv2";
/**
* Supports SSL version 3; may support other versions
*/
String SSLv3 = "SSLv3";
/**
* Supports some version of TLS; may support other versions
*/
String TLS = "TLS";
/**
* Supports RFC 2246: TLS version 1.0 ; may support other versions
*/
String TLSv1 = "TLSv1";
/**
* Supports RFC 4346: TLS version 1.1 ; may support other versions
*/
String TLSv11 = "TLSv1.1";
/**
* Supports RFC 5246: TLS version 1.2 ; may support other versions
*/
String TLSv12 = "TLSv1.2";
}

View File

@@ -14,6 +14,18 @@ import javax.net.ssl.TrustManager;
*/
public class SSLUtil {
/**
* 创建{@link SSLContext},默认新人全部
*
* @param protocol SSL协议例如TLS等
* @return {@link SSLContext}
* @throws IORuntimeException 包装 GeneralSecurityException异常
* @since 5.7.8
*/
public static SSLContext createSSLContext(String protocol) throws IORuntimeException{
return SSLContextBuilder.create().setProtocol(protocol).buildQuietly();
}
/**
* 创建{@link SSLContext}
*