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

关于 BLOB

BLOBBinary Large Object)通常是以二进制格式保存的大型项(照片、演示文稿、文档或媒体)。

Aspose.Slides for PHP via Java 允许您在涉及大文件时使用 BLOB 来降低内存消耗。

使用 BLOB 减少内存消耗

通过 BLOB 向演示文稿添加大型文件

Aspose.Slides for Java 允许您通过 BLOB 过程添加大型文件(本例中为大型视频文件),以降低内存消耗。

此示例展示了如何通过 BLOB 过程向演示文稿添加大型视频文件:

  $pathToVeryLargeVideo = "veryLargeVideo.avi";
  # 创建一个新演示文稿,将添加视频
  $pres = new Presentation();
  try {
    $fileStream = new Java("java.io.FileInputStream", $pathToVeryLargeVideo);
    try {
      # 让我们将视频添加到演示文稿中 - 我们选择 KeepLocked 行为,因为我们
      # 不打算访问 "veryLargeVideo.avi" 文件。
      $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 (!java_is_null($fileStream)) {
        $fileStream->close();
      }
    }
  } catch (JavaException $e) {
  } finally {
    if (!java_is_null($pres)) {
      $pres->dispose();
    }
  }

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

Aspose.Slides for PHP via Java 允许您通过 BLOB 过程从演示文稿中导出大型文件(例如音频或视频文件)。例如,您可能需要从演示文稿中提取大型媒体文件,但不希望将其加载到计算机内存中。通过 BLOB 过程导出文件,可保持低内存消耗。

以下代码演示了上述操作:

  $hugePresentationWithAudiosAndVideosFile = "LargeVideoFileTest.pptx";
  $loadOptions = new LoadOptions();
  # 锁定源文件且不将其加载到内存中
  # 创建 Presentation 实例,锁定 “hugePresentationWithAudiosAndVideos.pptx” 文件。
  $pres = new Presentation($hugePresentationWithAudiosAndVideosFile, $loadOptions);
  try {
    # 我们将每个视频保存到文件。为防止高内存使用,需要使用缓冲区
    # 以将演示文稿的视频流数据传输到新创建的视频文件流中。
    $Array = new JavaClass("java.lang.reflect.Array");
    $Byte = new JavaClass("java.lang.Byte");
    $buffer = $Array->newInstance($Byte, 8 * 1024);
    # 遍历视频
    for($index = 0; $index < java_values($pres->getVideos()->size()) ; $index++) {
      $video = $pres->getVideos()->get_Item($index);
      # 打开演示文稿的视频流。请注意,我们有意避免访问属性
      # 比如 video.BinaryData —— 因为此属性返回包含完整视频的字节数组,这将
      # 导致字节加载到内存中。我们使用 video.GetStream,它返回 Stream —— 并且不
      # 需要我们将整个视频加载到内存中。
      $presVideoStream = $video->getStream();
      try {
        $outputFileStream = new Java("java.io.FileOutputStream", "video" . $index . ".avi");
        try {
          $bytesRead;
          while ($bytesRead = $presVideoStream->read($buffer, 0, java_values($Array->getLength($buffer))) > 0) {
            $outputFileStream->write($buffer, 0, $bytesRead);
          } 
        } finally {
          $outputFileStream->close();
        }
      } finally {
        $presVideoStream->close();
      }
      # 无论视频或演示文稿大小,内存消耗都将保持低水平。
    }
    # 如有必要,您可以对音频文件执行相同的步骤。
  } catch (JavaException $e) {
  } finally {
    $pres->dispose();
  }

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

使用 ImageCollection 类的方法,您可以将大型图像作为流添加,以将其视为 BLOB。

以下 PHP 代码展示了如何通过 BLOB 过程添加大型图像:

  $pathToLargeImage = "large_image.jpg";
  # 创建一个新演示文稿,将添加图像。
  $pres = new Presentation();
  try {
    $fileStream = new Java("java.io.FileInputStream", $pathToLargeImage);
    try {
      # 将图像添加到演示文稿 - 我们选择 KeepLocked 行为,因为我们
      # 不打算访问 "largeImage.png" 文件。
      $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 (!java_is_null($fileStream)) {
        $fileStream->close();
      }
    }
  } catch (JavaException $e) {
  } finally {
    if (!java_is_null($pres)) {
      $pres->dispose();
    }
  }

内存和大型演示文稿

通常,加载大型演示文稿需要大量临时内存。演示文稿的所有内容会加载到内存中,加载后原文件不再被使用。

考虑一个包含 1.5 GB 视频文件的大型 PowerPoint 演示文稿(large.pptx)。以下 PHP 代码描述了加载该演示文稿的标准方法:

  $pres = new Presentation("large.pptx");
  try {
    $pres->save("large.pdf", SaveFormat::Pdf);
  } finally {
    if (!java_is_null($pres)) {
      $pres->dispose();
    }
  }

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

以 BLOB 加载大型演示文稿

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

  $loadOptions = new LoadOptions();
  $loadOptions->getBlobManagementOptions()->setPresentationLockingBehavior(PresentationLockingBehavior->KeepLocked);
  $loadOptions->getBlobManagementOptions()->setTemporaryFilesAllowed(true);
  $pres = new Presentation("large.pptx", $loadOptions);
  try {
    $pres->save("large.pdf", SaveFormat::Pdf);
  } finally {
    if (!java_is_null($pres)) {
      $pres->dispose();
    }
  }

更改临时文件夹位置

使用 BLOB 过程时,计算机会在默认临时文件夹中创建临时文件。如需将临时文件保存到其他文件夹,可使用 setTempFilesRootPath 修改存储设置:

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

常见问题

Aspose.Slides 演示文稿中哪些数据被视为 BLOB 并受 BLOB 选项控制?

图像、音频和视频等大型二进制对象被视为 BLOB。整个演示文稿文件在加载或保存时也涉及 BLOB 处理。这些对象受 BLOB 策略管控,您可以管理内存使用并在需要时溢写到临时文件。

在演示文稿加载期间,在哪里配置 BLOB 处理规则?

使用带有 BlobManagementOptionsLoadOptions。在此可以设置 BLOB 的内存限制、是否允许临时文件、临时文件的根路径以及源锁定行为。

BLOB 设置会影响性能吗?如何在速度和内存之间取得平衡?

是的。将 BLOB 保持在内存中可提升速度,但会增加 RAM 消耗;降低内存限制会将更多工作转移到临时文件,从而降低 RAM 占用但会增加 I/O。使用 setMaxBlobsBytesInMemory 方法可为您的工作负载和环境找到合适的平衡点。

在打开极大型演示文稿(如数 GB)时,BLOB 选项有帮助吗?

是的。BlobManagementOptions 专为此类场景设计:启用临时文件并使用源锁定,可显著降低峰值 RAM 使用并使处理极大演示文稿更稳定。

可以在从流加载而不是磁盘文件时使用 BLOB 策略吗?

可以。相同的规则适用于流:演示文稿实例可以拥有并锁定输入流(取决于所选的锁定模式),并在允许的情况下使用临时文件,从而在处理过程中保持可预测的内存使用。