如何编写检查文件名非法字符

wen 实用脚本 2

本文目录导读:

如何编写检查文件名非法字符

  1. Python
  2. Java
  3. JavaScript/Node.js
  4. C
  5. 通用检查规则
  6. 关键要点

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

关键要点

  1. 非法字符< > : " / \ | ? * 和控制字符
  2. 保留名称:Windows的CON、PRN等
  3. 长度限制:一般255个字符
  4. 结尾限制:不能以空格或点结尾
  5. 跨平台考虑:不同操作系统规则不同

建议在用户输入时实时检查,并给予明确的错误提示。

抱歉,评论功能暂时关闭!