2013-05-19 11 views
9

Python 3. Używam widgetu pliku QT do zapisywania plików PDF pobranych z Internetu. Czytałem plik przy użyciu "otwartego" i próbuję go zapisać za pomocą widżetu okna pliku. Jednak korzystałem z "TypeError:" _io.BufferedReader "nie obsługuje interfejsu bufora" błąd.Python zapisujący pliki binarne, bajty

Przykładowy kod:

with open('file_to_read.pdf', 'rb') as f1: 
    with open('file_to_save.pdf', 'wb') as f2: 
     f2.write(f1) 

Ta logika działa prawidłowo z plikami tekstowymi, gdy nie jest używany „b” oznacznik lub podczas czytania pliku z sieci, jak z urllib lub żądań. Są one typu 'bytes', które, jak sądzę, muszę otwierać plik jako. Zamiast tego otwiera się jako buforowany czytnik. Próbowałem bajtów (f1), ale otrzymałem "TypeError:" obiektu bajtów "nie można interpretować jako liczby całkowitej." Jakieś pomysły?

+1

Po prostu spróbuj - 'data = lista (f1.read())' i 'f2.write (dane)' – karthikr

+0

'lista' ewidentnie nie obsługuje również interfejsu bufora. –

Odpowiedz

10

Jeśli zamiarem jest, aby po prostu zrobić kopię pliku, można użyć shutil

>>> import shutil 
>>> shutil.copyfile('file_to_read.pdf','file_to_save.pdf') 

Lub jeśli chcesz mieć dostęp bajt po bajcie, podobna do struktury, to działa:

>>> with open('/tmp/fin.pdf','rb') as f1: 
... with open('/tmp/test.pdf','wb') as f2: 
...  while True: 
...   b=f1.read(1) 
...   if b: 
...    # process b if this is your intent 
...    n=f2.write(b) 
...   else: break 

Ale bajt po bajcie jest potencjalnie bardzo wolny .

Albo, jeśli chcesz bufor, że będzie to przyspieszenie (bez podejmowania ryzyka czytanie nieznanego rozmiaru pliku całkowicie do pamięci):

>>> with open('/tmp/fin.pdf','rb') as f1: 
... with open('/tmp/test.pdf','wb') as f2: 
...  while True: 
...   buf=f1.read(1024) 
...   if buf: 
...    for byte in buf: 
...     pass # process the bytes if this is what you want 
...       # make sure your changes are in buf 
...    n=f2.write(buf) 
...   else: 
...    break 

z Python 2.7+ lub 3.1 i nowsze można również użyć ten skrót (zamiast używać dwóch with bloki):

with open('/tmp/fin.pdf','rb') as f1,open('/tmp/test.pdf','wb') as f2: 
    ... 
+0

Dziękuję - twoje drugie i trzecie rozwiązanie zadziałały. (Nie można użyć pliku kopii z powodu sposobu, w jaki działa okno dialogowe zapisywania QT). Po prostu używanie .read() na bufferedReaderze do konwersji na bajty również wydawało się działać - myślałem, że próbowałem tego. Nauczyłem się nowych rzeczy z twoich przykładów. –

+1

Uważaj, nazwa zmiennej 'bytes' może kolidować z wbudowanym w Python typem' bytes', który reprezentuje dane binarne w Pythonie 3.x! (W Pythonie 2.7 jest to po prostu alias 'str') – minmaxavg

+0

@minmaxavg: masz rację, a zmienię się, gdy dostanę szansę. Dzięki! – dawg

5

to naprawdę nie ma sensu pisać pliku w innym pliku. To, czego chcesz, to zapisać zawartość f1 na f2. Otrzymasz zawartość za pomocą f1.read(). Więc trzeba to zrobić:

with open('file_to_read.pdf', 'rb') as f1: 
    with open('file_to_save.pdf', 'wb') as f2: 
     f2.write(f1.read()) 
+0

Tak właśnie wygląda obecne rozwiązanie. –

+3

Podczas gdy to działa, cały plik jest wczytany do pamięci, zanim zostanie zapisany - niezbyt przyjazny dla pamięci. Jak stwierdzono w Pythonie [docs] (http://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects) "to twój problem, jeśli plik jest dwa razy większy niż pamięć twojego komputera ' –

2

wyciągnięte z python cookbook

from functools import partial 

with open(fpath, 'rb') as f, open(target_fpath, 'wb') as target_f: 
    for _bytes in iter(partial(f.read, 1024), ''): 
     target_f.write(_bytes) 

partial(f.read, 1024) zwraca funkcję, przeczytaj plik binarny 1024 bajtów na każdym kroku. iter zakończy się po spełnieniu blank string ''.

Powiązane problemy