Cách tải tài liệu trong C++
Aspose.PDF FOSS cho C++ mở một tệp PDF hiện có thông qua lớp Document — từ một đường dẫn tệp đơn giản, hoặc với mật khẩu khi nguồn được mã hoá — và cung cấp siêu dữ liệu /Info của tệp qua DocumentInfo. Hướng dẫn này đề cập đến việc tải tài liệu, phát hiện và mở các tệp được bảo vệ bằng mật khẩu, đọc và cập nhật siêu dữ liệu tiêu đề/tác giả/người sản xuất, và lưu kết quả. Thư viện được thêm vào dự án qua CMake; không có bước cài đặt qua trình quản lý gói.
Hướng dẫn từng bước
Bước 1: Cài đặt gói
Thêm thư viện như một thư mục con CMake và liên kết với mục tiêu aspose_pdf_foss:
add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)Xác minh toolchain và các header được giải quyết bằng cách biên dịch một chương trình tối thiểu:
#include <aspose/pdf/document.hpp>
#include <iostream>
int main() {
Aspose::Pdf::Document doc;
std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}Một bản build thành công in ra pages: 0 xác nhận thư viện đã được liên kết đúng.
Bước 2: Nhập các lớp cần thiết
#include <aspose/pdf/document.hpp>
#include <aspose/pdf/document_info.hpp>
using namespace Aspose::Pdf;Document và DocumentInfo đều được khai báo trực tiếp dưới không gian tên Aspose::Pdf.
Bước 3: Mở tài liệu PDF từ đường dẫn tệp
Constructor Document(filename) đọc tệp, phân tích bảng tham chiếu chéo và cây trang của nó, và xây dựng mô hình trong bộ nhớ. Nó ném std::system_error khi tệp không tồn tại hoặc không thể đọc được, và std::runtime_error khi tệp không phải là PDF hợp lệ:
#include <iostream>
#include <stdexcept>
try {
Document doc("input.pdf");
std::cout << "Pages: " << doc.Pages().Count() << "\n";
} catch (const std::runtime_error& e) {
std::cerr << "Not a valid PDF: " << e.what() << "\n";
} catch (const std::system_error& e) {
std::cerr << "Could not read file: " << e.what() << "\n";
}Bước 4: Mở tài liệu được bảo vệ bằng mật khẩu
Constructor một đối số từ Bước 3 không bao giờ xác thực mật khẩu hoặc kiểm tra mục /Encrypt của trailer, vì vậy IsEncrypted() trên tài liệu được mở theo cách đó luôn báo cáo false — ngay cả khi tệp nguồn thực sự đã được mã hoá. Để phát hiện và mở một PDF đã mã hoá, hãy sử dụng constructor hai đối số, nó đọc /Encrypt và xác thực mật khẩu bạn cung cấp:
try {
Document doc("input.pdf", "user-password");
if (doc.IsEncrypted()) {
std::cout << "Opened an encrypted document.\n";
}
} catch (const std::runtime_error& e) {
// Thrown when /Encrypt is present and the password matches
// neither the user nor the owner entry in the trailer.
std::cerr << "Wrong password or unreadable /Encrypt dictionary: "
<< e.what() << "\n";
}Nếu PDF nguồn không được mã hoá, đối số mật khẩu sẽ bị bỏ qua và tài liệu mở bình thường — vì vậy việc sử dụng constructor hai đối số vẫn an toàn ngay cả khi bạn không chắc tệp có được bảo vệ hay không.
Bước 5: Đọc siêu dữ liệu tài liệu bằng DocumentInfo
Document.Info() trả về một DocumentInfo& được liên kết với từ điển /Info của tài liệu. Mỗi trường được định nghĩa trước có accessor đọc riêng, trả về một chuỗi rỗng khi khóa không tồn tại trong tệp nguồn:
Document doc("input.pdf");
DocumentInfo& info = doc.Info();
std::cout << "Title: " << info.Title() << "\n";
std::cout << "Author: " << info.Author() << "\n";
std::cout << "Subject: " << info.Subject() << "\n";
std::cout << "Producer: " << info.Producer() << "\n";
std::cout << "Creator: " << info.Creator() << "\n";
std::cout << "Keywords: " << info.Keywords() << "\n";DocumentInfo::IsPredefinedKey báo cáo xem một tên khóa /Info cho trước có phải là một trong các trường tích hợp này hay không, thay vì một khóa tùy chỉnh được thêm bằng Add:
bool builtin = DocumentInfo::IsPredefinedKey("Title"); // true
bool custom = DocumentInfo::IsPredefinedKey("MyKey"); // false
Bước 6: Cập nhật siêu dữ liệu và lưu tài liệu
Đặt siêu dữ liệu thông qua các overload setter tương ứng, hoặc thông qua phương thức tiện lợi SetTitle trên Document, sau đó lưu lại thay đổi bằng Save:
Document doc("input.pdf");
doc.Info().Author("Report Generator");
doc.SetTitle("Quarterly Report"); // equivalent to doc.Info().Title(title)
doc.Save("output.pdf");Các chỉnh sửa siêu dữ liệu được đặt trong bộ nhớ và chỉ được ghi ra khi gọi Save tiếp theo. Gọi Save(outputFileName) để ghi vào một đường dẫn mới, hoặc Save() không đối số để ghi đè lên tệp mà tài liệu được mở ban đầu:
Document doc("input.pdf");
doc.SetTitle("Updated In Place");
doc.Save(); // writes back to "input.pdf"
Các vấn đề thường gặp và cách khắc phục
IsEncrypted() returns false cho một PDF tôi biết đã được bảo vệ bằng mật khẩu
Constructor Document(path) nhận một đối số duy nhất không bao giờ xác thực dựa trên từ điển /Encrypt của tệp, vì vậy IsEncrypted() luôn báo false trên tài liệu được mở theo cách này, bất kể nguồn có thực sự được mã hoá hay không. Hãy mở tệp bằng constructor Document(path, password) nhận hai đối số thay thế — đây là overload duy nhất thiết lập trạng thái mã hoá.
Phương thức khởi tạo có hai đối số ném ngoại lệ std::runtime_error
Điều này có nghĩa là PDF nguồn có một mục /Encrypt trong trailer và mật khẩu được cung cấp không khớp với mật khẩu người dùng cũng như mật khẩu chủ được ghi ở đó. Bắt std::runtime_error và yêu cầu người dùng nhập lại mật khẩu chính xác, hoặc xác nhận mật khẩu qua kênh khác trước khi thử lại.
Save() ném “no source filename to save to”
Constructor không đối số Save() ghi lại vào đường dẫn mà tài liệu được tạo ra từ đó. Một Document được tạo bằng constructor không đối số — một tài liệu mới, trong bộ nhớ, không có tệp nguồn — không có đường dẫn để ghi lại, vì vậy Save() ném ra lỗi. Hãy gọi Save(outputFileName) thay thế.
Decrypt() không có vẻ tạo ra tệp không được bảo vệ
Decrypt() xóa cờ IsEncrypted() trong bộ nhớ để các lần đọc tiếp theo xử lý tài liệu như văn bản thuần, nhưng trong phiên bản hiện tại nó không ghi lại từ điển /Encrypt của trailer hoặc mã hoá lại các chuỗi và luồng đã được mã hoá. Một lời gọi Save() sau Decrypt() vẫn ghi lại các byte gốc, bao gồm cả mã hoá ban đầu — phương pháp này vẫn chưa tạo ra bản sao văn bản thuần trên đĩa.
Tiêu đề/Tác giả/… in ra chuỗi rỗng
Các accessor DocumentInfo trả về một chuỗi trống, không phải lỗi, khi khóa /Info tương ứng không có trong PDF nguồn. Kết quả trống có nghĩa là trường chưa bao giờ được đặt trên tài liệu đó, không phải là việc đọc thất bại.
Câu hỏi thường gặp
Liệu Document(path) có hoạt động trên PDF được mã hoá không?
Nó thường phân tích cây trang mà không ném ngoại lệ, nhưng không bao giờ xác thực mật khẩu và luôn để IsEncrypted() ở false. Hãy sử dụng hàm khởi tạo hai đối số bất cứ khi nào nguồn có thể được mã hoá.
Có an toàn khi truyền mật khẩu cho Document(path, password) cho một tệp mà thực tế không được mã hoá không?
Có. Khi trailer không có mục /Encrypt, đối số mật khẩu sẽ bị bỏ qua và tài liệu sẽ mở theo cùng cách như khi sử dụng hàm khởi tạo một đối số.
Làm sao tôi có thể phân biệt khóa /Info tùy chỉnh với khóa tích hợp sẵn?
Gọi DocumentInfo::IsPredefinedKey(key) tĩnh. Nó trả về true cho Title, Author, Subject, Keywords, Creator, Producer, và Trapped, và false cho bất kỳ thứ gì khác.
Tôi có thể ghi đè lên tệp mà tôi vừa tải lên thay vì ghi vào một đường dẫn mới không?
Có — gọi Save() không đối số trên một Document được tạo từ đường dẫn tệp; nó sẽ ghi lại vào cùng một đường dẫn nguồn. Nó sẽ ném lỗi cho các tài liệu được tạo bằng bộ khởi tạo không đối số, những tài liệu không có đường dẫn nguồn.
Việc lưu sau khi Decrypt() có loại bỏ bảo vệ mật khẩu của PDF không?
Không, không có trong phiên bản hiện tại — xem phần Common Issues ở trên. Decrypt() chỉ ảnh hưởng tới trạng thái trong bộ nhớ được các trình đọc nội dung sử dụng; tệp được Save() ghi vẫn chứa từ điển /Encrypt gốc.