Flujos y archivos adjuntos

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 OptimizedMemoryStream sobre MemoryStream siempre que un documento en memoria pueda superar los 2GB — MemoryStream lanza 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) – FileSpecification implementa IDisposable.
  • Compruebe Document.HasEmbeddedFiles antes de iterar EmbeddedFiles para omitir la enumeración innecesaria en documentos sin adjuntos.
  • Establezca MimeType y AFRelationship en cada FileSpecification para que los consumidores de PDF posteriores puedan clasificar los adjuntos correctamente.
  • Utilice EmbeddedFileCollection.FindByName para una búsqueda única por nombre en lugar de escribir un bucle manual.

Problemas comunes

ProblemaCausaSolución
OutOfMemoryException guardando un documento grande en un streamMemoryStream está limitado a una única matriz de respaldo de ~2GBGuarde en OptimizedMemoryStream en su lugar
FileSpecification.GetData() devuelve una matriz vacíaLa posición del stream de origen no se restableció antes de que se creara el FileSpecificationPosicione el flujo a la posición 0 (o reábralo) antes de pasarlo a FileSpecification
EmbeddedFiles.FindByName devuelve nullEl 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 incorrectaVarios adjuntos comparten el mismo nombreUtiliza 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étodoDescripción
OptimizedMemoryStreamFlujo de memoria ampliable que supera el límite de 2GB de MemoryStream
OptimizedMemoryStream.WriteEscriba bytes en el buffer
OptimizedMemoryStream.ToArrayDevuelve los bytes en buffer como una matriz de bytes
FileSpecificationDescriptor de archivo adjunto incrustado, respaldado por un stream o datos de bytes
FileSpecification.GetDataRecuperar los bytes sin procesar de un archivo incrustado
FileSpecification.ParamsMetadatos (tamaño, suma de verificación, fechas) del archivo incrustado
EmbeddedFileCollectionColección de FileSpecification adjuntos en un Document
EmbeddedFileCollection.FindByNameBuscar un adjunto por nombre
EmbeddedFileCollection.DeleteEliminar un adjunto por nombre
Document.AddEmbeddedFileMétodo de conveniencia para incrustar un archivo a partir de bytes crudos
Document.EmbeddedFilesLa colección de archivos incrustados del documento
Document.HasEmbeddedFilesIndica si el documento contiene archivos incrustados
FileParamsEnvuelve metadatos de tamaño/checksum/fecha para una secuencia de archivo incrustada

Ver también

 Español