Python'da UTF-8 dosyasına yaz


205

İle gerçekten kafam karıştı codecs.open function. Ben yaparken:

file = codecs.open("temp", "w", "utf-8")
file.write(codecs.BOM_UTF8)
file.close()

Bana hata veriyor

UnicodeDecodeError: 'ascii' codec bileşeni 0 konumunda bayt 0xef kodunun kodunu çözemiyor: sıra değeri aralıkta değil (128)

Eğer yaparsam:

file = open("temp", "w")
file.write(codecs.BOM_UTF8)
file.close()

İyi çalışıyor.

Soru , ilk yöntem neden başarısız oluyor? Ve bomba nasıl yerleştirilir?

İkinci yöntem bunu yapmanın doğru yoluysa, ne kullanıyorsunuz codecs.open(filename, "w", "utf-8")?


55
UTF-8'de ürün ağacı kullanmayın. Lütfen.
tchrist

7
@tchrist Huh? Neden olmasın?
Salman von Abbas

8
@SalmanPK BOM, UTF-8'de gerekli değildir ve yalnızca karmaşıklık katar (örneğin, BOM'd dosyalarını birleştirip geçerli metinle sonuçlandıramazsınız). Bu Soru ve Cevaplara bakın ; Q
Alois Mahdal

Yanıtlar:


272

Sorunun codecs.BOM_UTF8bir bayt dizesi, bir Unicode dizesi olduğuna inanıyorum . Dosya işleyicisinin "Unicode'u UTF-8 kodlu metin olarak yazmayı amaçladım, ancak bana bir bayt dizesi verdiniz!"

Doğrudan bayt sırası işareti (yani Unicode U + FEFF) için Unicode dizesini yazmayı deneyin, böylece dosya bunu UTF-8 olarak kodlar:

import codecs

file = codecs.open("lol", "w", "utf-8")
file.write(u'\ufeff')
file.close()

(Bu doğru cevabı veriyor gibi görünüyor - bayt EF BB BF içeren bir dosya.)

EDIT: S. Lott kodlama olarak "utf-8-sig" kullanma önerisi açıkça BOM kendiniz yazmak daha iyidir, ama ben daha önce neyin yanlış gittiğini açıklar gibi bu cevap burada bırakacağım.


Uyarı: açık ve açık aynı değil. Eğer "codec bileşenlerinden import open" yaparsanız, sadece "open" yazacağınız gibi DEĞİLDİR.
Apache

2
bunun yerine codecs.open ('test.txt', 'w', 'utf-8-sig') kullanabilirsiniz
beta kapalı

1
"TypeError: tamsayı gerekli (str türü var)" alıyorum. Burada ne yaptığımızı anlamıyorum. Birisi lütfen yardım edebilir mi? Bir metin dosyasına bir dize (paragraf) eklemeniz gerekir. Yazmadan önce bunu bir tam sayıya dönüştürmem gerekir mi?
Mugen

@Mugen: Yazdığım kod tam olarak görebildiğim kadar iyi çalışıyor. Tam olarak hangi koda sahip olduğunuzu ve hatanın nerede oluştuğunu gösteren yeni bir soru sormanızı öneririm .
Jon Skeet

@Mugen codecs.opensadece yerine çağırmalısınopen
northben

179

Aşağıdakileri okuyun: http://docs.python.org/library/codecs.html#module-encodings.utf_8_sig

Bunu yap

with codecs.open("test_output", "w", "utf-8-sig") as temp:
    temp.write("hi mom\n")
    temp.write(u"This has ♭")

Ortaya çıkan dosya beklenen BOM ile UTF-8'dir.


2
Teşekkürler. Bu işe yaradı (Windows 7 x64, Python 2.7.5 x64). Bu çözüm, dosyayı "a" (append) modunda açtığınızda iyi çalışır.
Mohamad Fakih

Bu benim için işe yaramadı, Windows'ta Python 3. Bunun yerine bomfile: bomfile.write (codecs.BOM_UTF8) olarak open (dosya_adı, 'wb') ile yapmak zorunda kaldım sonra dosyayı eklemek için yeniden açın.
Dustin Andrews

Belki ekleyin temp.close()?
user2905353

2
@ user2905353: gerekli değil; Bu tarafından işlenir bağlam yönetiminin ait open.
matheburg

11

@ S-Lott doğru prosedürü verir, ancak Unicode konularını genişleterek Python yorumlayıcısı daha fazla bilgi sağlayabilir.

Jon Skeet codecsmodül hakkında doğru (olağandışı) - bayt dizeleri içeriyor:

>>> import codecs
>>> codecs.BOM
'\xff\xfe'
>>> codecs.BOM_UTF8
'\xef\xbb\xbf'
>>> 

Başka bir nit seçildiğinde, BOMstandart bir Unicode adı vardır ve şu şekilde girilebilir:

>>> bom= u"\N{ZERO WIDTH NO-BREAK SPACE}"
>>> bom
u'\ufeff'

Ayrıca şunlara da erişilebilir unicodedata:

>>> import unicodedata
>>> unicodedata.lookup('ZERO WIDTH NO-BREAK SPACE')
u'\ufeff'
>>> 

8

Bir utf-8 dosyasında bilinmeyen bir charset dosyasını dönüştürmek için * nix komutunu kullanıyorum

# -*- encoding: utf-8 -*-

# converting a unknown formatting file in utf-8

import codecs
import commands

file_location = "jumper.sub"
file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location)

file_stream = codecs.open(file_location, 'r', file_encoding)
file_output = codecs.open(file_location+"b", 'w', 'utf-8')

for l in file_stream:
    file_output.write(l)

file_stream.close()
file_output.close()

1
Hatırlamak çok daha kolay olan # coding: utf8yerine kullanın # -*- coding: utf-8 -*-.
show0k
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.