【问题标题】:Managing Mac OS created filenames with non ASCII characters in windows environments?在 Windows 环境中管理 Mac OS 创建的具有非 ASCII 字符的文件名?
【发布时间】:2011-10-06 23:40:35
【问题描述】:

我处理大量未知文件,并且一直在学习 python 来帮助我过滤/排序和处理这些文件。

我正在查看的集合有大量资源分支,我编写了一个小脚本来查找它们并删除它们(下一步是找到它们并移动它们,但那是另一天的事了)。

我在这个集合中发现有许多文件名中包含非 ascii 字符,这似乎触发了 os.delete 函数。

示例文件名:._spec com 报告 395 (注意 3 在它下面有一个小点,我找不到示例,或者弄清楚如何显示文件名的十六进制...)

我记录了所有文件名,这是该文件的日志记录:._spec com report 3?95

我得到的错误是windowserror,因为它找不到文件(它传递的字符串不是windows操作系统所知道的文件。)我放入了一个try子句以允许我工作它,但我真的很喜欢妥善处理它。

我还尝试根据这篇文章在步行选项 `os.walk(u'.') 中使用 unicode 开关:Handling ascii char in python string(最佳答案),我看到以下错误:

Traceback (most recent call last):
 File "<stdin>", line 3, in <module>
 File "c:\python27\lib\encodings\cp850.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode character u'\uf022' in position
20: character maps to <undefined>

所以我猜答案在于如何解析文件名,并想知​​道是否有人能够指出我正确的方向......

代码:

import os
import sys

rootdir = "c:\target Dir to walk"
destKeep = "Keepers.txt"
destDelete = "Deleted.txt"

matchingText = "._"
files_removed = 1
for folder, subs, files in os.walk(rootdir):  
    outfileKeep = open(destKeep,"a")
    outfileDelete = open(destDelete,"a")
    for filename in files:
        matchScore = filename.find(matchingText)
        src = os.path.join(folder, filename)
        srcNewline = src + ", " + str(filename) + "\n"
        if matchScore == -1:
        outfileKeep.writelines(srcNewline)
        else: 
            outfileDelete.writelines(srcNewline)
            try:
                os.remove(src)
        except WindowsError:
                print "I was unable to delete this file:"
                outfileKeep.writelines(srcNewline)
            files_removed += 1
            if files_removed:
                print '%d files removed' % files_removed
            else :
                print 'No files removed'
    outfileKeep.close()
    outfileDelete.close()

【问题讨论】:

    标签: python macos unicode filenames


    【解决方案1】:

    os.walk(u'.') 是获取本机 Unicode 文件名的常规方法,它应该可以正常工作;对我有用。

    你的问题就在这里:

    srcNewline = src + ", " + str(filename) + "\n"
    

    str(filename) 将使用默认编码将您的 Unicode 字符串转换回字节,并且因为该编码没有字符 U+F022(*),​​所以您会得到一个 UnicodeEncodeError。您必须通过例如srcNewLine= '%s, %s\n' % (src, filename.encode('utf-8')) 来选择要存储在输出文件中的编码,或者(也许更好)将您的字符串保持为Unicode 并使用codecs.opened 文件将它们写入文件。

    (*:这是一个不应该使用的私人使用区域字符,但我想你现在对此无能为力......)

    【讨论】:

    • 您好,谢谢您的回复。我了解您所说的大部分内容,并且一直在考虑您的建议。我仍然无法让它工作 - 我想我更接近于理解这个问题......问题似乎是操作系统层如何处理文件名,这与基于 MSDOS 的函数的工作方式不同文件名。本质上,文件名中有一个 2 字节字符(未知编码),资源管理器可以“看到”但被剥离和屏蔽的 MSDOS。似乎这个字符的传递是问题 - 也许我应该查看的是比特流而不是字符串?
    • 我还发现有问题的字形由一个 ASCII 数字组成,后跟一个十六进制代码 EF 80 A2。我通过查看 Firefox 中的文件夹并查看源代码发现了这一点。有趣的是,我可以看到一些数字的数字字形,每个数字都有相同的以下代码,建议字符的 4 字节字 - UTF-16?
    • 字节序列EF 80 A2是U+F022的UTF-8编码。这就是我希望.encode('utf-8') 在输出到 Keepers.txt/Deleted.txt 文件时能够正常工作的方式,所以这很好。但是,您不应该使用编码到字节的字符串来实际访问文件,因为当您使用字节字符串作为文件名时,您会受到系统默认代码页的限制(其中不会包含大多数 Unicode 字符,当然也不会伪造的 U+F022 字符)。将文件名保持为 Unicode,仅在将它们写入字节流时将它们编码为字节。
    • 太棒了,谢谢。我做了很多关于 U+F022 字形和变音符号的背景阅读。这一切都说得通。谢谢你的时间,我很感激。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多