mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add CharSequenceReader and remove FastStringReader
This commit is contained in:
parent
003ff34af1
commit
88e70404bc
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user