【问题标题】:python magic can't identify unicode filenamepython magic无法识别unicode文件名
【发布时间】:2016-01-17 09:12:00
【问题描述】:

在我的小项目中,我必须识别目录中的文件类型。所以我选择了python-magic 模块并做了以下事情:

from Tkinter import Tk
from tkFileDialog import askdirectory

def getDirInput():
    root = Tk()
    root.withdraw()
    return askdirectory()
di = getDirInput()
print('Selected Directory: ' + di)
for f in os.listdir(di):
    m = magic.Magic(magic_file='magic')
    print 'Type of ' + f + '  -->  ' + m.from_file(f)

但是当我将它传递给from_file() 函数时,python-magic 似乎无法采用 unicode 文件名。这是一个示例输出:

Selected Directory: C:/Users/pruthvi/Desktop/vidrec/temp
Type of log.txt  -->  ASCII English text, with very long lines, with CRLF, CR line terminators
Type of TAEYEON 태연_ I (feat. Verbal Jint)_Music Video.mp4  -->  cannot open `TAEYEON \355\234\227_ I (feat. Verbal Jint)_Music Video.mp4' (No such file or directory)
Type of test.py  -->  a python script text executable

您可以观察到 python-magic 无法识别第二个文件 TAEYEON... 的类型,因为其中包含 unicode 字符。它将태연 字符显示为\355\234\227,而我在两种情况下都通过了相同的字符。我怎样才能克服这个问题并找到带有 Unicode 字符的文件类型呢?谢谢你

【问题讨论】:

  • Python 2.x 还是 Python 3?
  • 如果对文件名进行编码会发生什么? m.from_file(f.encode(sys.getfilesystemencoding()))
  • @AlastairMcCormack,Python 2.x
  • @falsetru ,IO 错误指出文件不存在,因为 unicode 字符被替换为 '??'显然是错误的
  • 这个怎么样? m.from_file(os.path.join(di, f))

标签: python unicode


【解决方案1】:

但似乎 python-magic 不能接受 unicode 文件名

正确。事实上,Windows 上的大多数跨平台软件都无法处理文件名中的非 ASCII 字符。

这是因为 C 标准库对所有文件名都使用字节字符串,但 Windows 使用 Unicode 字符串(技术上是 UTF-16 代码单元字符串,但这里的区别并不重要)。当使用 C 标准库的软件通过基于字节的字符串打开文件时,MS C 运行时会自动将其转换为 Unicode 字符串,使用取决于 Windows 语言环境的编码(易混淆的“ANSI”代码页)安装。您的 ANSI 代码页可能是 1252,它无法编码韩语字符,因此无法使用该文件名。不幸的是,ANSI 代码页从来没有像 UTF-8 那样合理,因此它永远不能包含所有可能的 Unicode 字符。

Python 的特殊之处在于它对 Windows Unicode 文件名有额外的支持,它绕过 C 标准库并直接为 Unicode 文件名调用底层 Win32 API。因此,您可以使用例如open() 传递一个 unicode 字符串,它将适用于所有文件名。

但是 python-magicfrom_file 调用不会从 Python 打开文件。相反,它将文件名传递给用纯 C 编写的 libmagic 库。libmagic 没有用于 Unicode 的特殊 Windows 文件名代码路径,因此失败。

我建议您自己从 Python 中打开文件并改用 magic.from_buffer

【讨论】:

  • 谢谢,有没有办法克服这个问题,找到文件名中包含 unicode 字符的文件类型?
  • 是的,使用m.from_buffer() 和从文件开头读取的一些数据(例如1024 字节)。
  • 哇,谢谢你解决了所有问题! ,我傻了不知道from_buffer() :3
【解决方案2】:

魔术模块的响应似乎表明您的字符在某处被错误地翻译了 - 只显示了一半的字符串并且 的字节顺序错误 - 至少应该是\355\227\234

由于这是在 Windows 上,这会引发 UTF-16 字节顺序的警钟。

也许可以通过编码为 UTF-16 来解决这个问题。正如其他评论者所建议的,您需要为目录添加前缀。

input_encoding = locale.getpreferredencoding()
u_di = di.decode(input_encoding)
m = magic.Magic(magic_file='magic') # only needs to be initialised once

for f in os.listdir(u_di):
    fq_f = os.path.join(u_di, f)
    utf16_fq_f = fq_f.encode("UTF-16LE")
    print m.from_file(utf16_fq_f)

【讨论】:

  • 谢谢,我知道在 python 2 中并非所有字符串都是 unicode,您需要传递一个 unicode 目录路径,但这也不能解决问题,它会创建一个 IO Error 声明文件不存在,因为我之前对 falsetru 评论过
  • 目录是否包含非ASCII字符?
  • 不,不是,所选目录打印在问题的输出中:)
  • 你能提供完整的IO Error异常吗?
  • 对不起,实际上它不会生成IO Error,但输出与上述问题中显示的相同
猜你喜欢
  • 1970-01-01
  • 2021-12-10
  • 2012-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-15
  • 1970-01-01
  • 2018-02-15
相关资源
最近更新 更多