当前位置: 首页 > 面试题库 >

从Google Cloud Storage流式传输文件

司徒正信
2023-03-14
问题内容

这是从Google Cloud Storage下载文件的代码:

@Override
public void write(OutputStream outputStream) throws IOException {
    try {
        LOG.info(path);
        InputStream stream = new ByteArrayInputStream(GoogleJsonKey.JSON_KEY.getBytes(StandardCharsets.UTF_8));
        StorageOptions options = StorageOptions.newBuilder()
                .setProjectId(PROJECT_ID)
                .setCredentials(GoogleCredentials.fromStream(stream)).build();
        Storage storage = options.getService();
        final CountingOutputStream countingOutputStream = new CountingOutputStream(outputStream);
        byte[] read = storage.readAllBytes(BlobId.of(BUCKET, path));
        countingOutputStream.write(read);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        outputStream.close();
    }
}

这行得通,但是这里的问题是,在流回此方法的客户端之前,它必须先缓冲所有字节。这会导致很多延迟,尤其是当存储在GCS中的文件很大时。

有没有一种方法可以从GCS获取文件并将 其直接流式传输到OutputStream ,这里的OutputStream是用于Servlet的。


问题答案:

只是为了澄清一下,您需要一个OutputStream还是一个InputStream?一种查看方式是,将Google Cloud
Storage对象中存储的数据作为文件存储,并且您有一个InputStream可以读取该文件。如果可行,请继续阅读。

Storage API中没有提供InputStream或的现有方法OutputStream。但是Cloud
Storage客户端库中
有2个API,它们公开了一个ReadChannel对象ReadableByteChannel(从Java
NIO API 扩展)。

ReadChannel reader(String bucket, String blob, BlobSourceOption... options);
ReadChannel reader(BlobId blob, BlobSourceOption... options);

一个简单的例子(摘自StorageSnippets.java):

/**
   * Example of reading a blob's content through a reader.
   */
  // [TARGET reader(String, String, BlobSourceOption...)]
  // [VARIABLE "my_unique_bucket"]
  // [VARIABLE "my_blob_name"]
  public void readerFromStrings(String bucketName, String blobName) throws IOException {
    // [START readerFromStrings]
    try (ReadChannel reader = storage.reader(bucketName, blobName)) {
      ByteBuffer bytes = ByteBuffer.allocate(64 * 1024);
      while (reader.read(bytes) > 0) {
        bytes.flip();
        // do something with bytes
        bytes.clear();
      }
    }
    // [END readerFromStrings]
  }

您还可以使用该newInputStream()方法来包装一个InputStreamReadableByteChannel

public static InputStream newInputStream(ReadableByteChannel ch)

即使您需要使用OutputStream,也应该能够将InputStream或更好的ReadChannel对象中的数据复制到中OutputStream

完整的例子

将此示例运行为: PROGRAM_NAME <BUCKET_NAME> <BLOB_PATH>

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;

import com.google.cloud.ReadChannel;
import com.google.cloud.storage.Bucket;
import com.google.cloud.storage.BucketInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

/**
 * An example which reads the contents of the specified object/blob from GCS
 * and prints the contents to STDOUT.
 *
 * Run it as PROGRAM_NAME <BUCKET_NAME> <BLOB_PATH>
 */
public class ReadObjectSample {
  private static final int BUFFER_SIZE = 64 * 1024;

  public static void main(String[] args) throws IOException {
    // Instantiates a Storage client
    Storage storage = StorageOptions.getDefaultInstance().getService();

    // The name for the GCS bucket
    String bucketName = args[0];
    // The path of the blob (i.e. GCS object) within the GCS bucket.
    String blobPath = args[1];

    printBlob(storage, bucketName, blobPath);
  }

  // Reads from the specified blob present in the GCS bucket and prints the contents to STDOUT.
  private static void printBlob(Storage storage, String bucketName, String blobPath) throws IOException {
    try (ReadChannel reader = storage.reader(bucketName, blobPath)) {
      WritableByteChannel outChannel = Channels.newChannel(System.out);
      ByteBuffer bytes = ByteBuffer.allocate(BUFFER_SIZE);
      while (reader.read(bytes) > 0) {
        bytes.flip();
        outChannel.write(bytes);
        bytes.clear();
      }
    }
  }
}


 类似资料:
  • 问题内容: 我有一个200MB的文件,想通过下载提供给用户。但是,由于我们希望用户仅下载一次此文件,因此我们这样做: 强制下载。但是,这意味着整个文件必须加载到内存中,这通常不起作用。我们如何以每块kb的速度将文件流式传输给他们? 问题答案: 尝试这样的事情

  • 问题内容: 我正在尝试将csv文件作为附件下载流式传输。CSV文件的大小已达到4MB或更大,我需要一种让用户主动下载文件的方法,而不必等待所有数据都先创建并提交到内存中。 我首先使用了我自己的基于Django类的文件包装器。那失败了。然后,我在这里看到了一种使用生成器流式传输响应的方法: 如何使用Django流式传输HttpResponse 当我在生成器中引发错误时,可以看到我正在使用该函数创建正

  • 问题内容: 我正在构建需要扩展的Java服务器。Servlet之一将提供存储在Amazon S3中的图像。 最近,在负载下,我的VM内存不足,这是在我添加了为图像提供服务的代码之后,因此,我很确定流较大的servlet响应会引起我的麻烦。 我的问题是:从数据库或其他云存储中读取时,如何编写Java Servlet来将大型(> 200k)响应流回浏览器,是否有最佳实践? 我考虑过将文件写入本地临时驱

  • 问题内容: 我正在构建需要扩展的Java服务器。Servlet之一将提供存储在Amazon S3中的图像。 最近在负载下,我的VM内存不足,这是在添加代码以提供图像服务之后,因此,我很确定流较大的servlet响应会引起麻烦。 我的问题是:从数据库或其他云存储读取数据时,如何编写Java Servlet以便将大型(> 200k)响应流回浏览器,是否有最佳实践? 我考虑过将文件写入本地临时驱动器,然

  • 问题内容: 我正在尝试设置一个非常基本的html5页面,该页面会加载20MB的.mp4视频。看来,浏览器需要下载整个内容,而不仅仅是播放视频的第一部分并在其余部分进行流传输。 我在搜索时发现的最接近的内容…我尝试了“手刹”和“数据回合”,两者均未发挥作用: 关于如何执行此操作或是否可行的任何想法? 这是我正在使用的代码: 问题答案: 确保moov(元数据)在mdat(音频/视频数据)之前。这也称为

  • 如何将日志文件从Windows 7传输到Linux中的HDFS? Windows中的水槽出现错误 我已经在Windows 7(节点1)上安装了“flume-node-0.9.3”。“flumenode”服务正在运行,localhost:35862可以访问 在Windows中,日志文件位于“C:/logs/Weblogic”。log' CentOS Linux(节点2)中的Flume代理也在运行。