Потоки та вкладення файлів
Потоки та файлові вкладення
Поза базовими Document.Open/Document.Save перевантаженнями, Aspose.PDF FOSS для .NET дає вам більш точний контроль над тим, як байти переміщуються в документ і з нього – розширювані буфери в пам’яті для дуже великих файлів, і спеціальний API для вбудовування, перегляду та вилучення файлових вкладень через FileSpecification і EmbeddedFileCollection.
Розширення буферів у пам’яті понад 2 GB
MemoryStream зберігає свої дані в одному безперервному масиві, який обмежується приблизно 2 GB. OptimizedMemoryStream зберігає дані у фіксованих блоках, тому може вміщувати значно більші документи, коли ви зберігаєте або створюєте PDF повністю в пам’яті.
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}");Ви також можете записувати в нього безпосередньо, так само, як би це робили з будь-яким Stream:
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);Вбудовування файлу безпосередньо з потоку
FileSpecification може обгорнути Stream замість того, щоб вимагати попереднє буферизування вкладення у byte[]. Це корисно, коли джерело вкладення саме є потоком, наприклад відкритим файловим дескриптором.
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");Вбудовування файлу з необроблених байтів
Document.AddEmbeddedFile — це зручний метод для вбудовування файлу безпосередньо з масиву байтів, без прямого створення FileSpecification.
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");Перерахування та витягування вбудованих файлів
Document.EmbeddedFiles — це EmbeddedFileCollection, який можна перераховувати. Кожен запис є FileSpecification, а GetData() повертає необроблені байти вкладення.
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);
}
}Пошук, перегляд та видалення вкладень
Використовуйте FindByName для пошуку окремого вкладення, Params — для читання його метаданих, а Delete/DeleteByKey — для його видалення.
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");Поради та найкращі практики
- Віддавайте перевагу
OptimizedMemoryStreamзамістьMemoryStream, коли в пам’яті документ може перевищити 2 ГБ —MemoryStreamвикидає виключення, як тільки його єдиний бекінговий масив досягає цього ліміту. - Звільніть екземпляри
FileSpecification(і будь-який потік, який ви відкривали вручну для них) —FileSpecificationреалізуєIDisposable. - Перевірте
Document.HasEmbeddedFilesперед ітерацієюEmbeddedFiles, щоб уникнути зайвого перебору документів без вкладень. - Встановіть
MimeTypeтаAFRelationshipдля кожногоFileSpecification, щоб споживачі PDF нижчого рівня могли правильно класифікувати вкладення. - Використовуйте
EmbeddedFileCollection.FindByNameдля однократного пошуку за ім’ям замість написання ручного циклу.
Типові проблеми
| Проблема | Причина | Виправлення |
|---|---|---|
OutOfMemoryException збереження великого документа у потік | MemoryStream обмежений одним ~2 GB фоновим масивом | Збережіть у OptimizedMemoryStream натомість |
FileSpecification.GetData() повертає порожній масив | Позиція вихідного потоку не була скинута перед створенням FileSpecification | Встановіть позицію потоку на 0 (або відкрийте його заново) перед передачею в FileSpecification |
EmbeddedFiles.FindByName повертає null | Назва вкладення не збігається точно (пошук здійснюється за назвою) | Ітеруйте doc.EmbeddedFiles і порівнюйте значення Name, або перевірте Keys |
| Видалення вкладення видаляє неправильний запис | Кілька вкладень мають однакову назву | Використовуйте DeleteByKey з точним ключем з Keys для однозначного видалення |
FAQ
У чому різниця між MemoryStream і OptimizedMemoryStream?
MemoryStream зберігає свої байти в одному безперервному масиві, обмеженому приблизно 2ГБ. OptimizedMemoryStream зберігає дані у фіксованих блоках, тому може перевищувати це обмеження — корисно для операцій Document.Save, які виконуються повністю в пам’яті над дуже великими файлами.
Чи можу я вбудувати файл без попереднього завантаження його в byte[]?
Так. FileSpecification(stream, name, description) приймає Stream безпосередньо, тож ви можете вбудовувати з File.OpenRead(...) або будь-якого іншого потоку без буферизації його в пам’яті вручну.
Як отримати вбудований файл з документа?
Пройдіть doc.EmbeddedFiles і викличте GetData() для кожного FileSpecification, щоб отримати необроблені байти.
Чи EmbeddedFileCollection.Delete(name) видаляє усі вкладення з таким ім’ям?
Ні — точно вкажіть одне вкладення за допомогою DeleteByKey і конкретного ключа з Keys, якщо декілька вкладень мають однакове ім’я.
Чи безпечно повторно використовувати FileSpecification у кількох документах?
Ні. FileSpecification реалізує IDisposable і обгортає один потік вбудованого файлу; створюйте новий екземпляр для кожного вкладення в кожному документі.
API Reference Підсумок
| Клас / Метод | Опис |
|---|---|
OptimizedMemoryStream | Зростаючий потік у пам’яті, який перевищує обмеження у 2GB для MemoryStream |
OptimizedMemoryStream.Write | Записати байти у буфер |
OptimizedMemoryStream.ToArray | Повернути буферизовані байти як масив байтів |
FileSpecification | Вбудований дескриптор вкладення файлу, підкріплений потоком або байтовими даними |
FileSpecification.GetData | Отримати сирі байти вбудованого файлу |
FileSpecification.Params | Метадані (розмір, контрольна сума, дати) для вбудованого файлу |
EmbeddedFileCollection | Колекція FileSpecification вкладень у Document |
EmbeddedFileCollection.FindByName | Знайти вкладення за назвою |
EmbeddedFileCollection.Delete | Видалити вкладення за назвою |
Document.AddEmbeddedFile | Зручний метод для вбудовування файлу з необроблених байтів |
Document.EmbeddedFiles | Колекція вбудованих файлів документа |
Document.HasEmbeddedFiles | Чи містить документ будь-які вбудовані файли |
FileParams | Обгортає метадані розміру/контрольної суми/дати для вбудованого потоку файлу |