在Windows中检测文件名大小写不匹配(最好使用python)?

4 投票
2 回答
1485 浏览
提问于 2025-04-15 13:59

我有一些 XML 配置文件,这些文件是在 Windows 环境下创建的,但最终是在 Linux 上使用。这些配置文件之间通过文件路径互相引用。我们之前遇到过大小写敏感和多余空格的问题,所以我想写一个脚本来检查这些问题。如果有 Cygwin 的话,可能会有帮助。

举个例子:

假设我有一个指向文件 foo/bar/baz.xml 的引用,我会这样做:

<someTag fileref="foo/bar/baz.xml" />

现在如果我们不小心这样做:

<someTag fileref="fOo/baR/baz.Xml  " />

在 Windows 上还是能正常工作,但在 Linux 上就会出错。

我想做的是检测这些情况,看看这些文件中的引用是否和实际文件在大小写上匹配。

2 个回答

0

很难判断你具体遇到了什么问题,不过如果你在保存文件名之前,先用一下 os.path.normcasestr.strip,应该能解决你所有的问题。

正如我在评论中提到的,怎么会出现这样的错误其实不太清楚。不过,只要你有一些合理的命名规则(比如所有文件名都用小写字母),检查文件是否存在其实是很简单的:

try:
    open(fname)
except IOError:
    open(fname.lower())
3

os.listdir 是一个用来列出目录中所有文件名的工具,在所有保留大小写的文件系统中(包括Windows),它会返回你所列目录中文件名的实际大小写。

所以你需要在路径的每一层都进行这样的检查:

def onelevelok(parent, thislevel):
  for fn in os.listdir(parent):
    if fn.lower() == thislevel.lower():
      return fn == thislevel
  raise ValueError('No %r in dir %r!' % (
      thislevel, parent))

在这里,我假设如果一个名字完全没有大小写变化,那是一种不同的错误,所以我会用异常来处理这种情况;对于整个路径(假设没有驱动器字母或UNC路径,因为这些在Windows上也不适用):

def allpathok(path):
  levels = os.path.split(path)
  if os.path.isabs(path):
    top = ['/']
  else:
    top = ['.']
  return all(onelevelok(p, t)
             for p, t in zip(top+levels, levels))

如果,比如说,foo/bar 并不是指 foo 在当前目录下,而是在其他地方;当然,如果需要使用UNC或驱动器字母的话,也可能需要调整(不过正如我提到的,把它们转换到Linux上其实并不简单;-)。

实现说明:我利用了 zip 的一个特点,它会自动忽略比最短序列多出的“额外项”;所以我不需要手动去切掉第一个参数 levels 中的“叶子”(最后一个项),zip 会帮我处理。all 会在可以的情况下提前结束,一旦发现有假值就会返回 False,所以它的效果和显式循环一样,但更快也更简洁。

撰写回答