Luồng và Tệp Đính Kèm
Luồng và Tệp Đính Kèm
Ngoài các bản tải trọng cơ bản Document.Open/Document.Save, Aspose.PDF FOSS cho .NET cung cấp cho bạn khả năng kiểm soát chi tiết hơn cách các byte di chuyển vào và ra tài liệu – các bộ đệm trong bộ nhớ có thể mở rộng cho các tệp rất lớn, và một API chuyên dụng để nhúng, kiểm tra và trích xuất các tệp đính kèm thông qua FileSpecification và EmbeddedFileCollection.
Mở rộng bộ đệm trong bộ nhớ vượt quá 2 GB
MemoryStream lưu trữ dữ liệu của nó trong một mảng liên tục duy nhất, giới hạn gần 2 GB. OptimizedMemoryStream lưu trữ dữ liệu thành các khối có kích thước cố định, vì vậy nó có thể chứa các tài liệu lớn hơn rất nhiều khi bạn lưu hoặc xây dựng PDF hoàn toàn trong bộ nhớ.
using Aspose.Pdf;
using var doc = Document.Open("large-input.pdf");
using var buffer = new OptimizedMemoryStream();
doc.Save(buffer);
buffer.Seek(0, SeekOrigin.Begin);
byte[] allBytes = buffer.ToArray();
Console.WriteLine($"Buffer length: {buffer.Length}");Bạn cũng có thể ghi trực tiếp vào nó, giống như cách bạn làm với bất kỳ Stream nào:
using var buffer = new OptimizedMemoryStream();
byte[] chunk = System.Text.Encoding.UTF8.GetBytes("raw content chunk");
buffer.Write(chunk, 0, chunk.Length);
buffer.WriteByte(0x0A);
buffer.SetLength(buffer.Length);Nhúng tệp trực tiếp từ một luồng
FileSpecification có thể bao bọc một Stream thay vì yêu cầu bạn phải lưu trữ tạm tệp đính kèm vào một byte[] trước. Điều này hữu ích khi nguồn tệp đính kèm tự nó là một luồng, chẳng hạn như một trình xử lý tệp mở.
using Aspose.Pdf;
using var doc = Document.Open("input.pdf");
using var attachmentStream = File.OpenRead("report.csv");
using var spec = new FileSpecification(attachmentStream, "report.csv", "Quarterly report data");
spec.MimeType = "text/csv";
spec.AFRelationship = AFRelationship.Data;
spec.Encoding = FileEncoding.Zip;
doc.EmbeddedFiles.Add(spec);
doc.Save("with-attachment.pdf");Nhúng một tệp từ byte thô
Document.AddEmbeddedFile là một phương thức tiện lợi để nhúng tệp trực tiếp từ một mảng byte, mà không cần tạo một FileSpecification một cách trực tiếp.
using Aspose.Pdf;
using var doc = Document.Open("input.pdf");
byte[] fileData = File.ReadAllBytes("appendix.docx");
doc.AddEmbeddedFile(
"appendix.docx",
fileData,
"Supporting appendix",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
true,
DateTime.Now,
DateTime.Now);
doc.Save("with-appendix.pdf");Liệt kê và trích xuất các tệp được nhúng
Document.EmbeddedFiles là một EmbeddedFileCollection mà bạn có thể liệt kê. Mỗi mục là một FileSpecification, và GetData() trả về các byte thô của tệp đính kèm.
using Aspose.Pdf;
using var doc = Document.Open("with-attachment.pdf");
if (doc.HasEmbeddedFiles)
{
foreach (FileSpecification file in doc.EmbeddedFiles)
{
Console.WriteLine($"{file.Name} ({file.Size} bytes, {file.MimeType})");
byte[] contents = file.GetData();
File.WriteAllBytes(file.Name, contents);
}
}Tìm kiếm, kiểm tra và xóa các tệp đính kèm
Sử dụng FindByName để tra cứu một tệp đính kèm duy nhất, Params để đọc siêu dữ liệu của nó, và Delete/DeleteByKey để xóa nó.
using Aspose.Pdf;
using var doc = Document.Open("with-attachment.pdf");
FileSpecification? found = doc.EmbeddedFiles.FindByName("report.csv");
if (found?.Params is FileParams info)
{
Console.WriteLine($"{found.Name}: {info.Size} bytes, checksum {info.CheckSum}, modified {info.ModDate}");
}
doc.EmbeddedFiles.Delete("report.csv");
Console.WriteLine($"Remaining attachments: {doc.EmbeddedFiles.Count}");
doc.Save("cleaned.pdf");Mẹo và Thực hành Tốt nhất
- Ưu tiên
OptimizedMemoryStreamhơnMemoryStreambất cứ khi nào tài liệu trong bộ nhớ có thể vượt quá 2 GB —MemoryStreamsẽ ném ngoại lệ khi mảng nền duy nhất của nó đạt tới giới hạn đó. - Giải phóng các đối tượng
FileSpecification(và bất kỳ luồng nào bạn đã mở thủ công cho chúng) –FileSpecificationthực thiIDisposable. - Kiểm tra
Document.HasEmbeddedFilestrước khi lặp quaEmbeddedFilesđể bỏ qua việc liệt kê không cần thiết trên các tài liệu không có tệp đính kèm. - Đặt
MimeTypevàAFRelationshiptrên mỗiFileSpecificationđể các trình tiêu thụ PDF ở phía sau có thể phân loại tệp đính kèm một cách chính xác. - Sử dụng
EmbeddedFileCollection.FindByNameđể tra cứu theo tên duy nhất thay vì viết một vòng lặp thủ công.
Các vấn đề thường gặp
| Vấn đề | Nguyên nhân | Cách khắc phục |
|---|---|---|
OutOfMemoryException lưu một tài liệu lớn vào luồng | MemoryStream bị giới hạn ở một mảng nền duy nhất ~2 GB | Thay vào đó, lưu vào OptimizedMemoryStream |
FileSpecification.GetData() trả về một mảng rỗng | Vị trí luồng nguồn chưa được đặt lại trước khi tạo FileSpecification | Di chuyển con trỏ luồng đến vị trí 0 (hoặc mở lại) trước khi truyền nó cho FileSpecification |
EmbeddedFiles.FindByName trả về null | Tên tệp đính kèm không khớp chính xác (tìm kiếm dựa trên tên) | Lặp qua doc.EmbeddedFiles và so sánh các giá trị Name, hoặc kiểm tra Keys |
| Xóa một tệp đính kèm sẽ xóa mục sai | Nhiều tệp đính kèm có cùng tên | Sử dụng DeleteByKey với khóa chính xác từ Keys để xóa bỏ một cách không gây nhầm lẫn |
FAQ
Sự khác biệt giữa MemoryStream và OptimizedMemoryStream là gì?
MemoryStream lưu trữ các byte của nó trong một mảng liên tục có giới hạn gần 2 GB. OptimizedMemoryStream lưu trữ dữ liệu thành các khối có kích thước cố định, vì vậy nó có thể mở rộng vượt qua giới hạn đó – hữu ích cho các thao tác Document.Save được thực hiện hoàn toàn trong bộ nhớ trên các tệp rất lớn.
Tôi có thể nhúng một tệp mà không cần tải nó vào một byte[] trước không?
Có. FileSpecification(stream, name, description) chấp nhận một Stream trực tiếp, vì vậy bạn có thể nhúng từ File.OpenRead(...) hoặc bất kỳ luồng nào khác mà không cần tự đệm nó vào bộ nhớ.
Làm sao tôi có thể lấy lại tệp đã nhúng từ tài liệu?
Duyệt doc.EmbeddedFiles và gọi GetData() trên mỗi FileSpecification để lấy các byte thô.
Liệu EmbeddedFileCollection.Delete(name) có xóa mọi tệp đính kèm có tên đó không?
Không — hãy nhắm chính xác một tệp đính kèm bằng DeleteByKey và khóa cụ thể từ Keys nếu có nhiều tệp đính kèm cùng tên.
Liệu FileSpecification có an toàn để tái sử dụng trên nhiều tài liệu không?
Không. FileSpecification triển khai IDisposable và bao bọc một luồng tệp đã nhúng duy nhất; hãy tạo một thể hiện mới cho mỗi tệp đính kèm trong mỗi tài liệu.
API Reference Tóm tắt
| Lớp / Phương thức | Mô tả |
|---|---|
OptimizedMemoryStream | Luồng bộ nhớ trong có khả năng mở rộng vượt quá giới hạn 2 GB của MemoryStream |
OptimizedMemoryStream.Write | Ghi các byte vào bộ đệm |
OptimizedMemoryStream.ToArray | Trả về các byte đã được đệm dưới dạng mảng byte |
FileSpecification | Mô tả tệp đính kèm nhúng, được hỗ trợ bởi một luồng hoặc dữ liệu byte |
FileSpecification.GetData | Lấy các byte thô của tệp nhúng |
FileSpecification.Params | Siêu dữ liệu (kích thước, checksum, ngày) cho tệp nhúng |
EmbeddedFileCollection | Bộ sưu tập các tệp đính kèm FileSpecification trên một Document |
EmbeddedFileCollection.FindByName | Tra cứu tệp đính kèm theo tên |
EmbeddedFileCollection.Delete | Xóa tệp đính kèm theo tên |
Document.AddEmbeddedFile | Phương thức tiện lợi để nhúng tệp từ dữ liệu thô |
Document.EmbeddedFiles | Bộ sưu tập tệp nhúng của tài liệu |
Document.HasEmbeddedFiles | Xác định xem tài liệu có chứa bất kỳ tệp nhúng nào hay không |
FileParams | Bao bọc siêu dữ liệu kích thước/mã kiểm tra/ngày cho luồng tệp được nhúng |