diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/io/CharSequenceReader.java b/hutool-core/src/main/java/org/dromara/hutool/core/io/CharSequenceReader.java
new file mode 100644
index 000000000..79612f612
--- /dev/null
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/io/CharSequenceReader.java
@@ -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}的读取
+ * 相比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();
+ }
+}
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/io/FastStringReader.java b/hutool-core/src/main/java/org/dromara/hutool/core/io/FastStringReader.java
deleted file mode 100644
index 57b3df033..000000000
--- a/hutool-core/src/main/java/org/dromara/hutool/core/io/FastStringReader.java
+++ /dev/null
@@ -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;
- }
-
- /**
- * 跳过指定长度,返回跳过的字符数。
- *
- *
{@code ns} 参数可能为负数, 负数表示向前跳过,跳到开头则停止 - * - *
如果字符串所有字符被读取或跳过, 此方法无效,始终返回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"); - } - } -}