Проверьте, не учитывает ли файловая система регистр в Python

есть ли простой способ проверить Python, если файловая система нечувствительна к регистру? Я имею в виду, в частности, файловые системы, такие как HFS+ (OSX) и NTFS (Windows), где вы можете получить доступ к тому же файлу, что и foo, Foo или FOO, хотя файловый кейс сохраняется.

6 ответов


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)

который немного медленнее, если только вызывается один раз, и значительно быстрее в каждом другом случае.


начиная с ответа Эмбер, я придумал этот код. Я не уверен, что он полностью надежен, но он пытается решить некоторые проблемы в оригинале (что я упомяну ниже).

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, вопрос чувствительности к регистру неясен. Вы тестируете чувствительность к регистру, где бы ни находился временный каталог, но вы можете узнать о конкретном пути.

если вы конвертируете полный путь, возвращенный из mkstemp в верхнем регистре вы потенциально можете пропустить переход где-то на пути. Например, у меня есть USB-накопитель на Linux, установленный с помощью vfat в /media/FLASH. Проверка существования чего-либо под /MEDIA/FLASH всегда будет терпеть неудачу, потому что /media находится на (чувствительном к регистру) разделе ext4, но сам Флэш-накопитель не чувствителен к регистру. Смонтированные сетевые ресурсы могут быть другой ситуацией, подобной этой.

наконец, и, возможно, это само собой разумеется в ответе Эмбер, вы захотите очистить вверх по временному файлу, созданному mkstemp.


хорошая точка в разных файловых системах и т. д. Эрик Смит. Но почему бы не использовать 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 ()), чтобы убедиться, что он содержит символ нижнего регистра. Поэтому включение префикса здесь не совсем необязательный.

ваше решение очищает временный файл. Согласен, это казалось очевидным, но ведь никогда не знаешь наверняка.


import os

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

Я считаю, что это самое простое решение вопроса:

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

From:https://docs.python.org/3.4/library/fnmatch.html

если операционная система нечувствительна к регистру, то оба параметра будут были преобразованы в Нижнем или верхнем регистре перед сравнением выполненный.