2013-05-19 54 views
9

Python 3. Tôi đang sử dụng tiện ích hộp thoại tệp của QT để lưu các tệp PDF được tải xuống từ internet. Tôi đã đọc các tập tin bằng cách sử dụng 'mở', và cố gắng để viết nó bằng cách sử dụng tiện ích hộp thoại tập tin. Tuy nhiên, tôi đã chạy vào một lỗi "TypeError: '_io.BufferedReader' không hỗ trợ giao diện bộ đệm" lỗi.Python viết các tệp nhị phân, byte

Ví dụ mã:

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

Logic này hoạt động đúng với các tập tin văn bản khi không sử dụng 'b' vấn thiết kế, hoặc khi đọc một tập tin từ trang web, giống như với urllib hoặc yêu cầu. Đây là những loại 'byte', mà tôi nghĩ rằng tôi cần phải được mở tập tin như. Thay vào đó, nó mở ra như một Buffered Reader. Tôi đã thử byte (f1), nhưng nhận được "TypeError: 'byte' đối tượng không thể được hiểu là một số nguyên." Bất kỳ ý tưởng nào?

+1

Chỉ cần thử - 'data = list (f1.read())' và 'f2.write (dữ liệu)' – karthikr

+0

'list' rõ ràng không hỗ trợ giao diện bộ đệm. –

Trả lời

10

Nếu ý định của bạn là chỉ cần tạo một bản sao của tập tin, bạn có thể sử dụng shutil

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

Hoặc nếu bạn cần truy cập byte bởi byte, tương tự như cấu trúc của bạn, công trình này:

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

Nhưng byte theo byte có khả năng là thực sự chậm.

Hoặc, nếu bạn muốn có một bộ đệm đó sẽ tăng tốc độ này lên (không có việc rủi ro của việc đọc một kích thước tập tin không rõ hoàn toàn vào bộ nhớ):

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

Với Python 2.7+ hoặc 3.1+ bạn cũng có thể sử dụng lối tắt này (thay vì sử dụng hai khối with):

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

Cảm ơn bạn - giải pháp thứ 2 và thứ 3 của bạn đều hoạt động. (Không thể sử dụng copyfile do cách hộp thoại lưu của QT hoạt động) Đơn giản chỉ cần sử dụng .read() trên bufferedReader để chuyển đổi thành byte dường như hoạt động tốt - nghĩ rằng tôi đã thử điều đó. Đã học một số nội dung mới từ ví dụ của bạn. –

+1

Hãy cẩn thận, tên biến 'byte' có thể va chạm với loại được xây dựng trong Python' byte' đại diện cho dữ liệu nhị phân trong Python 3.x! (Trong Python 2.7 nó chỉ là một bí danh của 'str') – minmaxavg

+0

@minmaxavg: bạn nói đúng, và tôi sẽ thay đổi khi tôi có cơ hội. Cảm ơn! – dawg

5

Thực sự không có ý nghĩa khi viết tệp trong một tệp khác. Những gì bạn muốn là viết nội dung của f1 trong f2. Bạn nhận được nội dung với f1.read(). Vì vậy, bạn phải làm điều này:

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

Đây là giải pháp hiện tại. –

+3

Trong khi tác phẩm này, toàn bộ tệp được đọc vào bộ nhớ trước khi được viết - không phải là rất thân thiện với bộ nhớ. Như đã nêu trong Python [docs] (http://docs.python.org/2/tutorial/inputoutput.html#methods-of-file-objects) 'đó là vấn đề của bạn nếu tệp lớn gấp đôi bộ nhớ của máy tính của bạn ' –

2

học được từ 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) trả về một chức năng, đọc các tập tin nhị phân 1024 byte ở mỗi lượt. iter sẽ kết thúc khi gặp số blank string ''.

Các vấn đề liên quan