【问题标题】:Check whether a string is a valid filename with Qt使用 Qt 检查字符串是否是有效的文件名
【发布时间】:2010-06-14 15:11:34
【问题描述】:

Qt 4.6 有没有办法检查给定的QString 是否是当前操作系统上的有效文件名(或目录名)?我想检查名称是否有效,文件是否存在。

例子:

// Some valid names
test
under_score
.dotted-name

// Some specific names
colon:name // valid under UNIX OSes, but not on Windows
what? // valid under UNIX OSes, but still not on Windows

我将如何实现这一目标?有没有Qt 内置函数?

我想避免创建一个空文件,但是如果没有其他可靠的方法,我仍然想看看如何以“干净”的方式来做。

非常感谢。

【问题讨论】:

    标签: c++ validation qt filesystems


    【解决方案1】:

    这是我从 Silje Johansen - Support Engineer - Trolltech ASA 那里得到的答案(不过是在 2008 年 3 月)

    但是。包括区域设置和查找的复杂性 一种在 Linux/Unix 上查询文件系统的统一方法 功能几乎是不可能的。

    但是,据我所知,我所知道的所有应用程序都忽略了这一点 问题。

    (阅读:他们不会实现它)

    Boost 也不能​​解决问题,它们只给出了路径最大长度的一些模糊概念,特别是如果您想跨平台。据我所知,很多人都尝试过但未能解决这个问题(至少在理论上,实际上,在大多数情况下编写一个创建有效文件名的程序是绝对有可能的。

    如果您想自己实现这一点,可能值得考虑一些不太明显的事情,例如:

    无效字符的并发症

    文件系统限制与操作系统和软件限制之间的区别。例如,我认为是 Windows 操作系统的一部分的 Windows 资源管理器并不完全支持 NTFS。包含 ':' 和 '?' 等的文件可以愉快地驻留在 ntfs 分区上,但资源管理器只会扼杀它们。除此之外,您可以放心使用Boost Filesystem 的建议。

    路径长度的复杂性

    提升页面未完全解决的第二个问题是完整路径的长度。可能目前唯一可以确定的是,没有操作系统/文件系统组合支持无限的路径长度。但是,诸如“Windows 最大路径限制为 260 个字符”之类的陈述是错误的。 Windows 的 unicode API 允许您创建最长 32,767 个 utf-16 字符的路径。我还没有检查过,但我认为 Explorer 也同样投入使用,这将使该功能对于拥有除您自己以外的任何用户的软件完全无用(另一方面,您可能不希望您的软件在合唱中窒息)。

    存在一个名为 PATH_MAX 的旧变量,这听起来很有希望,但问题是 PATH_MAX simply isn't

    以建设性的说明结束,这里有一些关于编写解决方案的可能方法的想法。

    1. 使用定义来制作特定于操作系统的部分。 (Qt can help you with this)
    2. 使用 boost 页面和操作系统和文件系统文档中提供的建议来确定您的非法字符
    3. 对于路径长度,我想到的唯一可行的想法是二叉树试验一种错误方法,使用系统调用的错误处理来检查有效的路径长度。这是相当冷漠的,但可能是在各种系统上获得准确结果的唯一可能性。
    4. 擅长优雅的错误处理。

    希望这提供了一些见解。

    【讨论】:

    • 谢谢,非常有启发性且写得很好的答案。值得我 +1。
    • 嘿,谢谢,这是我的第一个赞!到现在为止,我什至有足够的声誉来清理链接并支持你的问题......让我们梦想有一天会出现一个好的图书馆来解决这个非常普遍的问题。
    【解决方案2】:

    根据 User7116 的回答:

    How do I check if a given string is a legal/valid file name under Windows?

    我不再偷懒了 ​​- 寻找优雅的解决方案,然后编写代码。我得到了:

    bool isLegalFilePath(QString path)
    {
        if (!path.length())
            return false;
    
        // Anything following the raw filename prefix should be legal.
        if (path.left(4)=="\\\\?\\")
            return true;
    
        // Windows filenames are not case sensitive.
        path = path.toUpper();
    
        // Trim the drive letter off
        if (path[1]==':' && (path[0]>='A' && path[0]<='Z'))
            path = path.right(path.length()-2);
    
        QString illegal="<>:\"|?*";
    
        foreach (const QChar& c, path)
        {
            // Check for control characters
             if (c.toLatin1() >= 0 && c.toLatin1() < 32)
                return false;
    
            // Check for illegal characters
            if (illegal.contains(c))
                return false;
        }
    
        // Check for device names in filenames
        static QStringList devices;
    
        if (!devices.count())
            devices << "CON" << "PRN" << "AUX" << "NUL" << "COM0" << "COM1" << "COM2"
                    << "COM3" << "COM4" << "COM5" << "COM6" << "COM7" << "COM8" << "COM9" << "LPT0"
                    << "LPT1" << "LPT2" << "LPT3" << "LPT4" << "LPT5" << "LPT6" << "LPT7" << "LPT8"
                    << "LPT9";
    
        const QFileInfo fi(path);
        const QString basename = fi.baseName();
    
        foreach (const QString& d, devices)
            if (basename == d)
    
                // Note: Names with ':' other than with a drive letter have already been rejected.
                return false;    
    
        // Check for trailing periods or spaces
        if (path.right(1)=="." || path.right(1)==" ")
            return false;
    
        // Check for pathnames that are too long (disregarding raw pathnames)
        if (path.length()>260)
            return false;
    
        // Exclude raw device names
        if (path.left(4)=="\\\\.\\")
            return false;
    
        // Since we are checking for a filename, it mustn't be a directory
        if (path.right(1)=="\\")
            return false;
    
        return true;
    }
    

    特点:

    • 可能比使用正则表达式更快
    • 检查非法字符并排除设备名称(注意 '' 不是非法的,因为它可以在路径名中)
    • 允许盘符
    • 允许完整路径名
    • 允许网络路径名
    • 允许 \\?\(原始文件名)之后的任何内容
    • 禁止任何以 \\.\(原始设备名称)开头的内容
    • 不允许以“\”结尾的名称(即目录名称)
    • 不允许名称超过 260 个不以 \\?\ 开头的字符
    • 不允许尾随空格和句点

    请注意,它不会检查以 \\? 开头的文件名的长度,因为这不是硬性规定。另请注意,正如 here 所指出的,包含多个反斜杠和正斜杠的名称不会被 win32 API 拒绝。

    【讨论】:

    • 这不适用于例如变音符号。 :-( "Ä" 是 196,c.toLatin1() 返回小于 32 的 -60。
    • 更好用:if (c.toLatin1() > 0 && c.toLatin1()
    • 嗯。再看一遍,我想知道一个控制字符是否可以编码在一个QString中。如果它在内部存储为 UTF16,则控制字符必须存在于 UTF 标准中。当我有时间的时候,我必须调查一下,或者你可以。
    • 我已经更新了。看来控制字符可以表示为 UTF-16。 Windows API 是否允许例如文件名中的选项卡?需要进行一些测试。
    • QChar::isPrint() 函数可能是更好的选择。事实证明,它们在内部是宽字符,并且可以具有控制代码。
    【解决方案3】:

    我不认为Qt有内置功能,但如果Boost是一个选项,你可以使用Boost.Filesystem的name_check functions

    如果 Boost 不是一个选项,它的 name_check 函数页面仍然很好地概述了在各种平台上检查的内容。

    【讨论】:

    • boost 绝对是一个选择,而且非常完美!非常感谢!
    • 注意 boost 不会检查无效名称(在 win 上),例如 com、lpt、aux 等 - 对于那些不记得 DOS 日子的人。
    • 没错。 Boost windows_name() 函数似乎就是它——对于我们这些使用 Boost 的人来说。请注意,它具有“CLOCK$”作为非法 Windows 名称;但似乎不是。
    【解决方案4】:

    很难在 Windows 上可靠地执行(一些奇怪的事情,例如名为“com”的文件仍然无效)并且您想处理 unicode,还是允许 >260 字符文件名的替代技巧。

    这里已经有很好的答案How do I check if a given string is a legal / valid file name under Windows?

    【讨论】:

      【解决方案5】:

      【讨论】:

      【解决方案6】:

      我只是创建一个简单的函数来验证平台的文件名,它只是在字符串中搜索任何无效字符。不要以为 Qt 中有内置函数。您可以在函数内使用#ifdefs 来确定您使用的平台。我会说足够干净。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-16
        • 2021-10-22
        • 2018-03-21
        • 2013-02-13
        • 2018-04-07
        • 1970-01-01
        相关资源
        最近更新 更多