本文目录导读:

Python
import os
import re
# Windows 非法字符
WINDOWS_ILLEGAL_CHARS = r'[<>:"/\\|?*\x00-\x1f]'
def check_filename_illegal_chars(filename):
"""检查文件名是否包含非法字符"""
illegal_chars = '<>:"/\\|?*'
for char in filename:
if char in illegal_chars:
return True, f"发现非法字符: '{char}'"
# 检查控制字符
for char in filename:
if ord(char) < 32:
return True, f"发现控制字符: '{char}'"
return False, "文件名合法"
# 使用正则表达式
def check_filename_regex(filename):
pattern = r'[<>:"/\\|?*\x00-\x1f]'
match = re.search(pattern, filename)
if match:
return True, f"发现非法字符: '{match.group()}'"
return False, "文件名合法"
# 综合检查
def validate_filename(filename):
# 检查是否为空
if not filename:
return False, "文件名不能为空"
# 检查长度
if len(filename) > 255:
return False, "文件名过长"
# 检查保留名称 (Windows)
reserved_names = ['CON', 'PRN', 'AUX', 'NUL',
'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9']
name_without_ext = Path(filename).stem.upper()
if name_without_ext in reserved_names:
return False, f"'{filename}' 是Windows保留名称"
has_illegal, msg = check_filename_illegal_chars(filename)
return not has_illegal, msg
Java
import java.io.File;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
public class FilenameValidator {
// Windows 非法字符
private static final char[] ILLEGAL_CHARS = {'<', '>', ':', '"', '/', '\\', '|', '?', '*'};
private static final String[] RESERVED_NAMES = {
"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
};
public static boolean validateFilename(String filename) {
if (filename == null || filename.isEmpty()) {
System.out.println("文件名不能为空");
return false;
}
// 检查非法字符
for (char c : filename.toCharArray()) {
for (char illegal : ILLEGAL_CHARS) {
if (c == illegal) {
System.out.println("发现非法字符: '" + c + "'");
return false;
}
}
// 检查控制字符
if (Character.isISOControl(c)) {
System.out.println("发现控制字符");
return false;
}
}
// 检查长度
if (filename.length() > 255) {
System.out.println("文件名过长");
return false;
}
// 检查保留名称
String nameWithoutExt = getFileNameWithoutExtension(filename).toUpperCase();
for (String reserved : RESERVED_NAMES) {
if (nameWithoutExt.equals(reserved)) {
System.out.println("Windows保留名称");
return false;
}
}
// 使用Java的路径验证
try {
Paths.get(filename);
} catch (InvalidPathException e) {
System.out.println("无效路径: " + e.getMessage());
return false;
}
return true;
}
private static String getFileNameWithoutExtension(String filename) {
int dotIndex = filename.lastIndexOf('.');
return dotIndex > 0 ? filename.substring(0, dotIndex) : filename;
}
}
JavaScript/Node.js
// 浏览器/Node环境通用
function checkIllegalChars(filename) {
// Windows非法字符
const illegalChars = /[<>:"/\\|?*\x00-\x1f]/;
if (illegalChars.test(filename)) {
const match = filename.match(illegalChars);
return {
valid: false,
message: `发现非法字符: '${match[0]}'`
};
}
return { valid: true, message: "文件名合法" };
}
// Node.js 更全面的检查
function validateFilenameNode(filename) {
if (!filename) {
return { valid: false, message: "文件名不能为空" };
}
// 检查非法字符
const result = checkIllegalChars(filename);
if (!result.valid) return result;
// 检查长度
if (filename.length > 255) {
return { valid: false, message: "文件名过长" };
}
// 检查保留名称
const reservedNames = [
'CON', 'PRN', 'AUX', 'NUL',
'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'
];
const nameWithoutExt = filename.split('.')[0].toUpperCase();
if (reservedNames.includes(nameWithoutExt)) {
return { valid: false, message: `'${filename}' 是Windows保留名称` };
}
return { valid: true, message: "文件名合法" };
}
// 实时检测的示例
function realtimeCheck(inputElement) {
inputElement.addEventListener('input', function() {
const result = checkIllegalChars(this.value);
if (!result.valid) {
this.classList.add('error');
document.getElementById('errorMsg').textContent = result.message;
} else {
this.classList.remove('error');
document.getElementById('errorMsg').textContent = '';
}
});
}
C
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
public class FilenameValidator
{
private static readonly char[] InvalidChars = Path.GetInvalidFileNameChars();
private static readonly string[] ReservedNames =
{
"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
};
public static (bool IsValid, string Message) ValidateFilename(string filename)
{
if (string.IsNullOrEmpty(filename))
return (false, "文件名不能为空");
// 使用 .NET 自带方法
if (filename.IndexOfAny(InvalidChars) >= 0)
{
var invalidChar = filename.First(c => InvalidChars.Contains(c));
return (false, $"发现非法字符: '{invalidChar}'");
}
// 检查长度
if (filename.Length > 255)
return (false, "文件名过长");
// 检查保留名称
string nameWithoutExt = Path.GetFileNameWithoutExtension(filename).ToUpper();
if (ReservedNames.Contains(nameWithoutExt))
return (false, $"'{filename}' 是Windows保留名称");
return (true, "文件名合法");
}
}
通用检查规则
# 提供一个通用检查函数
def universal_filename_check(filename, os_type='windows'):
"""跨平台文件名检查"""
checks = []
# 基础检查
if not filename:
checks.append(("错误", "文件名不能为空"))
if len(filename) > 255:
checks.append(("错误", "文件名过长"))
# 根据操作系统设置非法字符
if os_type == 'windows':
illegal_chars = '<>:"/\\|?*'
elif os_type == 'unix':
illegal_chars = '/' # Unix/Linux只禁止/
else:
illegal_chars = '/' # macOS也是/
# 检查非法字符
for char in filename:
if char in illegal_chars or ord(char) < 32:
checks.append(("错误", f"非法字符: '{char}'"))
# 检查结束点和空格问题
if filename.endswith('.') or filename.endswith(' '):
checks.append(("警告", "文件名不应以点或空格结尾"))
# 检查保留名称
if os_type == 'windows':
reserved = ['CON', 'PRN', 'AUX', 'NUL', 'COM1-9', 'LPT1-9']
name_part = filename.split('.')[0].upper()
if name_part in reserved:
checks.append(("错误", "Windows保留名称"))
return checks
关键要点
- 非法字符:
< > : " / \ | ? *和控制字符 - 保留名称:Windows的CON、PRN等
- 长度限制:一般255个字符
- 结尾限制:不能以空格或点结尾
- 跨平台考虑:不同操作系统规则不同
建议在用户输入时实时检查,并给予明确的错误提示。