检查文件系统是否在Python中不区分大小写

时间:2011-10-23 23:29:50

标签: python filesystems ntfs hfs+

如果文件系统不区分大小写,是否有一种简单的方法可以检查Python?我正在考虑像HFS +(OSX)和NTFS(Windows)这样的文件系统,你可以在其中访问与foo,Foo或FOO相同的文件,即使保留了文件大小写。

9 个答案:

答案 0 :(得分:17)

import os
import tempfile

# By default mkstemp() creates a file with
# a name that begins with 'tmp' (lowercase)
tmphandle, tmppath = tempfile.mkstemp()
if os.path.exists(tmppath.upper()):
    # Case insensitive.
else:
    # Case sensitive.

答案 1 :(得分:5)

Amber提供的答案将留下临时文件碎片,除非明确处理关闭和删除。为了避免这种情况,我使用:

import os
import tempfile

def is_fs_case_sensitive():
    #
    # Force case with the prefix
    #
    with tempfile.NamedTemporaryFile(prefix='TmP') as tmp_file:
        return(not os.path.exists(tmp_file.name.lower()))

虽然我的使用案例通常会多次测试,但我会将结果存储起来以避免不止一次触摸文件系统。

def is_fs_case_sensitive():
    if not hasattr(is_fs_case_sensitive, 'case_sensitive'):
        with tempfile.NamedTemporaryFile(prefix='TmP') as tmp_file:
            setattr(is_fs_case_sensitive,
                    'case_sensitive',
                    not os.path.exists(tmp_file.name.lower()))
    return(is_fs_case_sensitive.case_sensitive)

如果仅调用一次,则速度稍慢,而在其他情况下则显着更快。

答案 2 :(得分:2)

从Amber的回答开始,我想出了这段代码。我不确定它是否完全可靠,但它试图解决原始问题(我将在下面提到)。

import os
import sys
import tempfile
import contextlib


def is_case_sensitive(path):
    with temp(path) as tmppath:
        head, tail = os.path.split(tmppath)
        testpath = os.path.join(head, tail.upper())
        return not os.path.exists(testpath)


@contextlib.contextmanager
def temp(path):
    tmphandle, tmppath = tempfile.mkstemp(dir=path)
    os.close(tmphandle)
    try:
        yield tmppath
    finally:
        os.unlink(tmppath)


if __name__ == '__main__':
    path = os.path.abspath(sys.argv[1])
    print(path)
    print('Case sensitive: ' + str(is_case_sensitive(path)))

如果未在dir中指定mkstemp参数,则区分大小写的问题很模糊。您正在测试临时目录恰好位于何处的区分大小写,但您可能想知道特定路径。

如果将从mkstemp返回的完整路径转换为大写,则可能会错过路径中某处的转换。例如,我在/media/FLASH使用vfat在Linux上安装了USB闪存驱动器。测试/MEDIA/FLASH下任何内容的存在将始终失败,因为/media位于(区分大小写)的ext4分区上,但闪存驱动器本身不区分大小写。已安装的网络共享可能是另一种情况。

最后,也许在Amber的回答中不用说,你要清理mkstemp创建的临时文件。

答案 3 :(得分:2)

关于不同文件系统等的好点,Eric Smith。但是为什么不将tempfile.NamedTemporaryFile与dir参数一起使用,并避免让所有上下文管理器自行解除?

def is_fs_case_sensitive(path):
    #
    # Force case with the prefix
    #
    with tempfile.NamedTemporaryFile(prefix='TmP',dir=path) as tmp_file:
        return(not os.path.exists(tmp_file.name.lower()))

我还应该提一下,您的解决方案并不能保证您实际上是在测试区分大小写。除非您检查默认前缀(使用tempfile.gettempprefix())以确保它包含小写字符。所以在这里包含前缀并不是真正可选的。

您的解决方案会清除临时文件。我同意它似乎显而易见,但是一个人永远不知道,做一个吗?

答案 4 :(得分:1)

@Shrikant答案的变化,即使在用户没有房屋的情况下,也适用于模块(即,不在REPL中):

import os.path
is_fs_case_insensitive = os.path.exists(__file__.upper()) and os.path.exists(__file__.lower())
print(f"{is_fs_case_insensitive=}")

输出(macOS):

is_fs_case_insensitive=True ?

Linux方面:

(ssha)vagrant ~$python3.8 test.py
is_fs_case_insensitive=False ?
(ssha)vagrant ~$lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04 LTS
Release:    20.04
Codename:   focal

FWIW,我通过以下方式检查了pathlibosos.path的内容:

[k for k in vars(pathlib).keys() if "case" in k.lower()]

尽管它确实有一个pathlib.supports_symlinks,但看起来大小写却一无是处。

答案 5 :(得分:0)

import os

if os.path.normcase('A') == os.path.normcase('a'):
    # case insensitive
else:
    # case sensitive

答案 6 :(得分:0)

我相信这是这个问题最简单的解决方案:

from fnmatch import fnmatch
os_is_case_insensitive = fnmatch('A','a')

来自:https://docs.python.org/3.4/library/fnmatch.html

  

如果操作系统不区分大小写,则两个参数都将   在比较之前标准化为所有小写或大写   进行。

答案 7 :(得分:0)

我认为有一个更简单(可能更快)的解决方案。以下似乎适用于我测试的地方:

import os.path
home = os.path.expanduser('~')
is_fs_case_insensitive = os.path.exists(home.upper()) and os.path.exists(home.lower())

答案 8 :(得分:0)

我认为我们可以在 Python 3.5+ 上使用 pathlib 一行完成此操作,而无需创建临时文件:

from pathlib import Path

def is_case_insensitive(path) -> bool:
    return Path(str(Path.home()).upper()).exists()

反之亦然:

def is_case_sensitive(path) -> bool:
    return not Path(str(Path.home()).upper()).exists()