Flujos y archivos adjuntos
Flujos y archivos adjuntos
Más allá de las sobrecargas básicas Document.Open/Document.Save, Aspose.PDF FOSS para .NET te brinda un control más fino sobre cómo los bytes se mueven dentro y fuera de un documento – buffers en memoria expandibles para archivos muy grandes, y un API dedicado para incrustar, inspeccionar y extraer archivos adjuntos mediante FileSpecification y EmbeddedFileCollection.
Ampliando buffers en memoria más allá de 2 GB
MemoryStream almacena sus datos en una única matriz contigua, que se limita cerca de los 2 GB. OptimizedMemoryStream almacena los datos en fragmentos de tamaño fijo, de modo que puede contener documentos mucho más grandes cuando guardas o construyes un PDF completamente en memoria.
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}");También puedes escribir en él directamente, de la misma manera que lo harías con cualquier 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);Incrustar un archivo directamente desde un flujo
FileSpecification puede envolver un Stream en lugar de requerir que bufferices el adjunto en un byte[] primero. Esto es útil cuando la fuente del adjunto es un flujo en sí mismo, como un descriptor de archivo abierto.
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");Incrustar un archivo a partir de bytes crudos
Document.AddEmbeddedFile es un método de conveniencia para incrustar un archivo directamente desde una matriz de bytes, sin construir un FileSpecification directamente.
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");Enumerar y extraer archivos incrustados
Document.EmbeddedFiles es un EmbeddedFileCollection que puedes enumerar. Cada entrada es un FileSpecification, y GetData() devuelve los bytes crudos del adjunto.
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);
}
}Buscar, inspeccionar y eliminar adjuntos
Usa FindByName para buscar un único adjunto, Params para leer sus metadatos, y Delete/DeleteByKey para eliminarlo.
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");Consejos y buenas prácticas
- Prefiere
OptimizedMemoryStreamsobreMemoryStreamsiempre que un documento en memoria pueda superar los 2GB —MemoryStreamlanza una excepción cuando su única matriz subyacente alcanza ese límite. - Libere las instancias de
FileSpecification(y cualquier flujo que haya abierto manualmente para ellas) –FileSpecificationimplementaIDisposable. - Compruebe
Document.HasEmbeddedFilesantes de iterarEmbeddedFilespara omitir la enumeración innecesaria en documentos sin adjuntos. - Establezca
MimeTypeyAFRelationshipen cadaFileSpecificationpara que los consumidores de PDF posteriores puedan clasificar los adjuntos correctamente. - Utilice
EmbeddedFileCollection.FindByNamepara una búsqueda única por nombre en lugar de escribir un bucle manual.
Problemas comunes
| Problema | Causa | Solución |
|---|---|---|
OutOfMemoryException guardando un documento grande en un stream | MemoryStream está limitado a una única matriz de respaldo de ~2GB | Guarde en OptimizedMemoryStream en su lugar |
FileSpecification.GetData() devuelve una matriz vacía | La posición del stream de origen no se restableció antes de que se creara el FileSpecification | Posicione el flujo a la posición 0 (o reábralo) antes de pasarlo a FileSpecification |
EmbeddedFiles.FindByName devuelve null | El nombre del adjunto no coincide exactamente (la búsqueda es basada en el nombre) | Itera doc.EmbeddedFiles y compara los valores de Name, o verifica Keys |
| Eliminar un adjunto elimina la entrada incorrecta | Varios adjuntos comparten el mismo nombre | Utiliza DeleteByKey con la clave exacta de Keys para una eliminación inequívoca |
FAQ
¿Cuál es la diferencia entre MemoryStream y OptimizedMemoryStream?
MemoryStream almacena sus bytes en un único array contiguo limitado a cerca de 2GB. OptimizedMemoryStream almacena los datos en fragmentos de tamaño fijo, por lo que puede superar ese límite, lo que resulta útil para operaciones de Document.Save realizadas completamente en memoria sobre archivos muy grandes.
¿Puedo incrustar un archivo sin cargarlo primero en un byte[]?
Sí. FileSpecification(stream, name, description) acepta un Stream directamente, por lo que puedes incrustar desde File.OpenRead(...) o cualquier otro flujo sin almacenarlo en memoria tú mismo.
¿Cómo obtengo un archivo incrustado de un documento?
Itera doc.EmbeddedFiles y llama a GetData() en cada FileSpecification para obtener los bytes sin procesar.
¿EmbeddedFileCollection.Delete(name) elimina todos los adjuntos con ese nombre?
No – dirige un solo adjunto con precisión usando DeleteByKey y la clave específica de Keys si varios adjuntos comparten el mismo nombre.
¿FileSpecification es seguro reutilizarlo en varios documentos?
No. FileSpecification implementa IDisposable y envuelve un único flujo de archivo incrustado; crea una nueva instancia por adjunto por documento.
API Reference Resumen
| Clase / Método | Descripción |
|---|---|
OptimizedMemoryStream | Flujo de memoria ampliable que supera el límite de 2GB de MemoryStream |
OptimizedMemoryStream.Write | Escriba bytes en el buffer |
OptimizedMemoryStream.ToArray | Devuelve los bytes en buffer como una matriz de bytes |
FileSpecification | Descriptor de archivo adjunto incrustado, respaldado por un stream o datos de bytes |
FileSpecification.GetData | Recuperar los bytes sin procesar de un archivo incrustado |
FileSpecification.Params | Metadatos (tamaño, suma de verificación, fechas) del archivo incrustado |
EmbeddedFileCollection | Colección de FileSpecification adjuntos en un Document |
EmbeddedFileCollection.FindByName | Buscar un adjunto por nombre |
EmbeddedFileCollection.Delete | Eliminar un adjunto por nombre |
Document.AddEmbeddedFile | Método de conveniencia para incrustar un archivo a partir de bytes crudos |
Document.EmbeddedFiles | La colección de archivos incrustados del documento |
Document.HasEmbeddedFiles | Indica si el documento contiene archivos incrustados |
FileParams | Envuelve metadatos de tamaño/checksum/fecha para una secuencia de archivo incrustada |