mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix code
This commit is contained in:
239
hutool-core/src/main/java/cn/hutool/core/io/CircularByteBuffer.java
Executable file
239
hutool-core/src/main/java/cn/hutool/core/io/CircularByteBuffer.java
Executable file
@@ -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;
|
||||
}
|
||||
}
|
@@ -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 {
|
||||
|
||||
/**
|
||||
* 给定路径已经是绝对路径<br>
|
||||
* 此方法并没有针对路径做标准化,建议先执行{@link #normalize(String)}方法标准化路径后判断<br>
|
||||
* 此方法并没有针对路径做标准化,建议先执行{@link FileNameUtil#normalize(String)}方法标准化路径后判断<br>
|
||||
* 绝对路径判断条件是:
|
||||
* <ul>
|
||||
* <li>以/开头的路径</li>
|
||||
@@ -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<String> pathList = StrUtil.split(pathToUse, CharUtil.SLASH);
|
||||
|
||||
final List<String> 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, "/");
|
||||
|
@@ -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}
|
||||
*
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修复路径<br>
|
||||
* 如果原路径尾部有分隔符,则保留为标准分隔符(/),否则不保留
|
||||
* <ol>
|
||||
* <li>1. 统一用 /</li>
|
||||
* <li>2. 多个 / 转换为一个 /</li>
|
||||
* <li>3. 去除左边空格</li>
|
||||
* <li>4. .. 和 . 转换为绝对路径,当..多于已有路径时,直接返回根路径</li>
|
||||
* </ol>
|
||||
* <p>
|
||||
* 栗子:
|
||||
*
|
||||
* <pre>
|
||||
* "/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'
|
||||
* </pre>
|
||||
*
|
||||
* @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<String> pathList = StrUtil.split(pathToUse, CharUtil.SLASH);
|
||||
|
||||
final List<String> 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
|
||||
}
|
||||
|
@@ -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");
|
||||
}
|
||||
}
|
||||
|
@@ -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/"));
|
||||
}
|
||||
|
@@ -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 "));
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
@@ -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),
|
||||
// 用户自定义编码
|
||||
|
@@ -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
|
@@ -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),
|
||||
// 用户自定义编码
|
||||
|
Reference in New Issue
Block a user