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
OptimizedMemoryStreamem vez deMemoryStreamsempre que um documento em memória puder exceder 2GB —MemoryStreamgera 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) –FileSpecificationimplementaIDisposable. - Verifique
Document.HasEmbeddedFilesantes de iterarEmbeddedFilespara pular enumerações desnecessárias em documentos sem anexos. - Defina
MimeTypeeAFRelationshipem cadaFileSpecificationpara que os consumidores de PDF posteriores possam classificar os anexos corretamente. - Use
EmbeddedFileCollection.FindByNamepara uma única pesquisa nomeada em vez de escrever um loop manual.
Problemas comuns
| Problema | Causa | Correção |
|---|---|---|
OutOfMemoryException salvando um documento grande para um stream | MemoryStream é limitado a um único array de suporte de ~2GB | Salve em OptimizedMemoryStream em vez disso |
FileSpecification.GetData() retorna um array vazio | A posição do stream de origem não foi reinicializada antes de FileSpecification ser criado | Posicione o fluxo na posição0 (ou reabra-o) antes de passá-lo para FileSpecification |
EmbeddedFiles.FindByName retorna null | O 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 errada | Vários anexos compartilham o mesmo nome | Use 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étodo | Descrição |
|---|---|
OptimizedMemoryStream | Fluxo em memória expansível que excede o limite de 2GB de MemoryStream |
OptimizedMemoryStream.Write | Escreva bytes no buffer |
OptimizedMemoryStream.ToArray | Retorne os bytes em buffer como um array de bytes |
FileSpecification | Descritor de anexo de arquivo incorporado, suportado por um stream ou dados de bytes |
FileSpecification.GetData | Recuperar os bytes brutos de um arquivo incorporado |
FileSpecification.Params | Metadados (tamanho, soma de verificação, datas) para o arquivo incorporado |
EmbeddedFileCollection | Coleção de anexos FileSpecification em um Document |
EmbeddedFileCollection.FindByName | Buscar um anexo pelo nome |
EmbeddedFileCollection.Delete | Remover um anexo pelo nome |
Document.AddEmbeddedFile | Método de conveniência para incorporar um arquivo a partir de bytes brutos |
Document.EmbeddedFiles | A coleção de arquivos incorporados ao documento |
Document.HasEmbeddedFiles | Se o documento contém arquivos incorporados |
FileParams | Envolve metadados de tamanho/checksum/data para um fluxo de arquivo incorporado |