Fluxos e Anexos de Arquivo

Fluxos e Anexos de Arquivo

Fluxos e Anexos de Arquivo

Além das sobrecargas básicas Document.Open/Document.Save, o Aspose.PDF FOSS para .NET oferece controle mais fino sobre como os bytes entram e saem de um documento — buffers de memória expansíveis para arquivos muito grandes e um API dedicado para incorporar, inspecionar e extrair anexos de arquivo por meio de FileSpecification e EmbeddedFileCollection.


Expansão de buffers em memória além de 2GB

MemoryStream armazena seus dados em um único array contíguo, que atinge um limite próximo de 2GB. OptimizedMemoryStream armazena os dados em blocos de tamanho fixo, permitindo que ele contenha documentos muito maiores ao salvar ou gerar um PDF totalmente na memória.

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}");

Você também pode gravar nele diretamente, da mesma forma que faria com qualquer 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);

Incorporando um arquivo diretamente de um fluxo

FileSpecification pode envolver um Stream ao invés de exigir que você armazene o anexo em um byte[] primeiro. Isso é útil quando a fonte do anexo é ela própria um fluxo, como um manipulador de arquivo aberto.

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");

Incorporando um arquivo a partir de bytes brutos

Document.AddEmbeddedFile é um método de conveniência para incorporar um arquivo diretamente a partir de um array de bytes, sem construir um FileSpecification diretamente.

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");

Enumerando e extraindo arquivos incorporados

Document.EmbeddedFiles é um EmbeddedFileCollection que você pode enumerar. Cada entrada é um FileSpecification e GetData() devolve os bytes brutos do anexo.

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);
    }
}

Encontrando, inspecionando e removendo anexos

Use FindByName para localizar um único anexo, Params para ler seus metadados e Delete/DeleteByKey para removê-lo.

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");

Dicas e Melhores Práticas

  • Prefira OptimizedMemoryStream em vez de MemoryStream sempre que um documento em memória puder exceder 2GB — MemoryStream gera uma exceção quando seu array de suporte único atinge esse limite.
  • Libere as instâncias de FileSpecification (e qualquer stream que você abriu manualmente para elas) – FileSpecification implementa IDisposable.
  • Verifique Document.HasEmbeddedFiles antes de iterar EmbeddedFiles para pular enumerações desnecessárias em documentos sem anexos.
  • Defina MimeType e AFRelationship em cada FileSpecification para que os consumidores de PDF posteriores possam classificar os anexos corretamente.
  • Use EmbeddedFileCollection.FindByName para uma única pesquisa nomeada em vez de escrever um loop manual.

Problemas comuns

ProblemaCausaCorreção
OutOfMemoryException salvando um documento grande para um streamMemoryStream é limitado a um único array de suporte de ~2GBSalve em OptimizedMemoryStream em vez disso
FileSpecification.GetData() retorna um array vazioA posição do stream de origem não foi reinicializada antes de FileSpecification ser criadoPosicione o fluxo na posição0 (ou reabra-o) antes de passá-lo para FileSpecification
EmbeddedFiles.FindByName retorna nullO nome do anexo não corresponde exatamente (a busca é baseada em nome)Itere doc.EmbeddedFiles e compare os valores de Name, ou verifique Keys
Excluir um anexo remove a entrada erradaVários anexos compartilham o mesmo nomeUse DeleteByKey com a chave exata de Keys para remoção inequívoca

FAQ

Qual é a diferença entre MemoryStream e OptimizedMemoryStream?

MemoryStream armazena seus bytes em um único array contíguo limitado a cerca de 2GB. OptimizedMemoryStream armazena os dados em blocos de tamanho fixo, permitindo que cresça além desse limite – útil para operações de Document.Save realizadas inteiramente na memória em arquivos muito grandes.

Posso incorporar um arquivo sem carregá-lo primeiro em um byte[]?

Sim. FileSpecification(stream, name, description) aceita um Stream diretamente, então você pode incorporar a partir de File.OpenRead(...) ou qualquer outro stream sem armazená-lo em memória você mesmo.

Como obtenho um arquivo incorporado de volta de um documento?

Itere doc.EmbeddedFiles e chame GetData() em cada FileSpecification para recuperar os bytes brutos.

O EmbeddedFileCollection.Delete(name) remove todos os anexos com esse nome?

Não – direcione exatamente um anexo com DeleteByKey e a chave específica de Keys se vários anexos compartilharem o mesmo nome.

É seguro reutilizar FileSpecification em vários documentos?

Não. FileSpecification implementa IDisposable e encapsula um único stream de arquivo incorporado; crie uma nova instância por anexo por documento.


API Reference Resumo

Classe / MétodoDescrição
OptimizedMemoryStreamFluxo em memória expansível que excede o limite de 2GB de MemoryStream
OptimizedMemoryStream.WriteEscreva bytes no buffer
OptimizedMemoryStream.ToArrayRetorne os bytes em buffer como um array de bytes
FileSpecificationDescritor de anexo de arquivo incorporado, suportado por um stream ou dados de bytes
FileSpecification.GetDataRecuperar os bytes brutos de um arquivo incorporado
FileSpecification.ParamsMetadados (tamanho, soma de verificação, datas) para o arquivo incorporado
EmbeddedFileCollectionColeção de anexos FileSpecification em um Document
EmbeddedFileCollection.FindByNameBuscar um anexo pelo nome
EmbeddedFileCollection.DeleteRemover um anexo pelo nome
Document.AddEmbeddedFileMétodo de conveniência para incorporar um arquivo a partir de bytes brutos
Document.EmbeddedFilesA coleção de arquivos incorporados ao documento
Document.HasEmbeddedFilesSe o documento contém arquivos incorporados
FileParamsEnvolve metadados de tamanho/checksum/data para um fluxo de arquivo incorporado

Ver também

 Português