在Java中上传文件时,如果文件名中含有非法字符,可能会带来一系列的危害和潜在问题。
-
编译错误:
- Java文件名称中的非法字符,如斜杠(/)、反斜杠(\)、冒号(:)、星号(*)、问号(?)、双引号(")、尖括号(<>)、竖线(|)等,会导致编译错误。这些字符在Java文件系统中具有特殊含义,因此不能用于文件名中。
-
上传失败:
- 当文件名包含URI中的特殊字符,如井号(#)时,可能会导致上传失败。因为Uri类会对文件路径#号后面的内容进行拆分存放,从而导致文件名被截断或更改。
-
安全威胁:
- 文件名中的非法字符可能包含一些危险的字符,如“../”或“..\”,这些字符在文件系统中具有特殊的意义,可能导致文件被保存到预期之外的路径下,从而带来安全风险。
- 如果文件名中包含非法字符,且系统处理不正确,可能导致系统内部信息泄露。例如,在Windows系统中,如果文件名含有非法字符,可能会出错,如果处理不当就会导致信息泄露。
-
文件名解析错误:
- 文件名中的空格或其他特殊字符可能导致文件名解析错误,使得文件无法被正确识别和访问。
-
长度限制:
- 文件名加路径的长度可能受到操作系统的限制。在Windows系统中,文件名的最大长度(包括路径)通常为260个字符(Windows 10, 11的NTFS文件系统支持长达32,767个字符的路径,但实际应用中仍建议遵守较短的限制)。如果文件名或路径长度超过这个限制,可能会导致问题。
-
跨平台兼容性问题:
- 不同的操作系统和文件系统对文件名的限制和要求可能不同。因此,如果文件名包含非法字符,可能会导致文件在跨平台传输或访问时出现问题。
解决方法:
下面是我一个简单的例子:
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FileNameUtil {
private static final Pattern INVALID_FILENAME_CHARS = Pattern.compile("[\\\\/:*?\"<>|]");
private static final int MAX_LENGTH = 255; // 根据文件系统或应用需求设置最大长度
private static final String REPLACEMENT_CHAR = "_";
private static final String DEFAULT_FILENAME = default_filename;//如果文件名为空就将文件名设置为该字段
/**
* 清理文件名,去除可能导致问题的字符,并确保文件名长度在限制范围内
*
* @param originalFilename 原始文件名
* @return 清理后的文件名
*/
public static String cleanFileName(String originalFilename) {
if (originalFilename == null) {
return DEFAULT_FILENAME;
}
// 去除路径遍历字符,替换为下划线
String sanitizedFilename = originalFilename.replaceAll("\\.\\./", REPLACEMENT_CHAR);
// 使用正则表达式去除无效的文件名字符
Matcher matcher = INVALID_FILENAME_CHARS.matcher(sanitizedFilename);
sanitizedFilename = matcher.replaceAll(REPLACEMENT_CHAR);
// 去除文件名开头和结尾的无效字符(如点号)
sanitizedFilename = sanitizedFilename.trim().replaceAll("^\\.*|\\.*$", "");
// 截取文件名并尝试保留扩展名
String extension = "";
int dotIndex = sanitizedFilename.lastIndexOf('.');
if (dotIndex > 0 && dotIndex < sanitizedFilename.length() - 1) { // 确保扩展名至少有一个字符
extension = sanitizedFilename.substring(dotIndex);
sanitizedFilename = sanitizedFilename.substring(0, dotIndex);
// 如果文件名(不含扩展名)和扩展名的总长度超过限制,则截断文件名
if (sanitizedFilename.length() + extension.length() > MAX_LENGTH) {
sanitizedFilename = sanitizedFilename.substring(0, MAX_LENGTH - extension.length() - 1);
// 减去1是为了在文件名和扩展名之间添加一个分隔符
sanitizedFilename = sanitizedFilename.trim(); // 去除可能的尾随空格
// 确保至少保留一个字符作为文件名
if (sanitizedFilename.isEmpty()) {
sanitizedFilename = REPLACEMENT_CHAR;
}
}
}
// 如果文件名长度仍然超过限制(不含扩展名),则直接截断
if (sanitizedFilename.length() > MAX_LENGTH - extension.length()) {
sanitizedFilename = sanitizedFilename.substring(0, MAX_LENGTH - extension.length() - 1);
sanitizedFilename = sanitizedFilename.trim(); // 去除可能的尾随空格
// 确保至少保留一个字符作为文件名
if (sanitizedFilename.isEmpty()) {
sanitizedFilename = REPLACEMENT_CHAR;
}
}
// 添加回扩展名,并确保文件名和扩展名之间有一个点号
if (!extension.isEmpty()) {
sanitizedFilename += ".";
}
sanitizedFilename += extension;
// 确保文件名不为空
if (sanitizedFilename.isEmpty()) {
sanitizedFilename = DEFAULT_FILENAME;
}
return sanitizedFilename;
}
}
这是我的解决方法,简单的处理了一下文件名