2008-10-10 14 views

Odpowiedz

44

Można użyć codecs module coś takiego:

import codecs 
BLOCKSIZE = 1048576 # or some other, desired size in bytes 
with codecs.open(sourceFileName, "r", "your-source-encoding") as sourceFile: 
    with codecs.open(targetFileName, "w", "utf-8") as targetFile: 
     while True: 
      contents = sourceFile.read(BLOCKSIZE) 
      if not contents: 
       break 
      targetFile.write(contents) 

EDIT: dodano BLOCKSIZE parametr kontrolowania plików wielkość porcji.

+3

read() zawsze czyta cały plik - prawdopodobnie potrzebujesz .read (BLOCKSIZE), gdzie BLOCKSIZE to odpowiednia ilość do odczytu/zapisu na raz. – Brian

+1

To prawda, dziękuję. Zmodyfikuję mój przykład. – DzinX

25

ten pracował dla mnie w małym teście:

sourceEncoding = "iso-8859-1" 
targetEncoding = "utf-8" 
source = open("source") 
target = open("target", "w") 

target.write(unicode(source.read(), sourceEncoding).encode(targetEncoding)) 
+0

Jeszcze lepiej byłoby określić tryb binarny. – Arafangion

+0

@Arafangion Dlaczego tryb binarny byłby lepszy? Dzięki! –

+0

@ Honghe.Wu: W oknach tryb tekstowy jest domyślny, co oznacza, że ​​twoje zakończenia linii zostaną zniekształcone przez system operacyjny, czego nie chcesz, jeśli nie masz pewności co do kodowania na dysku. – Arafangion

12

Dzięki za odpowiedzi, to działa!

A ponieważ pliki źródłowe są w mieszanych formatach, dodałem listę formatów źródłowych być sądzony w sekwencji (sourceFormats), a na UnicodeDecodeError próbuję kolejny format:

from __future__ import with_statement 

import os 
import sys 
import codecs 
from chardet.universaldetector import UniversalDetector 

targetFormat = 'utf-8' 
outputDir = 'converted' 
detector = UniversalDetector() 

def get_encoding_type(current_file): 
    detector.reset() 
    for line in file(current_file): 
     detector.feed(line) 
     if detector.done: break 
    detector.close() 
    return detector.result['encoding'] 

def convertFileBestGuess(filename): 
    sourceFormats = ['ascii', 'iso-8859-1'] 
    for format in sourceFormats: 
    try: 
     with codecs.open(fileName, 'rU', format) as sourceFile: 
      writeConversion(sourceFile) 
      print('Done.') 
      return 
     except UnicodeDecodeError: 
     pass 

def convertFileWithDetection(fileName): 
    print("Converting '" + fileName + "'...") 
    format=get_encoding_type(fileName) 
    try: 
     with codecs.open(fileName, 'rU', format) as sourceFile: 
      writeConversion(sourceFile) 
      print('Done.') 
      return 
    except UnicodeDecodeError: 
     pass 

    print("Error: failed to convert '" + fileName + "'.") 


def writeConversion(file): 
    with codecs.open(outputDir + '/' + fileName, 'w', targetFormat) as targetFile: 
     for line in file: 
      targetFile.write(line) 

# Off topic: get the file list and call convertFile on each file 
# ... 

(Edycja przez Rudro Badhon: zawiera oryginalną próbkę wielu formatów, dopóki nie otrzymasz wyjątku, a także alternatywne podejście, które używa chardet.universaldetector)

+0

W trudnych przypadkach możesz spróbować wykryć kodowanie za pomocą modułu chardet z feedparser.org, ale w twoim przypadku jest to przesada. – itsadok

+0

Mój Python 3.5 nie rozpoznaje funkcji 'plik'. Skąd to pochodzi? – physicalattraction

+0

Tak, ta odpowiedź została wysłana 8 lat temu, więc jest to fragment starego kodu Pythona 2. –

0

Aby odgadnąć, jakie jest kodowanie źródłowe, możesz użyć polecenia nix file *.

przykład:

$ file --mime jumper.xml 

jumper.xml: application/xml; charset=utf-8 
+0

Nie odpowiada na pytanie. –

0

To Python3 funkcja konwersji każdy plik tekstowy do jednego z UTF-8. (bez użycia niepotrzebnych paczek)

def correctSubtitleEncoding(filename, newFilename, encoding_from, encoding_to='UTF-8'): 
    with open(filename, 'r', encoding=encoding_from) as fr: 
     with open(newFilename, 'w', encoding=encoding_to) as fw: 
      for line in fr: 
       fw.write(line[:-1]+'\r\n') 

Możesz go łatwo użyć w pętli do konwertowania listy plików.

Powiązane problemy