在 Java 中管理演示文稿 BLOB 以实现高效内存使用

概述

Aspose.Slides 提供基于 BLOB 的处理方式,以在演示文稿中处理大二进制数据,从而在使用大型图像、音频、视频和演示文稿文件时帮助降低内存消耗。
本文展示了如何使用基于 BLOB 的处理向演示文稿添加大型媒体、从演示文稿导出大型媒体,以及更高效地加载大型演示文稿。还说明了在处理过程中如何使用临时文件以及如何更改存储这些文件的文件夹。

关于 BLOB

BLOBBinary Large Object)通常是以二进制格式保存的大型项(照片、演示文稿、文档或媒体)。
Aspose.Slides for Java 允许您以降低内存消耗的方式对对象使用 BLOB,尤其在涉及大文件时。

使用 BLOB 减少内存消耗

通过 BLOB 将大文件添加到演示文稿

Aspose.Slides for Java 允许您通过涉及 BLOB 的过程添加大文件(此处为大型视频文件),以降低内存消耗。
下面的 Java 示例展示了如何通过 BLOB 过程将大型视频文件添加到演示文稿中:

String pathToVeryLargeVideo = "veryLargeVideo.avi";

// 创建一个将要添加视频的新演示文稿
Presentation pres = new Presentation();
try {
    FileInputStream fileStream = new FileInputStream(pathToVeryLargeVideo);
    try {
        // 让我们将视频添加到演示文稿中 - 我们选择 KeepLocked 行为,因为我们
        // 不打算访问 "veryLargeVideo.avi" 文件。
        IVideo video = pres.getVideos().addVideo(fileStream, LoadingStreamBehavior.KeepLocked);
        pres.getSlides().get_Item(0).getShapes().addVideoFrame(0, 0, 480, 270, video);

        // 保存演示文稿。即使输出大型演示文稿,内存消耗
        // 在 pres 对象的整个生命周期内保持较低 
        pres.save("presentationWithLargeVideo.pptx", SaveFormat.Pptx);
    } finally {
        if (fileStream != null) fileStream.close();
    }
} catch(IOException e) {
} finally {
    if (pres != null) pres.dispose();
}

通过 BLOB 从演示文稿导出大文件

Aspose.Slides for Java 允许您通过涉及 BLOB 的过程从演示文稿中导出大文件(此处为音频或视频文件)。例如,您可能需要从演示文稿中提取大型媒体文件,但不希望该文件加载到计算机内存中。通过 BLOB 过程导出文件,可保持低内存消耗。
下面的 Java 代码演示了上述操作:

String hugePresentationWithAudiosAndVideosFile = "LargeVideoFileTest.pptx";

LoadOptions loadOptions = new LoadOptions();
// 锁定源文件且不将其加载到内存中
loadOptions.getBlobManagementOptions().setPresentationLockingBehavior(PresentationLockingBehavior.KeepLocked);

// 创建 Presentation 实例,锁定 "hugePresentationWithAudiosAndVideos.pptx" 文件。
Presentation pres = new Presentation(hugePresentationWithAudiosAndVideosFile, loadOptions);
try {
    // 让我们将每个视频保存到文件。为防止内存使用过高,我们需要一个缓冲区来使用
    // 将演示文稿的视频流数据传输到新创建的视频文件的流中。
    byte[] buffer = new byte[8 * 1024];

    // 遍历视频
    for (int index = 0; index < pres.getVideos().size(); index++) {
        IVideo video = pres.getVideos().get_Item(index);

        // 打开演示文稿的视频流。请注意,我们有意避免访问属性
        // 如 video.BinaryData - 因为此属性返回包含完整视频的字节数组,这会
        // 导致字节被加载到内存中。我们使用 video.GetStream,它将返回 Stream,并且不会
        //  要求我们将整个视频加载到内存中。
        InputStream presVideoStream = video.getStream();
        try {
            OutputStream outputFileStream = new FileOutputStream("video" + index + ".avi");
            try {
                int bytesRead;
                while ((bytesRead = presVideoStream.read(buffer, 0, buffer.length)) > 0) {
                    outputFileStream.write(buffer, 0, bytesRead);
                }
            } finally {
                outputFileStream.close();
            }
        } finally {
            presVideoStream.close();
        }
        // 无论视频或演示文稿的大小如何,内存消耗都将保持低水平。
    }
    // 如有必要,您可以对音频文件应用相同的步骤。 
} catch (IOException e) {
} finally {
    pres.dispose();
}

将图像作为 BLOB 添加到演示文稿

通过 IImageCollection 接口和 ImageCollection 类的方法,您可以将大图像作为流添加,以使其被视为 BLOB。
下面的 Java 代码展示了如何通过 BLOB 过程添加大型图像:

String pathToLargeImage = "large_image.jpg";

// 创建一个将要添加图像的新演示文稿。
Presentation pres = new Presentation();
try {
	FileInputStream fileStream = new FileInputStream(pathToLargeImage);
	try {
		// 让我们将图像添加到演示文稿中 - 我们选择 KeepLocked 行为,因为我们
		// 不打算访问 "largeImage.png" 文件。
		IPPImage img = pres.getImages().addImage(fileStream, LoadingStreamBehavior.KeepLocked);
		pres.getSlides().get_Item(0).getShapes().addPictureFrame(ShapeType.Rectangle, 0, 0, 300, 200, img);

		// 保存演示文稿。即使输出大型演示文稿,内存消耗
		// 在 pres 对象的整个生命周期内保持较低
		pres.save("presentationWithLargeImage.pptx", SaveFormat.Pptx);
	} finally {
		if (fileStream != null) fileStream.close();
	}
} catch(IOException e) {
} finally {
	if (pres != null) pres.dispose();
}

内存与大型演示文稿

通常,加载大型演示文稿需要大量临时内存。演示文稿的全部内容会被加载到内存中,而加载该演示文稿的文件则不再被使用。
设想一个包含 1.5 GB 视频文件的大型 PowerPoint 演示文稿(large.pptx)。加载该演示文稿的标准方法在下面的 Java 代码中描述:

Presentation pres = new Presentation("large.pptx");
try {
    pres.save("large.pdf", SaveFormat.Pdf);
} finally {
    if (pres != null) pres.dispose();
}

但此方法会消耗约 1.6 GB 的临时内存。

将大型演示文稿作为 BLOB 加载

通过涉及 BLOB 的过程,您可以在使用极少内存的情况下加载大型演示文稿。下面的 Java 代码描述了使用 BLOB 过程加载大型演示文稿文件(large.pptx)的实现:

LoadOptions loadOptions = new LoadOptions();
loadOptions.getBlobManagementOptions().setPresentationLockingBehavior(PresentationLockingBehavior.KeepLocked);
loadOptions.getBlobManagementOptions().setTemporaryFilesAllowed(true);

Presentation pres = new Presentation("large.pptx", loadOptions);
try {
    pres.save("large.pdf", SaveFormat.Pdf);
} finally {
    if (pres != null) pres.dispose();
}

更改临时文件的文件夹

使用 BLOB 过程时,计算机会在默认的临时文件夹中创建临时文件。如果希望将临时文件保存在其他文件夹,可使用 TempFilesRootPath 更改存储设置:

LoadOptions loadOptions = new LoadOptions();
loadOptions.getBlobManagementOptions().setPresentationLockingBehavior(PresentationLockingBehavior.KeepLocked);
loadOptions.getBlobManagementOptions().setTemporaryFilesAllowed(true);
loadOptions.getBlobManagementOptions().setTempFilesRootPath("temp");

释放演示文稿对象以释放内存

在处理大型演示文稿时,请确保正确释放 Presentation 实例,以释放其占用的内存。在完成演示文稿的使用后调用 dispose(),以释放非托管资源。

Presentation presentation = new Presentation("large.pptx");

// ...处理演示文稿...
presentation.save("large.pdf", SaveFormat.Pdf);

// 显式释放资源。
presentation.dispose();

常见问题

Aspose.Slides 演示文稿中哪些数据被视为 BLOB 并受 BLOB 选项控制?
图像、音频、视频等大型二进制对象会被视为 BLOB。当加载或保存演示文稿时,整个演示文稿文件也涉及 BLOB 处理。这些对象受 BLOB 策略管理,您可以在需要时控制内存使用并将数据转存至临时文件。

在加载演示文稿时在哪里配置 BLOB 处理规则?
使用带有 BlobManagementOptionsLoadOptions。在此您可以设置 BLOB 的内存上限、是否允许临时文件、临时文件的根路径,以及源锁定行为。

BLOB 设置会影响性能吗?如何在速度与内存之间取得平衡?
会。将 BLOB 保持在内存中可最大化速度,但会增加 RAM 消耗;降低内存限制会将更多工作转移到临时文件,从而降低 RAM 使用,但会产生额外的 I/O。使用 setMaxBlobsBytesInMemory 方法来为您的工作负载和环境找到合适的平衡点。

在打开极大演示文稿(例如数 GB)时,BLOB 选项是否有帮助?
会。针对这种场景设计的 BlobManagementOptions 可启用临时文件并使用源锁定,从而显著降低峰值 RAM 使用并稳定对超大型演示文稿的处理。

在从流而非磁盘文件加载时,是否可以使用 BLOB 策略?
会。相同的规则同样适用于流:演示文稿实例可以拥有并锁定输入流(取决于所选的锁定模式),在允许的情况下使用临时文件,从而在处理期间保持内存使用可预测。