【问题标题】:PHP S3 stream wrapper read CSV GZ compressed filePHP S3 流包装器读取 CSV GZ 压缩文件
【发布时间】:2020-10-21 21:59:17
【问题描述】:

使用 aws-php-sdk 从 s3 存储桶中读取 csv.gz 文件。所有文件都是 csv.gz 文件,我打算读取这些文件,然后将数据导入我的数据库。

我查看了许多堆栈溢出问题,但似乎无法正常工作。

这是我目前写的代码。

$s3 = new S3Client([
    'version' => 'latest',
    'region' => 'us-east-2',
    'credentials' => [
        'key' => '',
        'secret' => ''
    ]
]);
$s3->registerStreamWrapper();

if ($stream = fopen('s3://bucket/file.csv.gz', 'r')) {
    // While the stream is still open
    while (!feof($stream)) {
        // Read 1024 bytes from the stream
        $d = gzread($stream, 1024);
        var_dump($d);
    }
    // Be sure to close the stream resource when you're done with it
    fclose($stream);
}

以下代码仅返回大量随机字符,这些字符必须是压缩文件的内容。

如果有人可以分享一个代码示例,说明如何解压缩 csv.gz 文件,然后从中读取并允许我将其导入数据库,我将不胜感激。

【问题讨论】:

    标签: php amazon-s3 aws-php-sdk


    【解决方案1】:

    对于在以后的搜索中进入此主题的任何人:

    我尝试使用 Hamlet 的关于使用 stream_filter_append 的答案,但注意到我的一些机器在此解决方案上存在问题(尽管流仍然打开并且并非所有数据都已读取,但 fread 返回读取的 0 字节。

    我遇到了this thread - 原来在 php 中有一个已知的流缓冲错误。 使用我写这篇文章的线程中的代码,它可能会帮助下一个穿越这些路径的旅行者:

            // init $client from S3Client
            $client->registerStreamWrapper();
            // full s3 path to the file
            $gzipUrl = "s3://{$bucketName}/{$filePath}";
            $sourceFile = fopen($gzipUrl, 'rb');
            $targetFile = fopen(sys_get_temp_dir() . '/user_input_import.csv.gz', 'wb');
            stream_copy_to_stream($sourceFile, $targetFile);
            fclose($sourceFile);
            fclose($targetFile);
    
            copy('compress.zlib://' . sys_get_temp_dir() . '/user_input_import.csv.gz', $tmpFileName);
    

    对于我成功的项目。

    【讨论】:

      【解决方案2】:

      为了使gzread 正常工作,您必须使用gzopen 打开文件。 但是gzopen不支持文件流,所以使用这个功能你可以通过提供相应的文件路径,只打开位于服务器上的文件。

      在您的情况下,解决方案是使用压缩过滤器。 所以你必须使用fopen 来打开文件流,然后应用压缩流过滤器来读取.gz 解码数据。

      stream_filter_append(
              $stream,
              'zlib.inflate',
              STREAM_FILTER_READ,
              ["window" => 32]
          );
      
      

      有关详细信息,请参阅文档: https://www.php.net/manual/en/filters.compression.php

      不幸的是,以上文档中没有足够的关于window 参数的信息。以下是来自 zlib.h inflateInit2 文档的一些更有用的信息:

      windowBits 参数是最大值的以二为底的对数 窗口大小(历史缓冲区的大小)。它应该在 此版本库的范围为 8..15。默认值为 如果改为使用 inflateInit,则为 15。

      ...

      对于可选的 gzip 解码,windowBits 也可以大于 15。 将 32 添加到 windowBits 以启用 zlib 和 gzip 解码 自动标头检测,或添加 16 以仅解码 gzip 格式(zlib 格式将返回 Z_DATA_ERROR)。如果是 gzip 正在解码流,strm->adler 是 CRC-32 而不是 阿德勒-32。与 gunzip 实用程序和 gzread() 不同(见下文), inflate() 不会自动解码连接的 gzip 流。
      inflate() 将在 gzip 流的末尾返回 Z_STREAM_END。这 需要重置状态才能继续解码后续的 gzip 流。

      基于此信息,我建议使用窗口大小 32,因为此大小将支持 zlib 和 gzip 解码以及自动标头检测。

      所以最终的代码应该是这样的:

      $s3 = new S3Client([
          'version' => 'latest',
          'region' => 'us-east-2',
          'credentials' => [
              'key' => '',
              'secret' => '',
          ],
      ]);
      $s3->registerStreamWrapper();
      
      if ($stream = fopen('s3://bucket/file.csv.gz', 'r')) {
          stream_filter_append(
              $stream,
              'zlib.inflate',
              STREAM_FILTER_READ,
              ["window" => 32]
          );
          // While the stream is still open
          while (!feof($stream)) {
                      // Read 1024 bytes from the stream
              $d = gzread($stream, 1024);
              var_dump($d);
          }
          // Be sure to close the stream resource when you're done with it
          fclose($stream);
      }
      

      【讨论】:

        猜你喜欢
        • 2020-02-12
        • 1970-01-01
        • 1970-01-01
        • 2017-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多