Kei*_*ith 7 python filesystems macos hfs+
我正在存储有关OSX HFS +文件系统上存在的文件的数据.我后来想迭代存储的数据并确定每个文件是否仍然存在.出于我的目的,我关心文件名区分大小写,所以如果文件名的大小写已经改变,我会认为该文件不再存在.
我开始尝试
os.path.isfile(filename)
Run Code Online (Sandbox Code Playgroud)
但是在HFS +上正常安装OSX时,即使文件名大小写不匹配,也会返回True.我正在寻找一种方法来编写一个isfile()函数,即使文件系统没有,它也会关心大小写.
os.path.normcase()和os.path.realpath()都会在我传入文件的情况下返回文件名.
编辑:
我现在有两个函数似乎适用于限制为ASCII的文件名.我不知道unicode或其他角色会如何影响这个.
第一个是基于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
Run Code Online (Sandbox Code Playgroud)
第二个可能效率更低.
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
Run Code Online (Sandbox Code Playgroud)
以下是DSM的第三个答案.
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
Run Code Online (Sandbox Code Playgroud)
如果我在一个目录中有数千个文件,我不希望这些表现良好.我仍然希望能有更高效的东西.
我在测试这些时注意到的另一个缺点是它们只检查案例匹配的文件名.如果我传递一个包含目录名的路径,到目前为止这些函数都没有检查目录名的大小写.
此答案通过提供改编自Alex L 的答案的函数来补充现有答案,即:
import os, unicodedata
def gettruecasepath(path): # IMPORTANT: <path> must be a Unicode string
if not os.path.lexists(path): # use lexists to also find broken symlinks
raise OSError(2, u'No such file or directory', path)
isosx = sys.platform == u'darwin'
if isosx: # convert to NFD for comparison with os.listdir() results
path = unicodedata.normalize('NFD', path)
parentpath, leaf = os.path.split(path)
# find true case of leaf component
if leaf not in [ u'.', u'..' ]: # skip . and .. components
leaf_lower = leaf.lower() # if you use Py3.3+: change .lower() to .casefold()
found = False
for leaf in os.listdir(u'.' if parentpath == u'' else parentpath):
if leaf_lower == leaf.lower(): # see .casefold() comment above
found = True
if isosx:
leaf = unicodedata.normalize('NFC', leaf) # convert to NFC for return value
break
if not found:
# should only happen if the path was just deleted
raise OSError(2, u'Unexpectedly not found in ' + parentpath, leaf_lower)
# recurse on parent path
if parentpath not in [ u'', u'.', u'..', u'/', u'\\' ] and \
not (sys.platform == u'win32' and
os.path.splitdrive(parentpath)[1] in [ u'\\', u'/' ]):
parentpath = gettruecasepath(parentpath) # recurse
return os.path.join(parentpath, leaf)
def istruecasepath(path): # IMPORTANT: <path> must be a Unicode string
return gettruecasepath(path) == unicodedata.normalize('NFC', path)
Run Code Online (Sandbox Code Playgroud)
gettruecasepath()
获取存储在指定路径(绝对或相对)路径的文件系统中的大小写精确表示(如果存在):
u
;例如u'Motörhead'
; str 变量:转换为,例如,strVar.decode('utf8')
.
和..
),除了折叠多个路径分隔符,并且在 Windows 上,返回的路径始终\
用作路径分隔符。OSError
,如果路径不存在,如果你没有权限访问它抛出异常,或。istruecasepath()
用于gettruecasepath()
将输入路径与存储在文件系统中的路径进行比较。
警告:由于这些函数需要检查输入路径(如指定的)每个级别的所有目录条目,它们会很慢- 不可预测,因为性能将对应于检查的目录包含的项目数量。请继续阅读背景信息。
奇怪的是 OSX 和 Windows 都没有提供直接解决这个问题的原生 API 方法。
虽然在 Windows 上你可以巧妙地结合两种 API 方法来解决这个问题,但在 OSX 上,除了上面所采用的在检查的路径的每个级别上缓慢枚举目录内容之外,我所知道的没有替代方法。
HFS+(OSX 文件系统)以分解的Unicode 形式 (NFD ) 存储文件名,这在将此类名称与大多数编程语言中的内存中 Unicode 字符串进行比较时会导致问题,这些字符串通常采用组合Unicode 形式 (NFC)。
例如,在源代码中ü
指定为文字的具有非 ASCII 字符的路径将表示为单个Unicode 代码点,; 这是一个例子NFC:在“C”表示组成,这是因为信基本字母和其变音符号(一个组合分音符号)形成单个字母。U+00FC
u
¨
相比之下,如果您将其ü
用作 HFS+文件名的一部分,它将被转换为NFD形式,从而产生2 个Unicode 代码点:基本字母u
( U+0075
),后跟组合分音符 ( ?
, U+0308
) 作为单独的代码点;'D' 代表分解,因为字符被分解为基本字母及其相关的变音符号。
尽管 Unicode 标准认为这两种表示(规范地)等效,但大多数编程语言,包括 Python,不承认这种等效性。
在 Python 的情况下,您必须unicodedata.normalize()
在比较之前使用将两个字符串转换为相同的形式。
(旁注:Unicode标准形式与 Unicode编码是分开的,尽管 Unicode 代码点的不同数量通常也会影响对每种形式进行编码所需的字节数。在上面的示例中,单代码点ü
(NFC) 需要2 个字节来以 UTF-8 ( U+00FC
-> 0xC3 0xBC
) 编码,而双码点ü
(NFD) 需要3 个字节(U+0075
->0x75
和U+0308
-> 0xCC 0x88
))。
继 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')
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
750 次 |
最近记录: |