This commit is contained in:
Looly
2024-09-07 20:04:36 +08:00
parent c74e244959
commit 1fa1b5f173
5 changed files with 97 additions and 35 deletions

View File

@@ -67,7 +67,7 @@ import java.util.Objects;
*/ */
public class IoUtil extends NioUtil { public class IoUtil extends NioUtil {
// region -------------------------------------------------------------------------------------- Copy // region ----- Copy
/** /**
* 将Reader中的内容复制到Writer中 使用默认缓存大小拷贝后不关闭Reader * 将Reader中的内容复制到Writer中 使用默认缓存大小拷贝后不关闭Reader
@@ -197,9 +197,9 @@ public class IoUtil extends NioUtil {
return FileChannelCopier.of().copy(in, out); return FileChannelCopier.of().copy(in, out);
} }
// endregion -------------------------------------------------------------------------------------- Copy // endregion ----- Copy
// region -------------------------------------------------------------------------------------- toReader and toWriter // region ----- toReader and toWriter
/** /**
* 获得一个文件读取器,默认使用 UTF-8 编码 * 获得一个文件读取器,默认使用 UTF-8 编码
@@ -274,9 +274,9 @@ public class IoUtil extends NioUtil {
return new OutputStreamWriter(out, charset); return new OutputStreamWriter(out, charset);
} }
} }
// endregion -------------------------------------------------------------------------------------- toReader and toWriter // endregion ----- toReader and toWriter
// region -------------------------------------------------------------------------------------- read // region ----- read
/** /**
* 从流中读取UTF8编码的内容 * 从流中读取UTF8编码的内容
@@ -423,7 +423,7 @@ public class IoUtil extends NioUtil {
* @param acceptClasses 读取对象类型 * @param acceptClasses 读取对象类型
* @return 输出流 * @return 输出流
* @throws IORuntimeException IO异常 * @throws IORuntimeException IO异常
* @throws HutoolException ClassNotFoundException包装 * @throws HutoolException ClassNotFoundException包装
*/ */
public static <T> T readObj(final InputStream in, final Class<?>... acceptClasses) throws IORuntimeException, HutoolException { public static <T> T readObj(final InputStream in, final Class<?>... acceptClasses) throws IORuntimeException, HutoolException {
return StreamReader.of(in, false).readObj(acceptClasses); return StreamReader.of(in, false).readObj(acceptClasses);
@@ -513,9 +513,9 @@ public class IoUtil extends NioUtil {
} }
} }
// endregion -------------------------------------------------------------------------------------- read // endregion ----- read
// region -------------------------------------------------------------------------------------- toStream // region ----- toStream
/** /**
* String 转为UTF-8编码的字节流流 * String 转为UTF-8编码的字节流流
@@ -806,9 +806,9 @@ public class IoUtil extends NioUtil {
return pushbackInputStream; return pushbackInputStream;
} }
// endregion -------------------------------------------------------------------------------------- toStream // endregion ----- toStream
// region ----------------------------------------------------------------------------------------------- write // region -------------- write
/** /**
* 将byte[]写到流中,并关闭目标流 * 将byte[]写到流中,并关闭目标流
@@ -882,7 +882,7 @@ public class IoUtil extends NioUtil {
public static void writeObjects(final OutputStream out, final boolean isCloseOut, final Object... contents) throws IORuntimeException { public static void writeObjects(final OutputStream out, final boolean isCloseOut, final Object... contents) throws IORuntimeException {
StreamWriter.of(out, isCloseOut).writeObjs(contents); StreamWriter.of(out, isCloseOut).writeObjs(contents);
} }
// endregion ----------------------------------------------------------------------------------------------- write // endregion -------------- write
/** /**
* 从缓存中刷出数据 * 从缓存中刷出数据
@@ -1099,4 +1099,22 @@ public class IoUtil extends NioUtil {
throw new IORuntimeException(e); throw new IORuntimeException(e);
} }
} }
/**
* 获取流长度,对于文件流,会调用{@link FileInputStream#available()}方法,对于其他流,返回-1<br>
* 对于网络流available可能为分段大小所以返回-1
*
* @param in 流
* @return 长度,-1表示未知长度
*/
public static int length(final InputStream in) {
if (in instanceof FileInputStream) {
try {
return in.available();
} catch (final IOException e) {
throw new IORuntimeException(e);
}
}
return -1;
}
} }

View File

@@ -16,6 +16,8 @@
package org.dromara.hutool.core.io.buffer; package org.dromara.hutool.core.io.buffer;
import org.dromara.hutool.core.io.IoUtil;
/** /**
* 代码移植自<a href="https://github.com/biezhi/blade">blade</a><br> * 代码移植自<a href="https://github.com/biezhi/blade">blade</a><br>
* 快速缓冲,将数据存放在缓冲集中,取代以往的单一数组 * 快速缓冲,将数据存放在缓冲集中,取代以往的单一数组
@@ -59,7 +61,7 @@ public class FastByteBuffer {
* 构造 * 构造
*/ */
public FastByteBuffer() { public FastByteBuffer() {
this(1024); this(IoUtil.DEFAULT_BUFFER_SIZE);
} }
/** /**
@@ -69,7 +71,7 @@ public class FastByteBuffer {
*/ */
public FastByteBuffer(int size) { public FastByteBuffer(int size) {
if (size <= 0) { if (size <= 0) {
size = 1024; size = IoUtil.DEFAULT_BUFFER_SIZE;
} }
this.minChunkLen = Math.abs(size); this.minChunkLen = Math.abs(size);
} }

View File

@@ -16,12 +16,14 @@
package org.dromara.hutool.core.io.stream; package org.dromara.hutool.core.io.stream;
import org.dromara.hutool.core.io.buffer.FastByteBuffer;
import org.dromara.hutool.core.io.IORuntimeException; import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.io.buffer.FastByteBuffer;
import org.dromara.hutool.core.util.CharsetUtil; import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.core.util.ObjUtil;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@@ -38,13 +40,32 @@ import java.nio.charset.Charset;
*/ */
public class FastByteArrayOutputStream extends OutputStream { public class FastByteArrayOutputStream extends OutputStream {
/**
* 根据输入流的总长度创建一个{@code FastByteArrayOutputStream}对象<br>
* 如果输入流的长度不确定,且
*
* @param in 输入流
* @param limit 限制大小
* @return {@code FastByteArrayOutputStream}
*/
public static FastByteArrayOutputStream of(final InputStream in, final int limit) {
int length = IoUtil.length(in);
if (length < 0 || length > limit) {
length = limit;
}
if (length < 0) {
length = IoUtil.DEFAULT_BUFFER_SIZE;
}
return new FastByteArrayOutputStream(length);
}
private final FastByteBuffer buffer; private final FastByteBuffer buffer;
/** /**
* 构造 * 构造
*/ */
public FastByteArrayOutputStream() { public FastByteArrayOutputStream() {
this(1024); this(IoUtil.DEFAULT_BUFFER_SIZE);
} }
/** /**

View File

@@ -16,6 +16,7 @@
package org.dromara.hutool.core.io.stream; package org.dromara.hutool.core.io.stream;
import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import java.io.FilterInputStream; import java.io.FilterInputStream;
@@ -32,6 +33,16 @@ public class LimitedInputStream extends FilterInputStream {
protected long limit; protected long limit;
private final boolean throwWhenReachLimit; private final boolean throwWhenReachLimit;
/**
* 构造
*
* @param in {@link InputStream}
* @param limit 限制最大读取量单位byte
*/
public LimitedInputStream(final InputStream in, final long limit) {
this(in, limit, true);
}
/** /**
* 构造 * 构造
* *
@@ -47,7 +58,7 @@ public class LimitedInputStream extends FilterInputStream {
@Override @Override
public int read() throws IOException { public int read() throws IOException {
final int data = (limit == 0) ? -1 : super.read(); final int data = (limit == 0) ? IoUtil.EOF : super.read();
checkLimit(data); checkLimit(data);
limit = (data < 0) ? 0 : limit - 1; limit = (data < 0) ? 0 : limit - 1;
return data; return data;
@@ -55,7 +66,7 @@ public class LimitedInputStream extends FilterInputStream {
@Override @Override
public int read(final byte[] b, final int off, final int len) throws IOException { public int read(final byte[] b, final int off, final int len) throws IOException {
final int length = (limit == 0) ? -1 : super.read(b, off, len > limit ? (int) limit : len); final int length = (limit == 0) ? IoUtil.EOF : super.read(b, off, len > limit ? (int) limit : len);
checkLimit(length); checkLimit(length);
limit = (length < 0) ? 0 : limit - length; limit = (length < 0) ? 0 : limit - length;
return length; return length;
@@ -72,7 +83,7 @@ public class LimitedInputStream extends FilterInputStream {
@Override @Override
public int available() throws IOException { public int available() throws IOException {
final int length = super.available(); final int length = super.available();
return length > limit ? (int)limit : length; return length > limit ? (int) limit : length;
} }
/** /**

View File

@@ -20,9 +20,9 @@ import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.io.IORuntimeException; import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.io.IoUtil;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.function.Predicate;
/** /**
* {@link InputStream}读取器 * {@link InputStream}读取器
@@ -102,21 +102,7 @@ public class StreamReader {
*/ */
public FastByteArrayOutputStream read(final int limit) throws IORuntimeException { public FastByteArrayOutputStream read(final int limit) throws IORuntimeException {
final InputStream in = this.in; final InputStream in = this.in;
final FastByteArrayOutputStream out; final FastByteArrayOutputStream out = FastByteArrayOutputStream.of(in, limit);
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 { try {
IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE, limit, null); IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE, limit, null);
} finally { } finally {
@@ -127,6 +113,30 @@ public class StreamReader {
return out; return out;
} }
/**
* 从流中读取内容直到遇到给定token满足{@link Predicate#test(Object)}
*
* @param predicate 读取结束条件, {@link Predicate#test(Object)}返回true表示结束
* @return 输出流
* @throws IORuntimeException IO异常
*/
public FastByteArrayOutputStream readTo(final Predicate<Integer> predicate) throws IORuntimeException {
final InputStream in = this.in;
final FastByteArrayOutputStream out = FastByteArrayOutputStream.of(in, -1);
int read;
try {
while ((read = in.read()) > 0) {
if (null != predicate && predicate.test(read)) {
break;
}
out.write(read);
}
} catch (final IOException e) {
throw new IORuntimeException(e);
}
return out;
}
/** /**
* 从流中读取对象,即对象的反序列化 * 从流中读取对象,即对象的反序列化
* *
@@ -142,7 +152,7 @@ public class StreamReader {
* @param acceptClasses 读取对象类型 * @param acceptClasses 读取对象类型
* @return 输出流 * @return 输出流
* @throws IORuntimeException IO异常 * @throws IORuntimeException IO异常
* @throws HutoolException ClassNotFoundException包装 * @throws HutoolException ClassNotFoundException包装
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T readObj(final Class<?>... acceptClasses) throws IORuntimeException, HutoolException { public <T> T readObj(final Class<?>... acceptClasses) throws IORuntimeException, HutoolException {