【问题标题】:python: read a binary file with non ascii namepython:读取具有非 ascii 名称的二进制文件
【发布时间】:2016-10-20 14:18:19
【问题描述】:

我尝试制作一个脚本,在文件夹中搜索双文件并将其返回到这样的字典中 {filehash1:[dirfile1,dirfile2],filehash2:[dirfile3]} (dirfile1 和 dirfile2 相同的文件名称/位置不同)

第一个代码:

import glob
import hashlib

def getallfolders(dir):
    print dir+"*\\"
    folders = glob.glob(dir+"*\\")
    return folders

def getallfiles(dir):
    folders = glob.glob(dir+"*.*")
    return folders


def filehash(file):
    BLOCKSIZE = 65536
    hasher = hashlib.sha1()
    with open(file, 'rb') as afile:
        buf = afile.read(BLOCKSIZE)
        while len(buf) > 0:
            hasher.update(buf)
            buf = afile.read(BLOCKSIZE)
    return hasher.hexdigest()


def double_files(dir):
    mil = {}
    folders = getallfolders(dir)
    for folder in folders:
        mil.update(double_files(folder))
    files = getallfiles(dir)
    for file in files:
        fhash = filehash(file)
        if fhash in mil.keys():
            mil[fhash] = mil[fhash] + [file]
        else:
            mil[fhash] = [file]
    return mil



print double_files("E:\\not organised\\")

但是如果我尝试运行它,它会因错误而崩溃

IOError: [Errno 2] No such file or directory: file

这是因为不是所有的文件名都是英文的 所以我尝试修复它,现在代码如下所示:

# -*- coding: utf-8 -*-
import glob
import hashlib
import codecs

def getallfolders(dir):
    print dir+"*\\"
    folders = glob.glob(dir+"*\\")
    return folders

def getallfiles(dir):
    folders = glob.glob(dir+"*.*")
    return folders



def filehash(file):
    BLOCKSIZE = 65536
    hasher = hashlib.sha1()
    file = file.decode("utf8")
    with codecs.open(file, "rb", encoding="utf8") as afile:
        buf = afile.read(BLOCKSIZE)
        while len(buf) > 0:
            buf = buf.encode("ISO-8859-1")
            hasher.update(buf)
            buf = afile.read(BLOCKSIZE)
    return hasher.hexdigest()

def double_files(dir):
    mil = {}
    folders = getallfolders(dir)
    for folder in folders:
        mil.update(double_files(folder))
    files = getallfiles(dir)
    for file in files:
        fhash = filehash(file)
        if fhash in mil.keys():
            mil[fhash] = mil[fhash] + [file]
        else:
            mil[fhash] = [file]
    return mil



print double_files("E:\\not organised\\")

我添加 # -*- coding: utf-8 -*- 并改变 with open(file, 'rb')with open(file, encoding='utf-8') 但现在我得到了错误:

UnicodeDecodeError: 'utf8' codec can't decode byte .. in position ..: Tnvalid start byte

(.. 表示它并不总是相同的) 它发生在buf = afile.read(BLOCKSIZE) 行 我知道文件已打开,但是当我尝试使用读取功能时,它会因该错误而崩溃。 而且我不知道如何解决它... 请帮忙。

【问题讨论】:

  • # -*- coding: utf-8 -*- 仅适用于代码中的非 ascii litteral 字符串。
  • 文件是什么编码的?你确定是utf-8 吗?
  • 它不是一个特定的文件它可以是一个txt jpg等
  • @Maze88 如何理解编码的工作原理而不是偶然编程? OP 已经将他的文件名解码为 un​​icode(你认为 file = file.decode("utf8") 在做什么?)

标签: python file unicode utf-8


【解决方案1】:

你似乎对编码很困惑......

  • # -*- coding: utf-8 -*- 仅适用于代码中的非 ascii litteral 字符串。

  • file = file.decode("utf8") 将字符串 file(最好命名为 filename)从 utf-8 解码为 un​​icode。这仅在您的文件系统的编码(文件和文件夹名称)当然是 utf-8 时才有效(或者更准确地说,只要您的所有文件和文件夹名称都可以解释为有效的 utf-8)。当然,它不会对文件的内容产生太大影响。

  • codecs.open(file, "rb", encoding="utf8") :这仅在您的文件内容实际上是一些 utf-8 编码的文本时才有意义,并且显然您正在读取任何类型的二进制数据,因此如果您收到虚假编码错误也就不足为奇了.

  • buf.encode("ISO-8859-1") : 完全没用,hashlib.sha1() 与 utf-8 配合得很好。

长话短说:没有你的“修复”是有意义的。

回到问题的根源:

IOError: [Errno 2] 没有这样的文件或目录:文件 这是因为不是所有的文件名都是英文的

我真的认为你在这里假设太多 - 如果你通过浏览文件系统获得非 ascii(不是“非英语”)文件名,那么你的文件系统应该支持这种非 ascii 编码(嗯它是 Windows,所以这里可能会发生一些特殊的事情,但我可以告诉你我从来没有在 Linux 和 MacOS 上遇到过这样的问题)。在最坏的情况下,如果您确定您的“非英语”(实际上是非 ascii)文件名是 utf8,您可以尝试 only file = file.decode('utf-8') 看看它是否效果更好,但仍然是 @987654321 @。

实际上,由于您没有发布有效的回溯(带有完整的文件名),因此很难判断您的原始代码到底出了什么问题,因此您最好的选择当然是切换回您的第一个实现并仔细阅读完整的追溯。然后,您可以使用交互式 Python shell 或 the step debugger 进一步检查问题。

哦,是的:我假设您使用的是 Python 2.x - Python 3 处理编码有点不同。

【讨论】:

  • 刚刚发现我的问题
  • 在 getallfiles 中的问题是我找到了一个名称中包含 ~ 的文件,并且它变成了一个 ~ 并且它与我编辑评论的方式不同?
【解决方案2】:

所以在我阅读了你们所有人写的内容后,我理解了我的问题,这次真的修复了代码,它工作正常 (发现我没有注意到的字典的另一个问题) 工作代码:

import hashlib
from os import listdir
from os.path import isfile, join
import os


def getallfolders(dir):
    folders = [d for d in os.listdir(dir) if os.path.isdir(os.path.join(dir, d))]
    return folders


def getallfiles(dir):
    folders = [f for f in listdir(dir) if isfile(join(dir, f))]
    return folders


def filehash(file):
    BLOCKSIZE = 65536
    hasher = hashlib.sha1()
    with open(file, "rb") as afile:
        buf = afile.read(BLOCKSIZE)
        while len(buf) > 0:
            hasher.update(buf)
            buf = afile.read(BLOCKSIZE)
    return hasher.hexdigest()


def double_files(dir):
    print dir
    mil = {}
    folders = getallfolders(dir)
    for folder in folders:
        newmil = double_files(dir + folder + "\\")
        for i in newmil:
            if i in mil.keys():
                mil[i] = mil[i] + newmil[i]
            else:
                mil[i] = newmil[i]
    files = getallfiles(dir)
    for file in files:
        fhash = filehash(dir + file)
        if fhash in mil.keys():
            mil[fhash] = mil[fhash] + [dir + file]
        else:
            mil[fhash] = [dir + file]
    return mil


mil = double_files(u"E:\\not organised\\")
f = open('double_files.txt', 'w')
for i in mil:
    if len(mil[i]) > 1:
        for y in mil[i]:
            f.write(y.encode('utf8')+"\n")
        f.write("\n\n")
f.close()

【讨论】:

  • 很高兴您解决了这个问题。只是一些提示wrt /你如何使用dicts:1 / dict.keys()list所以x in mydict.keys()是o(n)。你最好直接查一下,即x in mydict,也就是o(1)。 2/ 对于您的用例,collections.defaultdict 无论如何都会避免任何键查找;)
猜你喜欢
  • 1970-01-01
  • 2015-03-13
  • 1970-01-01
  • 1970-01-01
  • 2013-10-09
  • 2012-02-01
  • 1970-01-01
相关资源
最近更新 更多