diff --git a/hutool-core/src/main/java/cn/hutool/core/io/CircularByteBuffer.java b/hutool-core/src/main/java/cn/hutool/core/io/CircularByteBuffer.java
new file mode 100755
index 000000000..72508e1d7
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/core/io/CircularByteBuffer.java
@@ -0,0 +1,239 @@
+package cn.hutool.core.io;
+
+import java.util.Objects;
+
+/**
+ * 循环缓冲区
+ *
+ * @author apache commons io
+ */
+public class CircularByteBuffer {
+ private final byte[] buffer;
+ private int startOffset;
+ private int endOffset;
+ private int currentNumberOfBytes;
+
+ /**
+ * 默认缓冲大小的构造({@link IoUtil#DEFAULT_BUFFER_SIZE})
+ */
+ public CircularByteBuffer() {
+ this(IoUtil.DEFAULT_BUFFER_SIZE);
+ }
+
+ /**
+ * 构造
+ *
+ * @param pSize 缓冲大小
+ */
+ public CircularByteBuffer(final int pSize) {
+ buffer = new byte[pSize];
+ startOffset = 0;
+ endOffset = 0;
+ currentNumberOfBytes = 0;
+ }
+
+ /**
+ * 从buffer中读取下一个byte,同时移除这个bytes。
+ *
+ * @return The byte
+ * @throws IllegalStateException buffer为空抛出,使用{@link #hasBytes()},或 {@link #getCurrentNumberOfBytes()}判断
+ */
+ public byte read() {
+ if (currentNumberOfBytes <= 0) {
+ throw new IllegalStateException("No bytes available.");
+ }
+ final byte b = buffer[startOffset];
+ --currentNumberOfBytes;
+ if (++startOffset == buffer.length) {
+ startOffset = 0;
+ }
+ return b;
+ }
+
+ /**
+ * Returns the given number of bytes from the buffer by storing them in
+ * the given byte array at the given offset.
+ * 从buffer中获取指定长度的bytes,从给定的targetBuffer的targetOffset位置写出
+ *
+ * @param targetBuffer 目标bytes
+ * @param targetOffset 目标数组开始位置
+ * @param length 读取长度
+ * @throws NullPointerException 提供的数组为{@code null}
+ * @throws IllegalArgumentException {@code targetOffset}或{@code length} 为负数或{@code targetBuffer}太小
+ * @throws IllegalStateException buffer中的byte不足,使用{@link #getCurrentNumberOfBytes()}判断。
+ */
+ public void read(final byte[] targetBuffer, final int targetOffset, final int length) {
+ Objects.requireNonNull(targetBuffer);
+ if (targetOffset < 0 || targetOffset >= targetBuffer.length) {
+ throw new IllegalArgumentException("Invalid offset: " + targetOffset);
+ }
+ if (length < 0 || length > buffer.length) {
+ throw new IllegalArgumentException("Invalid length: " + length);
+ }
+ if (targetOffset + length > targetBuffer.length) {
+ throw new IllegalArgumentException("The supplied byte array contains only "
+ + targetBuffer.length + " bytes, but offset, and length would require "
+ + (targetOffset + length - 1));
+ }
+ if (currentNumberOfBytes < length) {
+ throw new IllegalStateException("Currently, there are only " + currentNumberOfBytes
+ + "in the buffer, not " + length);
+ }
+ int offset = targetOffset;
+ for (int i = 0; i < length; i++) {
+ targetBuffer[offset++] = buffer[startOffset];
+ --currentNumberOfBytes;
+ if (++startOffset == buffer.length) {
+ startOffset = 0;
+ }
+ }
+ }
+
+ /**
+ * 增加byte到buffer中
+ *
+ * @param value The byte
+ * @throws IllegalStateException buffer已满. 用{@link #hasSpace()}或{@link #getSpace()}判断。
+ */
+ public void add(final byte value) {
+ if (currentNumberOfBytes >= buffer.length) {
+ throw new IllegalStateException("No space available");
+ }
+ buffer[endOffset] = value;
+ ++currentNumberOfBytes;
+ if (++endOffset == buffer.length) {
+ endOffset = 0;
+ }
+ }
+
+ /**
+ * Returns, whether the next bytes in the buffer are exactly those, given by
+ * {@code sourceBuffer}, {@code offset}, and {@code length}. No bytes are being
+ * removed from the buffer. If the result is true, then the following invocations
+ * of {@link #read()} are guaranteed to return exactly those bytes.
+ *
+ * @param sourceBuffer the buffer to compare against
+ * @param offset start offset
+ * @param length length to compare
+ * @return True, if the next invocations of {@link #read()} will return the
+ * bytes at offsets {@code pOffset}+0, {@code pOffset}+1, ...,
+ * {@code pOffset}+{@code pLength}-1 of byte array {@code pBuffer}.
+ * @throws IllegalArgumentException Either of {@code pOffset}, or {@code pLength} is negative.
+ * @throws NullPointerException The byte array {@code pBuffer} is null.
+ */
+ public boolean peek(final byte[] sourceBuffer, final int offset, final int length) {
+ Objects.requireNonNull(sourceBuffer, "Buffer");
+ if (offset < 0 || offset >= sourceBuffer.length) {
+ throw new IllegalArgumentException("Invalid offset: " + offset);
+ }
+ if (length < 0 || length > buffer.length) {
+ throw new IllegalArgumentException("Invalid length: " + length);
+ }
+ if (length < currentNumberOfBytes) {
+ return false;
+ }
+ int localOffset = startOffset;
+ for (int i = 0; i < length; i++) {
+ if (buffer[localOffset] != sourceBuffer[i + offset]) {
+ return false;
+ }
+ if (++localOffset == buffer.length) {
+ localOffset = 0;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Adds the given bytes to the buffer. This is the same as invoking {@link #add(byte)}
+ * for the bytes at offsets {@code offset+0}, {@code offset+1}, ...,
+ * {@code offset+length-1} of byte array {@code targetBuffer}.
+ *
+ * @param targetBuffer the buffer to copy
+ * @param offset start offset
+ * @param length length to copy
+ * @throws IllegalStateException The buffer doesn't have sufficient space. Use
+ * {@link #getSpace()} to prevent this exception.
+ * @throws IllegalArgumentException Either of {@code pOffset}, or {@code pLength} is negative.
+ * @throws NullPointerException The byte array {@code pBuffer} is null.
+ */
+ public void add(final byte[] targetBuffer, final int offset, final int length) {
+ Objects.requireNonNull(targetBuffer, "Buffer");
+ if (offset < 0 || offset >= targetBuffer.length) {
+ throw new IllegalArgumentException("Invalid offset: " + offset);
+ }
+ if (length < 0) {
+ throw new IllegalArgumentException("Invalid length: " + length);
+ }
+ if (currentNumberOfBytes + length > buffer.length) {
+ throw new IllegalStateException("No space available");
+ }
+ for (int i = 0; i < length; i++) {
+ buffer[endOffset] = targetBuffer[offset + i];
+ if (++endOffset == buffer.length) {
+ endOffset = 0;
+ }
+ }
+ currentNumberOfBytes += length;
+ }
+
+ /**
+ * Returns, whether there is currently room for a single byte in the buffer.
+ * Same as {@link #hasSpace(int) hasSpace(1)}.
+ *
+ * @return true if there is space for a byte
+ * @see #hasSpace(int)
+ * @see #getSpace()
+ */
+ public boolean hasSpace() {
+ return currentNumberOfBytes < buffer.length;
+ }
+
+ /**
+ * Returns, whether there is currently room for the given number of bytes in the buffer.
+ *
+ * @param count the byte count
+ * @return true if there is space for the given number of bytes
+ * @see #hasSpace()
+ * @see #getSpace()
+ */
+ public boolean hasSpace(final int count) {
+ return currentNumberOfBytes + count <= buffer.length;
+ }
+
+ /**
+ * Returns, whether the buffer is currently holding, at least, a single byte.
+ *
+ * @return true if the buffer is not empty
+ */
+ public boolean hasBytes() {
+ return currentNumberOfBytes > 0;
+ }
+
+ /**
+ * Returns the number of bytes, that can currently be added to the buffer.
+ *
+ * @return the number of bytes that can be added
+ */
+ public int getSpace() {
+ return buffer.length - currentNumberOfBytes;
+ }
+
+ /**
+ * Returns the number of bytes, that are currently present in the buffer.
+ *
+ * @return the number of bytes
+ */
+ public int getCurrentNumberOfBytes() {
+ return currentNumberOfBytes;
+ }
+
+ /**
+ * Removes all bytes from the buffer.
+ */
+ public void clear() {
+ startOffset = 0;
+ endOffset = 0;
+ currentNumberOfBytes = 0;
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java
index a3ddb92e3..40a55393f 100755
--- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java
@@ -1,6 +1,6 @@
package cn.hutool.core.io;
-import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.compress.ZipUtil;
import cn.hutool.core.io.file.FileCopier;
import cn.hutool.core.io.file.FileMode;
import cn.hutool.core.io.file.FileNameUtil;
@@ -14,15 +14,15 @@ import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.func.SerConsumer;
+import cn.hutool.core.net.url.URLUtil;
+import cn.hutool.core.reflect.ClassUtil;
+import cn.hutool.core.regex.ReUtil;
+import cn.hutool.core.text.StrUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.reflect.ClassUtil;
-import cn.hutool.core.regex.ReUtil;
-import cn.hutool.core.text.StrUtil;
-import cn.hutool.core.net.url.URLUtil;
-import cn.hutool.core.compress.ZipUtil;
+import cn.hutool.core.util.SystemUtil;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -52,7 +52,6 @@ import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -410,16 +409,6 @@ public class FileUtil extends PathUtil {
return new File(URLUtil.toURI(url));
}
- /**
- * 获取临时文件路径(绝对路径)
- *
- * @return 临时文件路径
- * @since 4.0.6
- */
- public static String getTmpDirPath() {
- return System.getProperty("java.io.tmpdir");
- }
-
/**
* 获取临时文件目录
*
@@ -427,17 +416,7 @@ public class FileUtil extends PathUtil {
* @since 4.0.6
*/
public static File getTmpDir() {
- return file(getTmpDirPath());
- }
-
- /**
- * 获取用户路径(绝对路径)
- *
- * @return 用户路径
- * @since 4.0.6
- */
- public static String getUserHomePath() {
- return System.getProperty("user.home");
+ return file(SystemUtil.getTmpDirPath());
}
/**
@@ -447,7 +426,7 @@ public class FileUtil extends PathUtil {
* @since 4.0.6
*/
public static File getUserHomeDir() {
- return file(getUserHomePath());
+ return file(SystemUtil.getUserHomePath());
}
/**
@@ -1232,7 +1211,7 @@ public class FileUtil extends PathUtil {
if (path == null) {
normalPath = StrUtil.EMPTY;
} else {
- normalPath = normalize(path);
+ normalPath = FileNameUtil.normalize(path);
if (isAbsolutePath(normalPath)) {
// 给定的路径已经是绝对路径了
return normalPath;
@@ -1243,7 +1222,7 @@ public class FileUtil extends PathUtil {
final URL url = ResourceUtil.getResourceUrl(normalPath, baseClass);
if (null != url) {
// 对于jar中文件包含file:前缀,需要去掉此类前缀,在此做标准化,since 3.0.8 解决中文或空格路径被编码的问题
- return FileUtil.normalize(URLUtil.getDecodedPath(url));
+ return FileNameUtil.normalize(URLUtil.getDecodedPath(url));
}
// 如果资源不存在,则返回一个拼接的资源绝对路径
@@ -1255,7 +1234,7 @@ public class FileUtil extends PathUtil {
}
// 资源不存在的情况下使用标准化路径有问题,使用原始路径拼接后标准化路径
- return normalize(classPath.concat(Objects.requireNonNull(path)));
+ return FileNameUtil.normalize(classPath.concat(Objects.requireNonNull(path)));
}
/**
@@ -1290,7 +1269,7 @@ public class FileUtil extends PathUtil {
/**
* 给定路径已经是绝对路径
- * 此方法并没有针对路径做标准化,建议先执行{@link #normalize(String)}方法标准化路径后判断
+ * 此方法并没有针对路径做标准化,建议先执行{@link FileNameUtil#normalize(String)}方法标准化路径后判断
* 绝对路径判断条件是:
*
* - 以/开头的路径
@@ -1573,84 +1552,7 @@ public class FileUtil extends PathUtil {
* @return 修复后的路径
*/
public static String normalize(final String path) {
- if (path == null) {
- return null;
- }
-
- // 兼容Spring风格的ClassPath路径,去除前缀,不区分大小写
- String pathToUse = StrUtil.removePrefixIgnoreCase(path, URLUtil.CLASSPATH_URL_PREFIX);
- // 去除file:前缀
- pathToUse = StrUtil.removePrefixIgnoreCase(pathToUse, URLUtil.FILE_URL_PREFIX);
-
- // 识别home目录形式,并转换为绝对路径
- if (StrUtil.startWith(pathToUse, '~')) {
- pathToUse = getUserHomePath() + pathToUse.substring(1);
- }
-
- // 统一使用斜杠
- pathToUse = pathToUse.replaceAll("[/\\\\]+", StrUtil.SLASH);
- // 去除开头空白符,末尾空白符合法,不去除
- pathToUse = StrUtil.trimStart(pathToUse);
- //兼容Windows下的共享目录路径(原始路径如果以\\开头,则保留这种路径)
- if (path.startsWith("\\\\")) {
- pathToUse = "\\" + pathToUse;
- }
-
- String prefix = StrUtil.EMPTY;
- final int prefixIndex = pathToUse.indexOf(StrUtil.COLON);
- if (prefixIndex > -1) {
- // 可能Windows风格路径
- prefix = pathToUse.substring(0, prefixIndex + 1);
- if (StrUtil.startWith(prefix, CharUtil.SLASH)) {
- // 去除类似于/C:这类路径开头的斜杠
- prefix = prefix.substring(1);
- }
- if (false == prefix.contains(StrUtil.SLASH)) {
- pathToUse = pathToUse.substring(prefixIndex + 1);
- } else {
- // 如果前缀中包含/,说明非Windows风格path
- prefix = StrUtil.EMPTY;
- }
- }
- if (pathToUse.startsWith(StrUtil.SLASH)) {
- prefix += StrUtil.SLASH;
- pathToUse = pathToUse.substring(1);
- }
-
- final List pathList = StrUtil.split(pathToUse, CharUtil.SLASH);
-
- final List pathElements = new LinkedList<>();
- int tops = 0;
- String element;
- for (int i = pathList.size() - 1; i >= 0; i--) {
- element = pathList.get(i);
- // 只处理非.的目录,即只处理非当前目录
- if (false == StrUtil.DOT.equals(element)) {
- if (StrUtil.DOUBLE_DOT.equals(element)) {
- tops++;
- } else {
- if (tops > 0) {
- // 有上级目录标记时按照个数依次跳过
- tops--;
- } else {
- // Normal path element found.
- pathElements.add(0, element);
- }
- }
- }
- }
-
- // issue#1703@Github
- if (tops > 0 && StrUtil.isEmpty(prefix)) {
- // 只有相对路径补充开头的..,绝对路径直接忽略之
- while (tops-- > 0) {
- //遍历完节点发现还有上级标注(即开头有一个或多个..),补充之
- // Normal path element found.
- pathElements.add(0, StrUtil.DOUBLE_DOT);
- }
- }
-
- return prefix + CollUtil.join(pathElements, StrUtil.SLASH);
+ return FileNameUtil.normalize(path);
}
/**
@@ -1693,8 +1595,8 @@ public class FileUtil extends PathUtil {
public static String subPath(String dirPath, String filePath) {
if (StrUtil.isNotEmpty(dirPath) && StrUtil.isNotEmpty(filePath)) {
- dirPath = StrUtil.removeSuffix(normalize(dirPath), "/");
- filePath = normalize(filePath);
+ dirPath = StrUtil.removeSuffix(FileNameUtil.normalize(dirPath), "/");
+ filePath = FileNameUtil.normalize(filePath);
final String result = StrUtil.removePrefixIgnoreCase(filePath, dirPath);
return StrUtil.removePrefix(result, "/");
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java
index cda225068..ac23975a7 100755
--- a/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java
@@ -738,6 +738,19 @@ public class IoUtil extends NioUtil {
return new ByteArrayInputStream(out.toByteArray());
}
+ /**
+ * {@link FastByteArrayOutputStream}转为{@link ByteArrayInputStream}
+ *
+ * @param out {@link FastByteArrayOutputStream}
+ * @return 字节流
+ */
+ public static ByteArrayInputStream toStream(final FastByteArrayOutputStream out) {
+ if (out == null) {
+ return null;
+ }
+ return new ByteArrayInputStream(out.toByteArray());
+ }
+
/**
* 转换为{@link BufferedInputStream}
*
diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/FileNameUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/file/FileNameUtil.java
index c2b6c818e..e8ac70863 100755
--- a/hutool-core/src/main/java/cn/hutool/core/io/file/FileNameUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/io/file/FileNameUtil.java
@@ -1,10 +1,15 @@
package cn.hutool.core.io.file;
-import cn.hutool.core.util.CharUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.net.url.URLUtil;
import cn.hutool.core.regex.ReUtil;
import cn.hutool.core.text.StrUtil;
+import cn.hutool.core.util.CharUtil;
+import cn.hutool.core.util.SystemUtil;
import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
import java.util.regex.Pattern;
/**
@@ -286,5 +291,119 @@ public class FileNameUtil {
public static boolean isType(final String fileName, final String... extNames) {
return StrUtil.equalsAnyIgnoreCase(extName(fileName), extNames);
}
+
+ /**
+ * 修复路径
+ * 如果原路径尾部有分隔符,则保留为标准分隔符(/),否则不保留
+ *
+ * - 1. 统一用 /
+ * - 2. 多个 / 转换为一个 /
+ * - 3. 去除左边空格
+ * - 4. .. 和 . 转换为绝对路径,当..多于已有路径时,直接返回根路径
+ *
+ *
+ * 栗子:
+ *
+ *
+ * "/foo//" =》 "/foo/"
+ * "/foo/./" =》 "/foo/"
+ * "/foo/../bar" =》 "/bar"
+ * "/foo/../bar/" =》 "/bar/"
+ * "/foo/../bar/../baz" =》 "/baz"
+ * "/../" =》 "/"
+ * "foo/bar/.." =》 "foo"
+ * "foo/../bar" =》 "bar"
+ * "foo/../../bar" =》 "bar"
+ * "//server/foo/../bar" =》 "/server/bar"
+ * "//server/../bar" =》 "/bar"
+ * "C:\\foo\\..\\bar" =》 "C:/bar"
+ * "C:\\..\\bar" =》 "C:/bar"
+ * "~/foo/../bar/" =》 "~/bar/"
+ * "~/../bar" =》 普通用户运行是'bar的home目录',ROOT用户运行是'/bar'
+ *
+ *
+ * @param path 原路径
+ * @return 修复后的路径
+ */
+ public static String normalize(final String path) {
+ if (path == null) {
+ return null;
+ }
+
+ // 兼容Spring风格的ClassPath路径,去除前缀,不区分大小写
+ String pathToUse = StrUtil.removePrefixIgnoreCase(path, URLUtil.CLASSPATH_URL_PREFIX);
+ // 去除file:前缀
+ pathToUse = StrUtil.removePrefixIgnoreCase(pathToUse, URLUtil.FILE_URL_PREFIX);
+
+ // 识别home目录形式,并转换为绝对路径
+ if (StrUtil.startWith(pathToUse, '~')) {
+ pathToUse = SystemUtil.getUserHomePath() + pathToUse.substring(1);
+ }
+
+ // 统一使用斜杠
+ pathToUse = pathToUse.replaceAll("[/\\\\]+", StrUtil.SLASH);
+ // 去除开头空白符,末尾空白符合法,不去除
+ pathToUse = StrUtil.trimStart(pathToUse);
+ //兼容Windows下的共享目录路径(原始路径如果以\\开头,则保留这种路径)
+ if (path.startsWith("\\\\")) {
+ pathToUse = "\\" + pathToUse;
+ }
+
+ String prefix = StrUtil.EMPTY;
+ final int prefixIndex = pathToUse.indexOf(StrUtil.COLON);
+ if (prefixIndex > -1) {
+ // 可能Windows风格路径
+ prefix = pathToUse.substring(0, prefixIndex + 1);
+ if (StrUtil.startWith(prefix, CharUtil.SLASH)) {
+ // 去除类似于/C:这类路径开头的斜杠
+ prefix = prefix.substring(1);
+ }
+ if (false == prefix.contains(StrUtil.SLASH)) {
+ pathToUse = pathToUse.substring(prefixIndex + 1);
+ } else {
+ // 如果前缀中包含/,说明非Windows风格path
+ prefix = StrUtil.EMPTY;
+ }
+ }
+ if (pathToUse.startsWith(StrUtil.SLASH)) {
+ prefix += StrUtil.SLASH;
+ pathToUse = pathToUse.substring(1);
+ }
+
+ final List pathList = StrUtil.split(pathToUse, CharUtil.SLASH);
+
+ final List pathElements = new LinkedList<>();
+ int tops = 0;
+ String element;
+ for (int i = pathList.size() - 1; i >= 0; i--) {
+ element = pathList.get(i);
+ // 只处理非.的目录,即只处理非当前目录
+ if (false == StrUtil.DOT.equals(element)) {
+ if (StrUtil.DOUBLE_DOT.equals(element)) {
+ tops++;
+ } else {
+ if (tops > 0) {
+ // 有上级目录标记时按照个数依次跳过
+ tops--;
+ } else {
+ // Normal path element found.
+ pathElements.add(0, element);
+ }
+ }
+ }
+ }
+
+ // issue#1703@Github
+ if (tops > 0 && StrUtil.isEmpty(prefix)) {
+ // 只有相对路径补充开头的..,绝对路径直接忽略之
+ while (tops-- > 0) {
+ //遍历完节点发现还有上级标注(即开头有一个或多个..),补充之
+ // Normal path element found.
+ pathElements.add(0, StrUtil.DOUBLE_DOT);
+ }
+ }
+
+ return prefix + CollUtil.join(pathElements, StrUtil.SLASH);
+ }
// -------------------------------------------------------------------------------------------- name end
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/SystemUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/SystemUtil.java
index 44d54d085..32fd05e3f 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/SystemUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/SystemUtil.java
@@ -147,4 +147,23 @@ public class SystemUtil {
public static String[] getJavaClassPaths() {
return get("java.class.path").split(get("path.separator"));
}
+
+ /**
+ * 获取用户路径(绝对路径)
+ *
+ * @return 用户路径
+ */
+ public static String getUserHomePath() {
+ return get("user.home");
+ }
+
+ /**
+ * 获取临时文件路径(绝对路径)
+ *
+ * @return 临时文件路径
+ * @since 4.0.6
+ */
+ public static String getTmpDirPath() {
+ return get("java.io.tmpdir");
+ }
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java
index dec7bc063..d0db01e8c 100644
--- a/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/io/FileUtilTest.java
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.file.LineSeparator;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.SystemUtil;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
@@ -141,42 +142,15 @@ public class FileUtilTest {
FileUtil.convertLineSeparator(FileUtil.file("d:/aaa.txt"), CharsetUtil.UTF_8, LineSeparator.WINDOWS);
}
- @Test
- public void normalizeTest() {
- Assert.assertEquals("/foo/", FileUtil.normalize("/foo//"));
- Assert.assertEquals("/foo/", FileUtil.normalize("/foo/./"));
- Assert.assertEquals("/bar", FileUtil.normalize("/foo/../bar"));
- Assert.assertEquals("/bar/", FileUtil.normalize("/foo/../bar/"));
- Assert.assertEquals("/baz", FileUtil.normalize("/foo/../bar/../baz"));
- Assert.assertEquals("/", FileUtil.normalize("/../"));
- Assert.assertEquals("foo", FileUtil.normalize("foo/bar/.."));
- Assert.assertEquals("../bar", FileUtil.normalize("foo/../../bar"));
- Assert.assertEquals("bar", FileUtil.normalize("foo/../bar"));
- Assert.assertEquals("/server/bar", FileUtil.normalize("//server/foo/../bar"));
- Assert.assertEquals("/bar", FileUtil.normalize("//server/../bar"));
- Assert.assertEquals("C:/bar", FileUtil.normalize("C:\\foo\\..\\bar"));
- //
- Assert.assertEquals("C:/bar", FileUtil.normalize("C:\\..\\bar"));
- Assert.assertEquals("../../bar", FileUtil.normalize("../../bar"));
- Assert.assertEquals("C:/bar", FileUtil.normalize("/C:/bar"));
- Assert.assertEquals("C:", FileUtil.normalize("C:"));
- Assert.assertEquals("\\/192.168.1.1/Share/", FileUtil.normalize("\\\\192.168.1.1\\Share\\"));
- }
-
- @Test
- public void normalizeBlankTest() {
- Assert.assertEquals("C:/aaa ", FileUtil.normalize("C:\\aaa "));
- }
-
@Test
public void normalizeHomePathTest() {
- final String home = FileUtil.getUserHomePath().replace('\\', '/');
+ final String home = SystemUtil.getUserHomePath().replace('\\', '/');
Assert.assertEquals(home + "/bar/", FileUtil.normalize("~/foo/../bar/"));
}
@Test
public void normalizeHomePathTest2() {
- final String home = FileUtil.getUserHomePath().replace('\\', '/');
+ final String home = SystemUtil.getUserHomePath().replace('\\', '/');
// 多个~应该只替换开头的
Assert.assertEquals(home + "/~bar/", FileUtil.normalize("~/foo/../~bar/"));
}
diff --git a/hutool-core/src/test/java/cn/hutool/core/io/file/FileNameUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/file/FileNameUtilTest.java
index 344ba754f..be66ac71a 100755
--- a/hutool-core/src/test/java/cn/hutool/core/io/file/FileNameUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/io/file/FileNameUtilTest.java
@@ -18,4 +18,31 @@ public class FileNameUtilTest {
final String s = FileNameUtil.mainName("abc.tar.gz");
Assert.assertEquals("abc", s);
}
+
+ @Test
+ public void normalizeTest() {
+ Assert.assertEquals("/foo/", FileNameUtil.normalize("/foo//"));
+ Assert.assertEquals("/foo/", FileNameUtil.normalize("/foo/./"));
+ Assert.assertEquals("/bar", FileNameUtil.normalize("/foo/../bar"));
+ Assert.assertEquals("/bar/", FileNameUtil.normalize("/foo/../bar/"));
+ Assert.assertEquals("/baz", FileNameUtil.normalize("/foo/../bar/../baz"));
+ Assert.assertEquals("/", FileNameUtil.normalize("/../"));
+ Assert.assertEquals("foo", FileNameUtil.normalize("foo/bar/.."));
+ Assert.assertEquals("../bar", FileNameUtil.normalize("foo/../../bar"));
+ Assert.assertEquals("bar", FileNameUtil.normalize("foo/../bar"));
+ Assert.assertEquals("/server/bar", FileNameUtil.normalize("//server/foo/../bar"));
+ Assert.assertEquals("/bar", FileNameUtil.normalize("//server/../bar"));
+ Assert.assertEquals("C:/bar", FileNameUtil.normalize("C:\\foo\\..\\bar"));
+ //
+ Assert.assertEquals("C:/bar", FileNameUtil.normalize("C:\\..\\bar"));
+ Assert.assertEquals("../../bar", FileNameUtil.normalize("../../bar"));
+ Assert.assertEquals("C:/bar", FileNameUtil.normalize("/C:/bar"));
+ Assert.assertEquals("C:", FileNameUtil.normalize("C:"));
+ Assert.assertEquals("\\/192.168.1.1/Share/", FileNameUtil.normalize("\\\\192.168.1.1\\Share\\"));
+ }
+
+ @Test
+ public void normalizeBlankTest() {
+ Assert.assertEquals("C:/aaa ", FileNameUtil.normalize("C:\\aaa "));
+ }
}
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/body/RequestBody.java b/hutool-http/src/main/java/cn/hutool/http/client/body/RequestBody.java
index ae875d68e..94646e1db 100644
--- a/hutool-http/src/main/java/cn/hutool/http/client/body/RequestBody.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/body/RequestBody.java
@@ -1,7 +1,9 @@
package cn.hutool.http.client.body;
+import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.IoUtil;
+import java.io.InputStream;
import java.io.OutputStream;
/**
@@ -29,4 +31,15 @@ public interface RequestBody {
IoUtil.close(out);
}
}
+
+ /**
+ * 获取body资源流
+ *
+ * @return {@link InputStream}
+ */
+ default InputStream getStream() {
+ final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
+ writeClose(out);
+ return IoUtil.toStream(out);
+ }
}
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/body/ResourceBody.java b/hutool-http/src/main/java/cn/hutool/http/client/body/ResourceBody.java
index 4c3c6ee55..fe98d28d9 100755
--- a/hutool-http/src/main/java/cn/hutool/http/client/body/ResourceBody.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/body/ResourceBody.java
@@ -2,6 +2,7 @@ package cn.hutool.http.client.body;
import cn.hutool.core.io.resource.Resource;
+import java.io.InputStream;
import java.io.OutputStream;
/**
@@ -46,4 +47,9 @@ public class ResourceBody implements RequestBody {
public void write(final OutputStream out) {
resource.writeTo(out);
}
+
+ @Override
+ public InputStream getStream() {
+ return resource.getStream();
+ }
}
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/RequestBodyEntity.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4BodyEntity.java
similarity index 66%
rename from hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/RequestBodyEntity.java
rename to hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4BodyEntity.java
index 8cb2810ad..a2906ffc1 100755
--- a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/RequestBodyEntity.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4BodyEntity.java
@@ -1,12 +1,9 @@
package cn.hutool.http.client.engine.httpclient4;
-import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.http.client.body.BytesBody;
import cn.hutool.http.client.body.RequestBody;
-import cn.hutool.http.client.body.ResourceBody;
import org.apache.http.entity.AbstractHttpEntity;
-import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
@@ -17,7 +14,7 @@ import java.nio.charset.Charset;
* @author looly
* @since 6.0.0
*/
-public class RequestBodyEntity extends AbstractHttpEntity {
+public class HttpClient4BodyEntity extends AbstractHttpEntity {
private final RequestBody body;
@@ -29,7 +26,7 @@ public class RequestBodyEntity extends AbstractHttpEntity {
* @param chunked 是否块模式传输
* @param body {@link RequestBody}
*/
- public RequestBodyEntity(final String contentType, final Charset charset, final boolean chunked, final RequestBody body) {
+ public HttpClient4BodyEntity(final String contentType, final Charset charset, final boolean chunked, final RequestBody body) {
super();
setContentType(contentType);
setContentEncoding(null == charset ? null : charset.name());
@@ -46,13 +43,7 @@ public class RequestBodyEntity extends AbstractHttpEntity {
@Override
public InputStream getContent() {
- if (body instanceof ResourceBody) {
- return ((ResourceBody) body).getResource().getStream();
- } else {
- final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
- body.writeClose(out);
- return new ByteArrayInputStream(out.toByteArray());
- }
+ return body.getStream();
}
@Override
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Engine.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Engine.java
index e9f19dfeb..751337244 100755
--- a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Engine.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient4/HttpClient4Engine.java
@@ -88,7 +88,7 @@ public class HttpClient4Engine implements ClientEngine {
// 填充自定义消息体
final RequestBody body = message.body();
- request.setEntity(new RequestBodyEntity(
+ request.setEntity(new HttpClient4BodyEntity(
// 用户自定义的内容类型
message.header(cn.hutool.http.meta.Header.CONTENT_TYPE),
// 用户自定义编码
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/RequestBodyEntity.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5BodyEntity.java
similarity index 66%
rename from hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/RequestBodyEntity.java
rename to hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5BodyEntity.java
index 158bd16f9..bd8af189d 100755
--- a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/RequestBodyEntity.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5BodyEntity.java
@@ -1,12 +1,9 @@
package cn.hutool.http.client.engine.httpclient5;
-import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.http.client.body.BytesBody;
import cn.hutool.http.client.body.RequestBody;
-import cn.hutool.http.client.body.ResourceBody;
import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -18,7 +15,7 @@ import java.nio.charset.Charset;
* @author looly
* @since 6.0.0
*/
-public class RequestBodyEntity extends AbstractHttpEntity {
+public class HttpClient5BodyEntity extends AbstractHttpEntity {
private final RequestBody body;
@@ -30,7 +27,7 @@ public class RequestBodyEntity extends AbstractHttpEntity {
* @param chunked 是否块模式传输
* @param body {@link RequestBody}
*/
- public RequestBodyEntity(final String contentType, final Charset charset, final boolean chunked, final RequestBody body) {
+ public HttpClient5BodyEntity(final String contentType, final Charset charset, final boolean chunked, final RequestBody body) {
super(contentType, null == charset ? null : charset.name(), chunked);
this.body = body;
}
@@ -44,13 +41,7 @@ public class RequestBodyEntity extends AbstractHttpEntity {
@Override
public InputStream getContent() {
- if (body instanceof ResourceBody) {
- return ((ResourceBody) body).getResource().getStream();
- } else {
- final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
- body.writeClose(out);
- return new ByteArrayInputStream(out.toByteArray());
- }
+ return body.getStream();
}
@Override
diff --git a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Engine.java b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Engine.java
index 620f0ba6e..4a33b164d 100755
--- a/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Engine.java
+++ b/hutool-http/src/main/java/cn/hutool/http/client/engine/httpclient5/HttpClient5Engine.java
@@ -84,7 +84,7 @@ public class HttpClient5Engine implements ClientEngine {
// 填充自定义消息体
final RequestBody body = message.body();
- request.setEntity(new RequestBodyEntity(
+ request.setEntity(new HttpClient5BodyEntity(
// 用户自定义的内容类型
message.header(cn.hutool.http.meta.Header.CONTENT_TYPE),
// 用户自定义编码