การจัดการเอกสาร

การจัดการเอกสาร

การจัดการเอกสาร

คลาส Document เป็นจุดเริ่มต้นสำหรับการดำเนินการเกือบทั้งหมดใน Aspose.PDF FOSS สำหรับ Python: การสร้าง PDF ใหม่, การโหลดไฟล์ที่มีอยู่, การแก้ไขหน้าของมัน, และการเขียนผลลัพธ์กลับออกไป คู่มือฉบับนี้จะพาคุณผ่านวงจรชีวิตของเอกสาร, การดำเนินการกับคอลเลกชันหน้า, การปรับประสิทธิภาพ, กระบวนการทำงานหลายไฟล์, การเข้ารหัส, และข้อยกเว้นที่คุณควรคาดว่าจะต้องจัดการ.


วงจรชีวิตของเอกสาร: สร้าง, เปิด, และบันทึก

Document() โดยไม่มีอาร์กิวเมนต์จะสร้างเอกสารว่างในหน่วยความจำ ส่งพาธไฟล์, bytes แบบดิบ, หรือสตรีมไบนารีที่อ่านได้ใด ๆ เป็นอาร์กิวเมนต์แรก (หรือเรียก load_from() อย่างชัดเจน) เพื่อโหลด PDF ที่มีอยู่แทน save() ยอมรับพาธหรือสตรีมไบนารีที่เขียนได้เช่น io.BytesIO.

from aspose_pdf import Document

# Create a new, empty document and add a blank page
doc = Document()
doc.pages.add()
doc.save("hello.pdf")

# Re-open it — a path, bytes, or a binary stream all work
reopened = Document("hello.pdf")
print(reopened.page_count)   # 1

# ...or load explicitly onto an existing instance
another = Document()
another.load_from("hello.pdf")

reopened.close()
another.dispose()
doc.dispose()

save() จะโยน FileExistsError หากพาธปลายทางมีอยู่แล้ว, ยกเว้นคุณส่ง overwrite=True. close() เป็นนามแฝงของ dispose(); ทั้งสองเป็นอิดีมพอตัน, ดังนั้นการเรียกใช้หลายครั้งจึงปลอดภัย.

มีเพียง PDF เท่านั้นที่ทำงานเป็นเป้าหมายการบันทึก — นี่คือฟังก์ชันหลักของไลบรารีที่ทำงานเต็มรูปแบบ การส่งค่าการส่งออกเช่น SaveFormat.PPTX หรือ DocFormat.HTML ไปยัง save() จะทำให้เกิด UnsupportedFeatureException แทนการเขียนไฟล์ที่มีชื่อไม่ถูกต้อง, ดังนั้นการส่งออกที่ล้มเหลวจะถูกแจ้งอย่างชัดเจนไม่ใช่เงียบ.


การจัดการคอลเลกชันหน้า

doc.pages คือ PageCollection. มันรองรับ len(), การวนซ้ำ, และการจัดทำดัชนีแบบ 0-based (doc.pages[0]), รวมถึง add(), insert(index, page), และ delete(index) สำหรับการแก้ไขเชิงโครงสร้าง. แต่ละ Page เปิดเผย index, rect (ซึ่งคือ MediaBox), และ rotation.

from aspose_pdf import Document

doc = Document()
doc.pages.add()            # page 0
doc.pages.add()            # page 1
doc.pages.insert(1, None)  # insert a blank page at index 1

print(doc.page_count)      # 3

first_page = doc.pages[0]
print(first_page.rect)     # (0, 0, 612, 792)

for page in doc.pages:
    print(page.index, page.rotation)

doc.pages.delete(1)        # remove the page we inserted
doc.save("pages_demo.pdf", overwrite=True)

pages.add(page=None) เพิ่มหน้าว่างเมื่อถูกเรียกโดยไม่มีอาร์กิวเมนต์. pages.insert() ปรับค่าดัชนีที่อยู่นอกช่วงให้เป็นตำแหน่งที่ใกล้ที่สุดที่เป็นค่าใช้ได้แทนการโยงข้อผิดพลาด.


การเพิ่มประสิทธิภาพและการบีบอัดเอกสาร

Document.optimize ทำการกำจัดสำเนาซ้ำของภาพ/สตรีม, garbage collection ของวัตถุที่ไม่ได้ใช้, และการบีบอัดสตรีมในคำสั่งเดียว. ส่งอ็อบเจกต์ OptimizationOptions เพื่อควบคุมเทคนิคที่ทำงาน; ไม่ส่งจะใช้โปรไฟล์ทำความสะอาดมาตรฐาน.

from aspose_pdf import Document, OptimizationOptions

doc = Document("large_report.pdf")

options = OptimizationOptions()
options.remove_unused_objects = True
options.link_duplicate_streams = True
options.image_compression_quality = 60
options.subset_fonts = True

doc.optimize(options)
doc.save("large_report_optimized.pdf", overwrite=True)

optimize_resources() เป็นนามแฝงของ optimize(). หากคุณต้องการเพียงการบีบอัดสตรีมโดยไม่มีขั้นตอนทำความสะอาดเชิงโครงสร้าง, เรียก doc.compress_streams() โดยตรง.


การผสาน, การแยก, และการแก้ไขไฟล์

สำหรับเอกสารที่คุณเปิดอยู่แล้ว, Document.merge() จะเพิ่มอ็อบเจกต์ Document อื่น ๆ ลงบนอ็อบเจกต์ปัจจุบัน:

from aspose_pdf import Document

base = Document("part1.pdf")
extra = Document("part2.pdf")

base.merge(extra)
base.save("combined.pdf", overwrite=True)

สำหรับเวิร์กโฟลว์แบบไฟล์ต่อไฟล์โดยไม่ต้องเปิด Document ด้วยตนเอง, ปลั๊กอิน low-code Merger และ Splitter จะรับอ็อบเจกต์ MergeOptions/SplitOptions ที่สร้างจากอินพุตและเอาต์พุตของ FileDataSource:

from aspose_pdf import Merger, MergeOptions, Splitter, SplitOptions, FileDataSource

# Merge two files into one
merge_options = MergeOptions()
merge_options.add_input(FileDataSource("part1.pdf"))
merge_options.add_input(FileDataSource("part2.pdf"))
merge_options.add_output(FileDataSource("combined.pdf"))
Merger().process(merge_options)

# Split the result into one file per page
split_options = SplitOptions()
split_options.add_input(FileDataSource("combined.pdf"))
split_options.add_output(FileDataSource("combined_page1.pdf"))
split_options.add_output(FileDataSource("combined_page2.pdf"))
Splitter().process(split_options)

PdfFileEditor มีชุดการดำเนินการเดียวกันเป็น facade ที่คืนค่า True/False แทนการโยนข้อยกเว้น ซึ่งสะดวกสำหรับสคริปต์แบบ batch:

from aspose_pdf import PdfFileEditor

with PdfFileEditor() as editor:
    ok = editor.concatenate(["part1.pdf", "part2.pdf"], "combined.pdf")
    if not ok:
        print("concatenate failed:", editor.last_exception)

    editor.extract("combined.pdf", "first_page_only.pdf", page_from=1, page_to=1)

PdfFileEditor.extract() and .insert() take นับจาก 1 หมายเลขหน้า, ไม่เหมือน PageCollectionใช้การจัดทำดัชนีเริ่มจาก 0 — ดู ปัญหาทั่วไป ด้านล่าง.


การเข้ารหัสและความปลอดภัยของเอกสาร

Document.encrypt(user_password, owner_password=None, permissions=-4) เข้ารหัสเอกสารในหน่วยความจำ; decrypt(password) และ change_passwords(old, new_user, new_owner=None) ย้อนหรือหมุนรหัสผ่าน. is_encrypted และ permissions รายงานสถานะปัจจุบัน.

from aspose_pdf import Document
from aspose_pdf.exceptions import PdfSecurityException

doc = Document()
doc.pages.add()
doc.encrypt("user-pass", "owner-pass", permissions=-4)
doc.save("secured.pdf", overwrite=True)

try:
    Document("secured.pdf", password="wrong-pass")
except PdfSecurityException as exc:
    print("could not open:", exc)

reopened = Document("secured.pdf", password="user-pass")
print(reopened.is_encrypted)   # True
reopened.decrypt("user-pass")
reopened.save("unsecured.pdf", overwrite=True)

การเปิดเอกสารที่เข้ารหัสโดยไม่มีรหัสผ่านหรือรหัสผ่านผิด จะโยน PdfSecurityException — ให้จับคลาสนี้ (จาก aspose_pdf.exceptions) แทนการสันนิษฐานว่าการโหลดจะสำเร็จเสมอ.


เมตาดาต้า, การตรวจสอบความถูกต้อง, และการจัดการข้อยกเว้น

เมตาดาต้าเอกสารอยู่บน doc.info (เป็น dict[str, str] ธรรมดา) และ doc.version / doc.id แสดงเวอร์ชันหัว PDF และตัวระบุไฟล์ส่วนท้าย. validate() (มีนามแฝงเป็น check()) รายงานความสมบูรณ์ของโครงสร้าง; repair() พยายามแก้ไขปัญหาทั่วไปเช่นรายการหน้าที่หายไปหรือ MediaBox ที่อยู่นอกช่วง.

from aspose_pdf import Document, PdfLoadLimits
from aspose_pdf.exceptions import AsposePdfException, PdfIOException

doc = Document()
doc.pages.add()
doc.info["Title"] = "Quarterly Report"
doc.info["Author"] = "Reporting Bot"
doc.save("report.pdf", overwrite=True)

# Load untrusted input under an explicit resource-limit policy
safe_limits = PdfLoadLimits(max_input_bytes=50 * 1024 * 1024, max_pages=1000)

try:
    untrusted = Document("incoming.pdf", limits=safe_limits)
    if not untrusted.validate():
        untrusted.repair()
except (AsposePdfException, PdfIOException) as exc:
    print("failed to process incoming.pdf:", exc)

PdfLoadLimits จำกัดหน่วยความจำและจำนวนอ็อบเจ็กต์สำหรับไฟล์ที่ไม่เชื่อถือ; เรียก PdfLoadLimits.unlimited() เพื่อปิดการใช้งานขีดจำกัดทั้งหมดเมื่อคุณเชื่อถือแหล่งที่มานั้นอย่างเต็มที่. AsposePdfException เป็นคลาสฐานของลำดับชั้นข้อยกเว้นทั้งหมด (รวมถึง PdfIOException และ PdfSecurityException) ดังนั้น except AsposePdfException เดียวสามารถจับข้อผิดพลาดใด ๆ ที่ไลบรารีโยนขึ้นมา.


เคล็ดลับและแนวทางปฏิบัติที่ดีที่สุด

  • ควรเรียก dispose() (หรือ close()) บน Document เมื่อคุณใช้เสร็จแล้ว, หรือใช้เป็นตัวแปรท้องถิ่นที่มีอายุสั้น — เอนจินจะเก็บเนื้อหาหน้าที่ถอดรหัสและรูปภาพไว้ในหน่วยความจำจนกว่าจะถูกทำลาย.
  • ส่ง overwrite=True ไปยัง save() เมื่อเขียนทับเส้นทางที่คุณได้สร้างไว้แล้วในรอบเดียวกัน; ค่าเริ่มต้นคือ False และจะทำให้เกิด FileExistsError.
  • ควรใช้ doc.optimize() ก่อนส่ง PDF ที่สร้างขึ้น — เป็นการเรียกเพียงครั้งเดียวที่ลบวัตถุที่ไม่ได้ใช้และบีบอัดสตรีม, และโดยทั่วไปจะทำให้ขนาดผลลัพธ์ลดลงอย่างเห็นได้ชัด.
  • กำหนดนโยบาย PdfLoadLimits อย่างชัดเจนทุกครั้งที่คุณโหลด PDF จากแหล่งที่ไม่ได้รับความเชื่อถือ (การอัปโหลด, ไฟล์แนบอีเมล, การดึงข้อมูลเว็บ); ค่าเริ่มต้นนั้นใจกว้างแต่มีขีดจำกัด, ไม่ใช่เส้นแบ่งความปลอดภัยที่คุณควรพึ่งพาโดยไม่ตรวจสอบ.
  • ดักจับ AsposePdfException (หรือซับคลาสเฉพาะเช่น PdfSecurityException) รอบการเรียกโหลด/บันทึกแทนการใช้ Exception อย่างเปล่า — มันเป็นฐานร่วมสำหรับข้อผิดพลาดทุกประเภทที่ไลบรารีโยนขึ้น.

ปัญหาทั่วไป

ปัญหาสาเหตุวิธีแก้
FileExistsError บน save()เส้นทางปลายทางมีอยู่แล้วและ overwrite ถูกทิ้งไว้ที่ค่าเริ่มต้น Falseผ่าน save(path, overwrite=True)
UnsupportedFeatureException บน save()มีการร้องขอ save_format ที่ไม่ใช่ PDF (เช่น SaveFormat.PPTX, DocFormat.HTML)บันทึกเป็น PDF — ค่าของ SaveFormat/DocFormat ใด ๆ ที่ไม่ใช่จะทำให้เกิด UnsupportedFeatureException แทนการเขียนผลลัพธ์
PdfSecurityException: Password required for encrypted documentเปิด PDF ที่เข้ารหัสโดยไม่มีอาร์กิวเมนต์ passwordส่ง Document(path, password="...") หรือเรียก load_from(path, password="...")
จำนวนหน้าผิดหนึ่งระหว่าง PageCollection และ PdfFileEditordoc.pages[i] ใช้ตำแหน่งเริ่มจาก 0; อาร์กิวเมนต์หน้า PdfFileEditor.extract()/.insert() ใช้ตำแหน่งเริ่มจาก 1เพิ่มหรือลบ 1 เมื่อแปลงระหว่าง API ทั้งสอง
IndexError: Page index out of range. จาก pages.delete()ดัชนีที่ส่งให้ delete() ไม่มีอยู่ในคอลเลกชันตรวจสอบ doc.page_count (หรือ len(doc.pages)) ก่อนทำการลบ

FAQ

ฉันต้องการใบอนุญาตเพื่อใช้ Aspose.PDF FOSS สำหรับ Python หรือไม่?

ไม่. นี่เป็นรุ่นโอเพนซอร์ส (ได้รับใบอนุญาตแบบ MIT); ไม่มีไฟล์ใบอนุญาตหรือขั้นตอนการเปิดใช้งานที่ต้องกำหนดค่า.

ฉันสามารถส่งออก Document ไปยังรูปแบบอื่นนอกจาก PDF ได้หรือไม่?

ไม่มีในรุ่นนี้. save() รองรับการออกผลเป็น PDF เท่านั้น — การส่งค่า SaveFormat/DocFormat อื่นจะทำให้เกิด UnsupportedFeatureException แทนการสร้างไฟล์ที่มีชื่อไม่ตรง.

ความแตกต่างระหว่าง Document.merge() กับปลั๊กอิน Merger คืออะไร?

Document.merge() รวมเอาอินสแตนซ์ของ Document ที่คุณเปิดอยู่ในหน่วยความจำแล้ว. Merger (พร้อมกับ MergeOptions และ FileDataSource) เป็น wrapper สะดวกแบบไฟล์ต่อไฟล์ที่เปิด, ผสานและบันทึกให้คุณในหนึ่งคำสั่ง — มีประโยชน์สำหรับสคริปต์แบทช์ง่าย ๆ ที่ไม่ต้องการอ็อบเจกต์ Document ระหว่างขั้นตอน.

ทำไม pages.insert() ไม่เคยยกข้อยกเว้นสำหรับดัชนีที่อยู่นอกช่วง?

PageCollection.insert() จำกัดดัชนีให้อยู่ในช่วงที่ถูกต้อง (ค่าติดลบจะกลายเป็น 0, ค่าที่เกินจากจุดสิ้นสุดจะกลายเป็น len(doc.pages)) แทนการยกข้อยกเว้น, ดังนั้นการแทรกจะไม่มีการล้มเหลวเพียงเพราะค่าดัชนีเท่านั้น.

ฉันจะโหลดไฟล์ PDF จากแหล่งที่ไม่เชื่อถือได้อย่างปลอดภัยได้อย่างไร?

สร้าง PdfLoadLimits ที่มีการกำหนดขีดจำกัดที่ชัดเจน (max_input_bytes, max_pages, max_objects ฯลฯ) แล้วส่งเป็นอาร์กิวเมนต์ limits= ให้กับ Document(...) หรือ load_from(). แต่ละฟิลด์มีค่าเริ่มต้นเป็นค่าที่จำกัดอยู่แล้ว แต่การทำให้ขนาดแคบลงตามขนาดอินพุตที่คาดหวังของคุณจะลดทรัพยากรที่ไฟล์ที่ผิดรูปแบบสามารถใช้ได้.


API Reference สรุป

คลาส / เมธอดคำอธิบาย
Document() / Document.load_fromสร้างเอกสารเปล่าหรือโหลดจากเส้นทาง, ไบต์ หรือสตรีมไบนารี
Document.saveเขียนเอกสารไปยังเส้นทางหรือสตรีมที่สามารถเขียนได้ (PDF เท่านั้น)
Document.dispose() / Document.close()ปล่อยทรัพยากรของเอนจิน; idempotent
Document.pagesPageCollection ของเอกสาร
Document.infoเมตาดาต้าเอกสารเป็น dict[str, str]
Document.optimize / Document.optimize_resources / Document.compress_streams()ลบทรัพยากรที่ไม่ได้ใช้และบีบอัดสตรีม
Document.merge()ต่อท้ายอินสแตนซ์ Document อื่น ๆ กับอันนี้
Document.encrypt / Document.decrypt / Document.change_passwordsใช้, ลบ หรือหมุนรหัสผ่านเอกสาร
Document.validate() / Document.check() / Document.repair()ตรวจสอบและพยายามแก้ไขความสมบูรณ์ของโครงสร้าง
PageCollection.add() / .insert() / .delete() / .item()การแก้ไขการรวบรวมหน้าตามโครงสร้าง (เริ่มจากศูนย์)
Page.rect / Page.rotation / Page.indexเรขาคณิตและตำแหน่งต่อหน้า
OptimizationOptionsแฟล็กละเอียดระดับย่อยที่ใช้โดย Document.optimize
MergeOptions / Mergerปลั๊กอินรวมไฟล์ต่อไฟล์
SplitOptions / Splitterปลั๊กอินแยกไฟล์ต่อไฟล์ หนึ่งหน้าต่อผลลัพธ์
FileDataSourceอินพุต/เอาต์พุตแบบอ้างอิงไฟล์สำหรับ API ของปลั๊กอิน
PdfFileEditorFacade สำหรับ concatenate(), extract(), insert(), delete(), append() (หน้าเริ่มต้นที่ 1)
PdfLoadLimitsนโยบายข้อจำกัดทรัพยากรแบบคงที่สำหรับข้อมูลที่ไม่เชื่อถือ
AsposePdfExceptionคลาสฐานสำหรับข้อยกเว้นทั้งหมดที่ไลบรารียกขึ้น
PdfSecurityExceptionถูกยกขึ้นเมื่อรหัสผ่านหายหรือไม่ถูกต้องและเกิดข้อผิดพลาดด้านสิทธิ์
PdfIOExceptionถูกยกขึ้นเมื่อเกิดข้อผิดพลาด I/O ระหว่างการประมวลผล PDF

ดูเพิ่มเติม

 ภาษาไทย