java - 如何通过 Java API 将 block 上传到 Google Cloud Storage?

标签 java google-cloud-storage

我正在尝试在 Java 环境中将日志文件分块写入 Google Cloud Storage。我有一个进程可以解析原始日志文件并生成 JSON 行;我将 JSON 行存储在缓冲区中,每次缓冲区达到 5mgb 左右时,我想写入 GCS 中的同一个文件,直到完全解析原始原始源。我有一个写入 AWS S3 的类似设置。由于内存问题,分块写入。

我设法将文件写入GCS,如下所示(gcsService是配置了身份验证等的存储对象):

private void uploadStream(String path, String name, String contentType, InputStream stream, String bucketName) throws IOException, GeneralSecurityException {
    InputStreamContent contentStream = new InputStreamContent(contentType, stream);
    StorageObject objectMetadata = new StorageObject()
                .setName(path+"/"+name)
                .setAcl(Arrays.asList(new ObjectAccessControl().setEntity("allUsers").setRole("READER")));
    Storage.Objects.Insert insertRequest = gcsService.objects()
                .insert(bucketName, objectMetadata, contentStream);   
    insertRequest.execute();
}

不幸的是,我一直无法弄清楚如何以 block 的形式写入 GCS。谷歌的文档似乎提出了两种方法。其中之一涉及“可恢复”插入请求: https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload

另一种方法涉及“撰写”请求: https://cloud.google.com/storage/docs/json_api/v1/objects/compose

我一直在尝试设置“可恢复”上传,但无法使其正常工作。

有什么想法吗?我的具体问题是:

  • 将 block 上传到 GCS 的优雅和/或适当的方式是什么?
  • 有人知道如何通过 Java 中的插入请求设置到 GCS 的可断点续传上传吗?这完全可以做到吗?

最佳答案

让它工作 - 这很麻烦。作为记录,我的问题的答案是:

  • “可恢复”上传在 Java 中工作,对于将文件分块上传到 GCS 来说,这是一种优雅的方式,也许是首选方式(我不是专家,所以我不确定)。
  • 可以按照如下所述在 Java 中设置“可断点续传”上传。

我最终有两种方法 - 一种用于启动上传,另一种用于发送 block 。

private String initiateResumableUpload() throws IOException {
        String URI = "https://storage.googleapis.com/" + bucket + "/" + path;
        GenericUrl url = new GenericUrl(URI);
        HttpRequest req = requestFactory.buildPostRequest(url, new ByteArrayContent("text/plain", new byte[0]));
        HttpHeaders headers = new HttpHeaders();
        headers.set("x-goog-resumable", "start");
        headers.setContentLength((long) 0);
        headers.setContentType("text/plain");
        req.setHeaders(headers);
        req.setReadTimeout((int) DEFAULT_TIMEOUT);
        req.setResponseHeaders(headers);
        HttpResponse resp;
        try {
            resp = req.execute();
        } catch (IOException e) {
            throw e;
        }
        if (resp.getStatusCode() == 201) {
            String location = resp.getHeaders().getLocation();
            return location;

        } else {
            throw new IOException();
        }
    }

requestFactory 应该知道您适当生成的凭据。

private void writeChunk(final boolean isFinalChunk) throws HttpResponseException, IOException {
    System.out.println("Writing chunk number " + Integer.toString(chunkCount) + ".");

    try (InputStream inputStream = new ByteBufInputStream(buffer)) {
        int length = Math.min(buffer.readableBytes(), DEFAULT_UPLOAD_CHUNK_SIZE);
        HttpContent contentsend = new InputStreamContent("text/plain", inputStream);

        String URI = location;
        GenericUrl url = new GenericUrl(URI);
        HttpRequest req = requestFactory.buildPutRequest(url, contentsend);

        int offset = chunkCount*DEFAULT_UPLOAD_CHUNK_SIZE;
        long limit = offset + length;
        HttpHeaders headers = new HttpHeaders();
        headers.setContentLength((long) length);
        headers.setContentRange("bytes " + (length == 0 ? "*" : offset + "-" + (limit - 1)) + (isFinalChunk ? "/" + limit : "/*"));

        req.setHeaders(headers);

        req.setReadTimeout((int) DEFAULT_TIMEOUT);

        try {
            req.execute();
            } 
        catch (HttpResponseException e) {
                if(e.getMessage().equals("308 Resume Incomplete"))
                {
                    ++chunkCount;
                }
                else
                {
                    throw e;
                }
            }
        catch (Exception e) {
            throw e;
        }
    }
}

我的缓冲区是 io.netty.buffer.ByteBuf。

我的 GCS 相关导入是:

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.ByteArrayContent;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpContent;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseException;
import com.google.api.client.http.HttpTransport;

上面的代码可能存在一些错误,但它确实成功地将文件分块写入GCS。

我还设法通过不同的库和“撰写”请求来完成任务。但“可恢复”的方式似乎更合适。

干杯,祝你好运。

关于java - 如何通过 Java API 将 block 上传到 Google Cloud Storage?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36610398/

相关文章:

google-cloud-storage - 附加了永久性磁盘的实例的 Google Compute Engine 快照失败

python - 如何将 OAuth2Decorator 与 Google Cloud Storage 结合使用?

python - 在for循环中将文件上传到gs存储桶

java - 当我尝试删除标题栏时应用程序崩溃

Java 的 AtomicLong 实现循环

python - 带有 gspythonlibrary 的 Google 云存储

iOS/Objective-C Google Cloud Storage 上传文件

java - 同时使用 @Nonnull 和 Preconditions.checkNotNull(...)

java - Firebase 中的设备到设备通知错误 token 编号

java - 使用for循环向StringBuilder插入重复项的方法