python:读取非ascii名称的二进制文件

时间:2016-10-20 14:18:19

标签: python file unicode utf-8

我尝试制作一个脚本,在文件夹中搜索双重文件并将其返回到这样的字典中 {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)行中很开心 我知道文件opend但是当我尝试使用read函数时它崩溃了。 我不知道如何解决它... 请帮忙。

2 个答案:

答案 0 :(得分:0)

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

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

  • file = file.decode("utf8")将字符串file(更好地命名为filename)从utf-8解码为unicode。这仅适用于文件系统的编码(文件和文件夹名称)当然是utf-8(或者更确切地说,只要所有文件和文件夹名称都可解释为有效的utf-8)。当然,它对文件的内容没有太大作用。

  • codecs.open(file, "rb", encoding="utf8"):这只有在您的文件内容实际上是一些utf-8编码的文本时才有意义,显然您正在阅读任何类型的二进制数据,因此如果您发现虚假的话,这并不奇怪编码错误。

  • buf.encode("ISO-8859-1"):简单无用,hashlib.sha1()可以使用utf-8。

总而言之: none 您的“修正”是有道理的。

回到问题的根源:

  

IOError:[Errno 2]没有这样的文件或目录:file   这是因为并非所有文件都用英文命名

我真的认为你在这里假设太多 - 如果你从浏览你的文件系统得到一个非ascii(不是“非英语”)文件名,那么你的文件系统应该支持这种非ascii编码(以及它是Windows,所以可能会有一些古怪的东西在这里,但我可以告诉你我永远在Linux和MacOS上都没有这样的问题)。在最糟糕的情况下,如果你肯定你的“非英语”(非ascii真的)文件名是utf8,你可以尝试使用 file = file.decode('utf-8')来查看它是否更好但是仍然programming by accident

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

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

答案 1 :(得分:0)

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

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()