Проверьте, не является ли файловая система нечувствительной к регистру в Python
Есть ли простой способ проверить Python, если файловая система нечувствительна к регистру? Я имею в виду, в частности, файловые системы, такие как HFS + (OSX) и NTFS (Windows), где вы можете получить доступ к тому же файлу, что и foo, Foo или FOO, даже если файл сохраняется.
Ответы
Ответ 1
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.
Ответ 2
Ответ, предоставленный 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)
Это немного медленнее, если вы вызываете только один раз и значительно быстрее в каждом другом случае.
Ответ 3
Начиная с ответа 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
в верхний регистр, вы можете пропустить переход где-то в пути. Например, у меня есть USB-накопитель на Linux, установленный с помощью vfat в /media/FLASH
. Тестирование существования чего-либо под /media/FLASH
всегда будет терпеть неудачу, потому что /media
находится на секционном диске ext4 (с учетом регистра), но сам флеш-диск не учитывает регистр. Установленные сетевые ресурсы могут быть другой ситуацией.
Наконец, и, может быть, это само собой разумеется в ответе Amber, вы захотите очистить временный файл, созданный mkstemp.
Ответ 4
Хорошая точка в разных файловых системах и т.д., Эрик Смит. Но почему бы не использовать 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()), чтобы убедиться, что он содержит строчный символ. Поэтому включение префикса здесь не является обязательным.
Ваше решение очищает временный файл. Я согласен с тем, что это казалось очевидным, но никто не знает, сделайте одно?
Ответ 5
import os
if os.path.normcase('A') == os.path.normcase('a'):
# case insensitive
else:
# case sensitive