Merge branch 'v6-dev' of gitee.com:dromara/hutool into v6-dev

This commit is contained in:
Looly 2024-10-09 18:12:21 +08:00
commit 64efd26c5f
2 changed files with 164 additions and 152 deletions

View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.core.io;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.text.StrUtil;
import java.io.Reader;
import java.util.Objects;
/**
* 基于{@link CharSequence}{@link Reader}实现用于支持{@link CharSequence}的读取<br>
* 相比jdk的StringReader非线程安全速度更快
*
* @author Looly
* @since 6.0.0
*/
public class CharSequenceReader extends Reader {
private final int start;
private final int end;
private final CharSequence str;
/**
* 读取到的位置
*/
private int next;
/**
* 读取标记位置
*/
private int mark;
/**
* 构造
*
* @param str {@link CharSequence}
* @param startInclude 开始位置包含
* @param endExclude 结束位置不包含
*/
public CharSequenceReader(CharSequence str, final int startInclude, final int endExclude) {
Assert.isTrue(startInclude >= 0, "Start index is less than zero: {}", startInclude);
Assert.isTrue(endExclude > startInclude, "End index is less than start {}: {}", startInclude, endExclude);
if (null == str) {
str = StrUtil.EMPTY;
}
this.str = str;
final int length = str.length();
this.start = Math.min(length, startInclude);
this.end = Math.min(length, endExclude);
this.next = startInclude;
this.mark = startInclude;
}
@Override
public boolean markSupported() {
return true;
}
@Override
public void mark(final int readAheadLimit) {
mark = next;
}
@Override
public void reset() {
next = mark;
}
@Override
public int read() {
if (next >= end) {
return IoUtil.EOF;
}
return str.charAt(next++);
}
@Override
public int read(final char[] array, final int offset, final int length) {
if (next >= end) {
return IoUtil.EOF;
}
Objects.requireNonNull(array, "array");
if (length < 0 || offset < 0 || offset + length > array.length) {
throw new IndexOutOfBoundsException("Array Size=" + array.length +
", offset=" + offset + ", length=" + length);
}
if (str instanceof String) {
final int count = Math.min(length, end - next);
((String) str).getChars(next, next + count, array, offset);
next += count;
return count;
}
if (str instanceof StringBuilder) {
final int count = Math.min(length, end - next);
((StringBuilder) str).getChars(next, next + count, array, offset);
next += count;
return count;
}
if (str instanceof StringBuffer) {
final int count = Math.min(length, end - next);
((StringBuffer) str).getChars(next, next + count, array, offset);
next += count;
return count;
}
int count = 0;
for (int i = 0; i < length; i++) {
final int c = read();
if (c == IoUtil.EOF) {
return count;
}
array[offset + i] = (char) c;
count++;
}
return count;
}
@Override
public long skip(final long n) {
if (n < 0) {
throw new IllegalArgumentException("Number of characters to skip is less than zero: " + n);
}
if (next >= end) {
return 0;
}
final int dest = (int) Math.min(end, next + n);
final int count = dest - next;
next = dest;
return count;
}
@Override
public boolean ready() {
return next < end;
}
@Override
public void close() {
next = start;
mark = start;
}
@Override
public String toString() {
return str.subSequence(start, end).toString();
}
}

View File

@ -1,152 +0,0 @@
/*
* Copyright (c) 2013-2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.core.io;
import java.io.IOException;
import java.io.Reader;
/**
* 快速字符串读取相比jdk的StringReader非线程安全速度更快
*
* @author looly
*/
public class FastStringReader extends Reader {
private String str;
private final int length;
private int next = 0;
private int mark = 0;
/**
* 构造
*
* @param s 供读取的String
*/
public FastStringReader(final String s) {
this.str = s;
this.length = s.length();
}
/**
* 读取单个字符
*
* @return 读取的字符, -1表示读取结束
* @throws IOException IO异常
*/
@Override
public int read() throws IOException {
ensureOpen();
if (next >= length) {
return -1;
}
return str.charAt(next++);
}
/**
* 将多个字符读取到提供的字符数组中
*
* @param charBuffer 目标buffer
* @param off 开始位置
* @param len 读取最大长度
* @return 读取的字符长度, -1表示读取到了末尾
* @throws IOException IO异常
*/
@Override
public int read(final char[] charBuffer, final int off, final int len) throws IOException {
ensureOpen();
if ((off < 0) || (off > charBuffer.length) || (len < 0) ||
((off + len) > charBuffer.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (len == 0) {
return 0;
}
if (next >= length) {
return -1;
}
final int n = Math.min(length - next, len);
str.getChars(next, next + n, charBuffer, off);
next += n;
return n;
}
/**
* 跳过指定长度返回跳过的字符数
*
* <p>{@code ns} 参数可能为负数, 负数表示向前跳过跳到开头则停止
*
* <p>如果字符串所有字符被读取或跳过, 此方法无效始终返回0.
*
* @throws IOException IO异常
*/
@Override
public long skip(final long ns) throws IOException {
ensureOpen();
if (next >= length){
return 0;
}
// Bound skip by beginning and end of the source
long n = Math.min(length - next, ns);
n = Math.max(-next, n);
next += n;
return n;
}
@Override
public boolean ready() throws IOException {
ensureOpen();
return true;
}
@Override
public boolean markSupported() {
return true;
}
@Override
public void mark(final int readAheadLimit) throws IOException {
if (readAheadLimit < 0) {
throw new IllegalArgumentException("Read-ahead limit < 0");
}
ensureOpen();
mark = next;
}
@Override
public void reset() throws IOException {
ensureOpen();
next = mark;
}
@Override
public void close() {
str = null;
}
/**
* Check to make sure that the stream has not been closed
*/
private void ensureOpen() throws IOException {
if (str == null){
throw new IOException("Stream closed");
}
}
}