Потоки та вкладення файлів

Потоки та вкладення файлів

Потоки та файлові вкладення

Поза базовими 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Обгортає метадані розміру/контрольної суми/дати для вбудованого потоку файлу

Дивіться також

 Українська