From d21c641efd3bf28d3163533a5bb077411672dc30 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 13 Nov 2022 22:06:29 +0800 Subject: [PATCH] fix code --- .../java/cn/hutool/core/io/LineReader.java | 107 ++++++++++++++---- .../hutool/core/io/resource/ResourceUtil.java | 2 +- .../core/lang/func/SerUnaryOperator.java | 1 + .../cn/hutool/core/io/LineReaderTest.java | 23 +++- .../src/test/resources/multi_line.properties | 32 +----- .../test/resources/multi_line_crlf.properties | 5 + .../java/cn/hutool/setting/SettingLoader.java | 10 +- 7 files changed, 122 insertions(+), 58 deletions(-) create mode 100755 hutool-core/src/test/resources/multi_line_crlf.properties diff --git a/hutool-core/src/main/java/cn/hutool/core/io/LineReader.java b/hutool-core/src/main/java/cn/hutool/core/io/LineReader.java index 0e7c559ca..eba0c8455 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/LineReader.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/LineReader.java @@ -1,22 +1,44 @@ package cn.hutool.core.io; -import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.collection.iter.ComputeIter; +import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; import java.io.IOException; +import java.io.InputStream; import java.io.Reader; +import java.nio.charset.Charset; +import java.util.Iterator; /** - * 行读取器,类似于BufferedInputStream,支持注释和多行转义 - * TODO 待实现 + * 行读取器,类似于BufferedInputStream,支持多行转义,规则如下:
+ * + *

+ * 例子: + *

+ * a=1\
+ *   2
+ * 
+ * 读出后就是{@code a=12} * * @author looly + * @since 6.0.0 */ -public class LineReader extends ReaderWrapper { +public class LineReader extends ReaderWrapper implements Iterable { /** - * 注释标识符 + * 构造 + * + * @param in {@link InputStream} + * @param charset 编码 */ - private char[] commentFlags; + public LineReader(final InputStream in, final Charset charset) { + this(IoUtil.toReader(in, charset)); + } /** * 构造 @@ -24,22 +46,7 @@ public class LineReader extends ReaderWrapper { * @param reader {@link Reader} */ public LineReader(final Reader reader) { - super(reader); - } - - /** - * 设置注释行标识符 - * - * @param commentFlags 注释行标识符 - * @return this - */ - public LineReader setCommentFlags(final char... commentFlags) { - if (ArrayUtil.isEmpty(commentFlags)) { - // 无注释行 - this.commentFlags = null; - } - this.commentFlags = ArrayUtil.copy(commentFlags, new char[commentFlags.length]); - return this; + super(IoUtil.toBuffered(reader)); } /** @@ -49,6 +56,60 @@ public class LineReader extends ReaderWrapper { * @throws IOException IO异常 */ public String readLine() throws IOException { - return null; + StringBuilder str = null; + // 换行符前是否为转义符 + boolean precedingBackslash = false; + int c; + while ((c = read()) > 0) { + if (null == str) { + // 只有有字符的情况下才初始化行,否则为行结束 + str = StrUtil.builder(1024); + } + if (CharUtil.BACKSLASH == c) { + // 转义符转义,行尾需要使用'\'时,使用转义符转义,即`\\` + if (false == precedingBackslash) { + // 转义符,添加标识,但是不加入字符 + precedingBackslash = true; + continue; + } else { + precedingBackslash = false; + } + } else { + if (precedingBackslash) { + // 转义模式下,跳过转义符后的所有空白符 + if (CharUtil.isBlankChar(c)) { + continue; + } + // 遇到普通字符,关闭转义 + precedingBackslash = false; + } else if (CharUtil.LF == c) { + // 非转义状态下,表示行的结束 + // 如果换行符是`\r\n`,删除末尾的`\r` + final int lastIndex = str.length() - 1; + if (lastIndex >= 0 && CharUtil.CR == str.charAt(lastIndex)) { + str.deleteCharAt(lastIndex); + } + break; + } + } + + str.append((char) c); + } + + return StrUtil.toStringOrNull(str); + } + + @Override + public Iterator iterator() { + return new ComputeIter() { + @Override + protected String computeNext() { + try { + return readLine(); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + }; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java index bed806d64..1ce456083 100755 --- a/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/resource/ResourceUtil.java @@ -194,7 +194,7 @@ public class ResourceUtil { public static EnumerationIter getResourceUrlIter(final String resource, final ClassLoader classLoader) { final Enumeration resources; try { - resources = ObjUtil.defaultIfNull(classLoader, ClassLoaderUtil.getClassLoader()).getResources(resource); + resources = ObjUtil.defaultIfNull(classLoader, ClassLoaderUtil::getClassLoader).getResources(resource); } catch (final IOException e) { throw new IORuntimeException(e); } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerUnaryOperator.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerUnaryOperator.java index bf6295228..8ddc6d489 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/SerUnaryOperator.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/SerUnaryOperator.java @@ -9,6 +9,7 @@ import java.util.function.UnaryOperator; /** * 可序列化的UnaryOperator * + * @param 参数类型 * @author VampireAchao * @see UnaryOperator */ diff --git a/hutool-core/src/test/java/cn/hutool/core/io/LineReaderTest.java b/hutool-core/src/test/java/cn/hutool/core/io/LineReaderTest.java index 2300bcdaa..01bdfdc39 100755 --- a/hutool-core/src/test/java/cn/hutool/core/io/LineReaderTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/LineReaderTest.java @@ -1,11 +1,30 @@ package cn.hutool.core.io; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.io.resource.ResourceUtil; +import org.junit.Assert; import org.junit.Test; -import java.io.IOException; +import java.util.ArrayList; public class LineReaderTest { @Test - public void readTest() throws IOException { + public void readLfTest() { + final LineReader lineReader = new LineReader(ResourceUtil.getUtf8Reader("multi_line.properties")); + final ArrayList list = ListUtil.of(lineReader); + Assert.assertEquals(3, list.size()); + Assert.assertEquals("test1", list.get(0)); + Assert.assertEquals("test2=abcd\\e", list.get(1)); + Assert.assertEquals("test3=abc", list.get(2)); + } + + @Test + public void readCrLfTest() { + final LineReader lineReader = new LineReader(ResourceUtil.getUtf8Reader("multi_line_crlf.properties")); + final ArrayList list = ListUtil.of(lineReader); + Assert.assertEquals(3, list.size()); + Assert.assertEquals("test1", list.get(0)); + Assert.assertEquals("test2=abcd\\e", list.get(1)); + Assert.assertEquals("test3=abc", list.get(2)); } } diff --git a/hutool-core/src/test/resources/multi_line.properties b/hutool-core/src/test/resources/multi_line.properties index 17719feaa..432d0997a 100755 --- a/hutool-core/src/test/resources/multi_line.properties +++ b/hutool-core/src/test/resources/multi_line.properties @@ -1,27 +1,5 @@ -client.mode=single -configure={\ - "singleServerConfig":{\ - "idleConnectionTimeout":10000,\ - "pingTimeout":1000, \ - "connectTimeout":10000, \ - "timeout":3000,\ - "retryAttempts":3,\ - "retryInterval":1500,\ - "reconnectionTimeout":3000,\ - "failedAttempts":3,\ - "password":null,\ - "subscriptionsPerConnection":5,\ - "clientName":null,\ - "address": "redis://127.0.0.1:6379",\ - "subscriptionConnectionMinimumIdleSize":1,\ - "subscriptionConnectionPoolSize":50,\ - "connectionMinimumIdleSize":12,\ - "connectionPoolSize":12\ - },\ - "threads":2,\ - "nettyThreads":2,\ - "codec":{\ - "class":"org.redisson.client.codec.StringCodec"\ - },\ - "transportMode":"NIO"\ - } +test1 +test2=a\ + bc\ + d\\e +test3=abc diff --git a/hutool-core/src/test/resources/multi_line_crlf.properties b/hutool-core/src/test/resources/multi_line_crlf.properties new file mode 100755 index 000000000..12b8b1c9a --- /dev/null +++ b/hutool-core/src/test/resources/multi_line_crlf.properties @@ -0,0 +1,5 @@ +test1 +test2=a\ + bc\ + d\\e +test3=abc diff --git a/hutool-setting/src/main/java/cn/hutool/setting/SettingLoader.java b/hutool-setting/src/main/java/cn/hutool/setting/SettingLoader.java index 4735fe91f..516284d49 100755 --- a/hutool-setting/src/main/java/cn/hutool/setting/SettingLoader.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/SettingLoader.java @@ -2,16 +2,16 @@ package cn.hutool.setting; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; +import cn.hutool.core.io.LineReader; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.lang.Assert; -import cn.hutool.core.util.CharUtil; -import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.regex.ReUtil; import cn.hutool.core.text.StrUtil; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.SystemUtil; import cn.hutool.log.Log; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -101,9 +101,9 @@ public class SettingLoader { */ synchronized public boolean load(final InputStream settingStream) throws IOException { this.groupedMap.clear(); - BufferedReader reader = null; + LineReader reader = null; try { - reader = IoUtil.toReader(settingStream, this.charset); + reader = new LineReader(settingStream, this.charset); // 分组 String group = null;