|
5 | 5 | * you may not use this file except in compliance with the License. |
6 | 6 | * You may obtain a copy of the License at |
7 | 7 | * |
8 | | - * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
9 | 9 | * |
10 | 10 | * Unless required by applicable law or agreed to in writing, software |
11 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
16 | 16 |
|
17 | 17 | package com.example.storage.object; |
18 | 18 |
|
19 | | -// [START storage_resume_appendable_object_upload] |
| 19 | +// [START storage_pause_and_resume_appendable_object_upload] |
20 | 20 |
|
21 | 21 | import com.google.cloud.storage.Blob; |
22 | 22 | import com.google.cloud.storage.BlobAppendableUpload; |
|
26 | 26 | import com.google.cloud.storage.BlobId; |
27 | 27 | import com.google.cloud.storage.BlobInfo; |
28 | 28 | import com.google.cloud.storage.Storage; |
| 29 | +import com.google.cloud.storage.StorageChannelUtils; |
29 | 30 | import com.google.cloud.storage.StorageOptions; |
30 | 31 | import com.google.common.io.ByteStreams; |
31 | 32 | import java.io.IOException; |
| 33 | +import java.nio.ByteBuffer; |
32 | 34 | import java.nio.channels.FileChannel; |
| 35 | +import java.nio.charset.StandardCharsets; |
33 | 36 | import java.nio.file.Paths; |
34 | 37 | import java.util.Locale; |
35 | 38 |
|
36 | | -public class ResumeAppendableObjectUpload { |
37 | | - public static void resumeAppendableObjectUpload( |
| 39 | +public class PauseAndResumeAppendableObjectUpload { |
| 40 | + public static void pauseAndResumeAppendableObjectUpload( |
38 | 41 | String bucketName, String objectName, String filePath) throws Exception { |
39 | 42 | // The ID of your GCS bucket |
40 | 43 | // String bucketName = "your-unique-bucket-name"; |
41 | 44 |
|
42 | | - // The ID of your GCS unfinalized appendable object |
| 45 | + // The ID of your GCS object |
43 | 46 | // String objectName = "your-object-name"; |
44 | 47 |
|
45 | 48 | // The path to the file to upload |
46 | 49 | // String filePath = "path/to/your/file"; |
47 | 50 |
|
48 | 51 | try (Storage storage = StorageOptions.grpc().build().getService()) { |
49 | 52 | BlobId blobId = BlobId.of(bucketName, objectName); |
50 | | - Blob existingBlob = storage.get(blobId); |
51 | | - BlobInfo blobInfoForTakeover = BlobInfo.newBuilder(existingBlob.getBlobId()).build(); |
| 53 | + BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build(); |
| 54 | + |
| 55 | + // --- Step 1: Initial string write (PAUSE) --- |
| 56 | + // Default close action will be CLOSE_WITHOUT_FINALIZING |
| 57 | + BlobAppendableUploadConfig initialConfig = BlobAppendableUploadConfig.of(); |
| 58 | + BlobAppendableUpload initialUploadSession = |
| 59 | + storage.blobAppendableUpload(blobInfo, initialConfig); |
| 60 | + |
| 61 | + try (AppendableUploadWriteableByteChannel channel = initialUploadSession.open()) { |
| 62 | + String initialData = "Initial data segment.\n"; |
| 63 | + ByteBuffer buffer = ByteBuffer.wrap(initialData.getBytes(StandardCharsets.UTF_8)); |
| 64 | + long totalBytesWritten = StorageChannelUtils.blockingEmptyTo(buffer, channel); |
| 65 | + channel.flush(); |
| 66 | + |
| 67 | + System.out.printf( |
| 68 | + Locale.US, "Wrote %d bytes (initial string) in first segment.\n", totalBytesWritten); |
| 69 | + } catch (IOException ex) { |
| 70 | + throw new IOException("Failed initial upload to object " + blobId.toGsUtilUri(), ex); |
| 71 | + } |
52 | 72 |
|
| 73 | + Blob existingBlob = storage.get(blobId); |
53 | 74 | long currentObjectSize = existingBlob.getSize(); |
54 | 75 | System.out.printf( |
55 | 76 | Locale.US, |
56 | | - "Resuming upload for %s. Currently uploaded size: %d bytes\n", |
57 | | - blobId.toGsUtilUri(), |
| 77 | + "Initial upload paused. Currently uploaded size: %d bytes\n", |
58 | 78 | currentObjectSize); |
59 | 79 |
|
60 | | - BlobAppendableUploadConfig config = |
61 | | - BlobAppendableUploadConfig.of().withCloseAction(CloseAction.CLOSE_WITHOUT_FINALIZING); |
| 80 | + // --- Step 2: Resume upload with file content and finalize --- |
| 81 | + // Use FINALIZE_WHEN_CLOSING to ensure the object is finalized on channel closure. |
| 82 | + BlobAppendableUploadConfig resumeConfig = |
| 83 | + BlobAppendableUploadConfig.of().withCloseAction(CloseAction.FINALIZE_WHEN_CLOSING); |
62 | 84 | BlobAppendableUpload resumeUploadSession = |
63 | | - storage.blobAppendableUpload(blobInfoForTakeover, config); |
| 85 | + storage.blobAppendableUpload(existingBlob.toBuilder().build(), resumeConfig); |
| 86 | + |
64 | 87 | try (FileChannel fileChannel = FileChannel.open(Paths.get(filePath)); |
65 | 88 | AppendableUploadWriteableByteChannel channel = resumeUploadSession.open()) { |
| 89 | + long bytesToAppend = fileChannel.size(); |
| 90 | + System.out.printf( |
| 91 | + Locale.US, |
| 92 | + "Appending the entire file (%d bytes) after the initial string.\n", |
| 93 | + bytesToAppend); |
66 | 94 |
|
67 | | - if (fileChannel.size() < currentObjectSize) { |
68 | | - throw new IOException( |
69 | | - "Local file is smaller than the already uploaded data. File size: " |
70 | | - + fileChannel.size() |
71 | | - + ", Uploaded size: " |
72 | | - + currentObjectSize); |
73 | | - } else if (fileChannel.size() == currentObjectSize) { |
74 | | - System.out.println("No more data to upload."); |
75 | | - } else { |
76 | | - fileChannel.position(currentObjectSize); |
77 | | - System.out.printf( |
78 | | - Locale.US, "Appending %d bytes\n", fileChannel.size() - currentObjectSize); |
79 | | - ByteStreams.copy(fileChannel, channel); |
80 | | - } |
| 95 | + ByteStreams.copy(fileChannel, channel); |
81 | 96 | } |
| 97 | + |
82 | 98 | BlobInfo result = storage.get(blobId); |
83 | 99 | System.out.printf( |
84 | 100 | Locale.US, |
85 | | - "Object %s successfully resumed. Total size: %d\n", |
| 101 | + "\nObject %s successfully resumed and finalized. Total size: %d bytes\n", |
86 | 102 | result.getBlobId().toGsUtilUriWithGeneration(), |
87 | 103 | result.getSize()); |
88 | 104 | } |
89 | 105 | } |
90 | 106 | } |
91 | | -// [END storage_resume_appendable_object_upload] |
| 107 | +// [END storage_pause_and_resume_appendable_object_upload] |
0 commit comments