[英]Check if file system is case-insensitive in Python
如果文件系统不区分大小写,是否有一种简单的方法来检查 Python? 我特别考虑像 HFS+ (OSX) 和 NTFS (Windows) 这样的文件系统,即使文件大小写被保留,您也可以在其中访问与 foo、Foo 或 FOO 相同的文件。
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.
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)
如果只调用一次,它会稍微慢一点,而在其他情况下会明显更快。
关于不同文件系统等的好点,Eric Smith。 但是为什么不使用带有 dir 参数的 tempfile.NamedTemporaryFile 并避免自己做所有上下文管理器呢?
def is_fs_case_sensitive(path):
#
# Force case with the prefix
#
with tempfile.NamedTemporaryFile(prefix='TmP',dir=path, delete=True) as tmp_file:
return(not os.path.exists(tmp_file.name.lower()))
我还应该提到,您的解决方案并不能保证您实际上是在测试区分大小写。 除非您检查默认前缀(使用 tempfile.gettempprefix())以确保它包含小写字符。 因此,在此处包含前缀并不是真正可选的。
您的解决方案会清理临时文件。 我同意这似乎很明显,但人们永远不知道,做一个吗?
从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)))
没有在mkstemp
指定dir
参数,区分大小写的问题是模糊的。 您正在测试临时目录所在位置的区分大小写,但您可能想知道特定路径。
如果您将从mkstemp
返回的完整路径转换为大写,您可能会错过路径中某处的转换。 例如,我在 Linux 上使用 vfat 在/media/FLASH
上安装了一个 USB 闪存驱动器。 测试/MEDIA/FLASH
下的任何内容总是会失败,因为/media
位于(区分大小写的)ext4 分区上,但闪存驱动器本身不区分大小写。 挂载的网络共享可能是另一种情况。
最后,也许在 Amber 的回答中不言而喻,您需要清理 mkstemp 创建的临时文件。
我认为对此有一个更简单(并且可能更快)的解决方案。 以下似乎适用于我测试的地方:
import os.path
home = os.path.expanduser('~')
is_fs_case_insensitive = os.path.exists(home.upper()) and os.path.exists(home.lower())
import os
if os.path.normcase('A') == os.path.normcase('a'):
# case insensitive
else:
# case sensitive
@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=}")
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,我通过以下方式检查了pathlib
、 os
、 os.path
的内容:
[k for k in vars(pathlib).keys() if "case" in k.lower()]
没有什么看起来像它,尽管它确实有一个pathlib.supports_symlinks
但没有区分大小写。
我认为我们可以在 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()
我相信这是对这个问题最简单的解决方案:
from fnmatch import fnmatch
os_is_case_insensitive = fnmatch('A','a')
来自: https : //docs.python.org/3.4/library/fnmatch.html
如果操作系统不区分大小写,则在执行比较之前,两个参数都将被规范化为全部小写或大写。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.