9

OSX HFS+ ファイルシステムに存在するファイルに関するデータを保存しています。後で保存されたデータを繰り返し処理し、各ファイルがまだ存在するかどうかを調べたいと思います。私の目的では、ファイル名の大文字と小文字の区別に注意を払っているため、ファイル名の大文字と小文字が変更された場合、ファイルはもう存在しないと見なします。

私は試してみることから始めました

os.path.isfile(filename)

ただし、HFS+ に OSX を通常インストールすると、ファイル名の大文字と小文字が一致しなくても True が返されます。ファイルシステムが大文字と小文字を区別しない場合でも、大文字と小文字を区別する isfile() 関数を作成する方法を探しています。

os.path.normcase() と os.path.realpath() はどちらもファイル名を返します。

編集:

現在、ASCII に限定されたファイル名で機能するように見える 2 つの関数があります。ユニコードやその他の文字がこれにどのように影響するかはわかりません。

1 つ目は、omz と Alex L による回答に基づいています。

def does_file_exist_case_sensitive1a(fname):
    if not os.path.isfile(fname): return False
    path, filename = os.path.split(fname)
    search_path = '.' if path == '' else path
    for name in os.listdir(search_path):
        if name == filename : return True
    return False

2 番目の方法は、おそらくさらに効率的ではありません。

def does_file_exist_case_sensitive2(fname):
    if not os.path.isfile(fname): return False
    m = re.search('[a-zA-Z][^a-zA-Z]*\Z', fname)
    if m:
        test = string.replace(fname, fname[m.start()], '?', 1)
        print test
        actual = glob.glob(test)
        return len(actual) == 1 and actual[0] == fname
    else:
        return True  # no letters in file, case sensitivity doesn't matter

これはDSMの回答に基づく3番目です。

def does_file_exist_case_sensitive3(fname):
    if not os.path.isfile(fname): return False
    path, filename = os.path.split(fname)
    search_path = '.' if path == '' else path
    inodes = {os.stat(x).st_ino: x for x in os.listdir(search_path)}
    return inodes[os.stat(fname).st_ino] == filename

単一のディレクトリに何千ものファイルがある場合、これらがうまく機能するとは思いません。私はまだもっと効率的なものを望んでいます。

これらをテストしているときに気付いたもう 1 つの欠点は、ファイル名の大文字と小文字の一致のみをチェックすることです。ディレクトリ名を含むパスを渡すと、これまでのところ、これらの関数はどれもディレクトリ名の大文字と小文字をチェックしていません。

4

6 に答える 6

5

omz の投稿に続いて、次のようなものが機能する可能性があります。

import os

def getcase(filepath):
    path, filename = os.path.split(filepath)
    for fname in os.listdir(path):
        if filename.lower() == fname.lower():
            return os.path.join(path, fname)

print getcase('/usr/myfile.txt')
于 2013-01-25T04:24:05.603 に答える
4

ここに私が持っていたクレイジーな考えがあります。免責事項: 私は、ファイルシステムについてエッジ ケースを検討するのに十分な知識を持っていません。一度。

>>> !ls
A.txt   b.txt
>>> inodes = {os.stat(x).st_ino: x for x in os.listdir(".")}
>>> inodes
{80827580: 'A.txt', 80827581: 'b.txt'}
>>> inodes[os.stat("A.txt").st_ino]
'A.txt'
>>> inodes[os.stat("a.txt").st_ino]
'A.txt'
>>> inodes[os.stat("B.txt").st_ino]
'b.txt'
>>> inodes[os.stat("b.txt").st_ino]
'b.txt'
于 2013-01-25T04:50:39.240 に答える
2

次のようなものを使用してos.listdir、探しているファイル名がリストに含まれているかどうかを確認できます。

于 2013-01-25T04:14:08.507 に答える
1

この回答は、特殊文字をエスケープしたり、非 ASCII 文字を処理したり、ファイル システムのエンコーディングの問題に対処したりしようとしないため、単なる概念実証です。

プラス面としては、Python でファイルをループする必要がなく、最終的なパス セグメントに至るまでのディレクトリ名のチェックを適切に処理します。

この提案は、(少なくとも bash を使用している場合) 次のコマンドは、その正確な大文字と小文字が一致する/my/path場合にのみ、エラーなしでパスを見つけるという観察に基づいています。/my/path

$ ls /[m]y/[p]ath

(括弧がパス部分から除外されている場合、その部分は大文字と小文字の変更に影響されません。)

この考え方に基づくサンプル関数を次に示します。

import os.path
import subprocess

def does_exist(path):
    """Return whether the given path exists with the given casing.

    The given path should begin with a slash and not end with a trailing
    slash.  This function does not attempt to escape special characters
    and does not attempt to handle non-ASCII characters, file system
    encodings, etc.
    """
    parts = []
    while True:
        head, tail = os.path.split(path)
        if tail:
            parts.append(tail)
            path = head
        else:
            assert head == '/'
            break
    parts.reverse()
    # For example, for path "/my/path", pattern is "/[m]y/[p]ath".
    pattern = "/" + "/".join(["[%s]%s" % (p[0], p[1:]) for p in parts])
    cmd = "ls %s" % pattern
    return_code = subprocess.call(cmd, shell=True)
    return not return_code
于 2014-12-21T12:36:19.757 に答える
-2

そのファイルを開こうとすることもできます。

    try:open('test', 'r')
    except IOError: print 'File does not exist'
于 2013-01-25T05:43:59.090 に答える