diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index 292403d52..948cdeeb0 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -56,5 +56,11 @@
1.1.3
test
+
+ org.apache.httpcomponents
+ httpmime
+ 4.5.13
+ test
+
diff --git a/samples/snippets/src/main/java/com/example/storage/object/DownloadByteRange.java b/samples/snippets/src/main/java/com/example/storage/object/DownloadByteRange.java
new file mode 100644
index 000000000..1eaf26cc3
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/storage/object/DownloadByteRange.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.storage.object;
+
+// [START storage_download_byte_range]
+
+
+import com.google.cloud.ReadChannel;
+import com.google.cloud.storage.BlobId;
+import com.google.cloud.storage.Storage;
+import com.google.cloud.storage.StorageOptions;
+import com.google.common.io.ByteStreams;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+
+public class DownloadByteRange {
+
+ public static void downloadByteRange(String projectId, String bucketName, String blobName,
+ long startByte, long endBytes, String destFileName) throws IOException {
+ // The ID of your GCP project
+ // String projectId = "your-project-id";
+
+ // The ID of your GCS bucket
+ // String bucketName = "your-unique-bucket-name";
+
+ // The name of the blob/file that you wish to modify permissions on
+ // String blobName = "your-blob-name";
+
+ // The starting byte at which to begin the download
+ // long startByte = 0;
+
+ // The ending byte at which to end the download
+ // long endByte = 20;
+
+ // The path to which the file should be downloaded
+ // String destFileName = '/local/path/to/file.txt';
+
+ Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
+ BlobId blobId = BlobId.of(bucketName, blobName);
+ try (
+ ReadChannel from = storage.reader(blobId);
+ FileChannel to = FileChannel.open(Paths.get(destFileName), StandardOpenOption.WRITE)
+ ) {
+ from.seek(startByte);
+ from.limit(endBytes);
+
+ ByteStreams.copy(from, to);
+
+ System.out.printf("%s downloaded to %s from byte %d to byte %d",
+ blobId.toGsUtilUri(), destFileName,
+ startByte, endBytes);
+ }
+ }
+
+}
+// [END storage_download_byte_range]
diff --git a/samples/snippets/src/test/java/com/example/storage/object/DownloadBytesRangeTest.java b/samples/snippets/src/test/java/com/example/storage/object/DownloadBytesRangeTest.java
new file mode 100644
index 000000000..2dd0e1474
--- /dev/null
+++ b/samples/snippets/src/test/java/com/example/storage/object/DownloadBytesRangeTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.storage.object;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.example.storage.TestBase;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class DownloadBytesRangeTest extends TestBase {
+
+ @Rule public final TemporaryFolder tmp = new TemporaryFolder();
+
+ @Test
+ public void testDownloadByteRange() throws IOException {
+ byte[] bytes = { // 18 elements per row
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
+ 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
+ };
+
+ blob = storage.create(blob, bytes);
+
+ File file = tmp.newFile();
+
+ int startByte = 14;
+ int endBytes = 37;
+ byte[] expectedBytes = Arrays.copyOfRange(bytes, startByte, endBytes);
+
+ try {
+ String destFileName = file.getAbsolutePath();
+ DownloadByteRange.downloadByteRange(
+ System.getenv("GOOGLE_CLOUD_PROJECT"),
+ bucketName,
+ blobName,
+ startByte,
+ endBytes,
+ destFileName
+ );
+
+ byte[] readBytes = Files.readAllBytes(Paths.get(destFileName));
+
+ assertThat(stdOut.getCapturedOutputAsUtf8String()).contains("downloaded to");
+ assertThat(stdOut.getCapturedOutputAsUtf8String()).contains("from byte 14 to byte 37");
+ assertThat(readBytes).isEqualTo(expectedBytes);
+ } finally {
+ file.delete();
+ }
+ }
+}