ストリーミング転送

Cloud Storage ではストリーミング転送がサポートされるため、データを最初にファイルに保存することなく、Cloud Storage アカウントと相互にデータのストリーミングを行うことができます。ストリーミングは、次のような場合に役立ちます。

  • プロセスからアップロード データを生成する場合や、状況に応じてオブジェクトを圧縮する場合など、アップロードの開始時に最終的なサイズがわからないデータをアップロードする場合。

  • Cloud Storage からプロセスにデータをダウンロードする場合。

ストリーミング時にチェックサム検証を使用する

チェックサムはアップロードの最初のリクエストでしか提供されないため、ストリーミング時に Cloud Storage のチェックサム検証を利用できないことも少なくありません。チェックサム検証は常に使用することをおすすめします。ストリーミング アップロードの完了後に手動で行うこともできますが、転送の完了後に検証を行った場合、破損を確認して削除する前に、破損したデータがアクセスされる可能性があります。

アップロードが完了してデータがアクセス可能になる前にチェックサム検証を行う必要がある場合は、ストリーミング アップロードを使用しないでください。オブジェクトの最終処理の前にチェックサム検証を行う別のアップロード オプションを使用する必要があります。

同様に、ダウンロードが完了してデータがアクセス可能になる前にチェックサム検証を行う必要がある場合は、ストリーミング ダウンロードを使用しないでください。ストリーミング ダウンロードでは Range ヘッダーが使用されますが、Cloud Storage はこのようなリクエストに対してチェックサム検証を行いません。

前提条件

前提条件は使用するツールによって異なります。

コンソール

Google Cloud コンソールを使用してこのガイドを完了するには、適切な IAM 権限が必要です。ストリーミングするバケットが、他のユーザーが作成したプロジェクトに存在する場合は、そのプロジェクトのオーナーから必要な権限を持つロールを付与してもらう必要があります。

特定のアクションに必要な権限の一覧については、Google Cloud コンソールに適用される IAM 権限をご覧ください。

関連するロールのリストについては、Cloud Storage のロールをご覧ください。また、特定の制限された権限を持つカスタムロールを作成することもできます。

コマンドライン

コマンドライン ユーティリティを使用してこのガイドを完了するには、適切な IAM 権限が必要です。ストリーミングするバケットが、他のユーザーが作成したプロジェクトに存在する場合は、そのプロジェクトのオーナーから必要な権限を持つロールを付与してもらう必要があります。

特定の操作に必要な権限の一覧については、gsutil コマンドの IAM 権限をご覧ください。

関連するロールのリストについては、Cloud Storage のロールをご覧ください。また、特定の制限された権限を持つカスタムロールを作成することもできます。

コードサンプル

Cloud Storage クライアント ライブラリを使用してこのガイドを完了するには、適切な IAM 権限が必要です。ストリーミングするバケットが、他のユーザーが作成したプロジェクトに存在する場合は、そのプロジェクトのオーナーから必要な権限を持つロールを付与してもらう必要があります。特に断りのない限り、クライアント ライブラリのリクエストは JSON API を介して行われます。

特定のアクションに必要な権限の一覧については、JSON メソッドの IAM 権限をご覧ください。

関連するロールのリストについては、Cloud Storage のロールをご覧ください。また、特定の制限された権限を持つカスタムロールを作成することもできます。

REST API

JSON API

JSON API を使用してこのガイドを完了するには、適切な IAM 権限が付与されている必要があります。ストリーミングするバケットが、他のユーザーが作成したプロジェクトに存在する場合は、そのプロジェクトのオーナーから必要な権限を持つロールを付与してもらう必要があります。

特定のアクションに必要な権限の一覧については、JSON メソッドの IAM 権限をご覧ください。

関連するロールのリストについては、Cloud Storage のロールをご覧ください。または、特定の制限された権限を持つカスタムロールを作成することもできます。

ストリーミング アップロード

次の例は、プロセスから Cloud Storage オブジェクトに対してストリーミング アップロードを行う方法を示しています。

コンソール

Google Cloud コンソールでは、ストリーミング アップロードはサポートされていません。代わりに gcloud CLI を使用してください。

コマンドライン

gcloud

  1. データを gcloud storage cp コマンドに連結し、ソース URL に対してダッシュを使用します。

    PROCESS_NAME | gcloud storage cp - gs://BUCKET_NAME/OBJECT_NAME

    ここで

    • PROCESS_NAME は、データを収集するプロセスの名前です。例: collect_measurements
    • BUCKET_NAME は、オブジェクトを含むバケットの名前です。例: my_app_bucket
    • OBJECT_NAME は、データから作成されるオブジェクトの名前です。例: data_measurements

gsutil

  1. データを gsutil cp コマンドに連結し、ソース URL に対してダッシュを使用します。

    PROCESS_NAME | gsutil cp - gs://BUCKET_NAME/OBJECT_NAME

    ここで

    • PROCESS_NAME は、データを収集するプロセスの名前です。例: collect_measurements
    • BUCKET_NAME は、オブジェクトを含むバケットの名前です。例: my_app_bucket
    • OBJECT_NAME は、データから作成されるオブジェクトの名前です。例: data_measurements

コードサンプル

C++

詳細については、Cloud Storage C++ API のリファレンス ドキュメントをご覧ください。

namespace gcs = ::google::cloud::storage;
using ::google::cloud::StatusOr;
[](gcs::Client client, std::string const& bucket_name,
   std::string const& object_name, int desired_line_count) {
  std::string const text = "Lorem ipsum dolor sit amet";
  gcs::ObjectWriteStream stream =
      client.WriteObject(bucket_name, object_name);

  for (int lineno = 0; lineno != desired_line_count; ++lineno) {
    // Add 1 to the counter, because it is conventional to number lines
    // starting at 1.
    stream << (lineno + 1) << ": " << text << "\n";
  }

  stream.Close();

  StatusOr<gcs::ObjectMetadata> metadata = std::move(stream).metadata();
  if (!metadata) throw std::runtime_error(metadata.status().message());
  std::cout << "Successfully wrote to object " << metadata->name()
            << " its size is: " << metadata->size()
            << "\nFull metadata: " << *metadata << "\n";
}

C#

詳細については、Cloud Storage C# API のリファレンス ドキュメントをご覧ください。


using Google.Cloud.Storage.V1;
using System;
using System.IO;

public class UploadFileSample
{
    public void UploadFile(
        string bucketName = "your-unique-bucket-name",
        string localPath = "my-local-path/my-file-name",
        string objectName = "my-file-name")
    {
        var storage = StorageClient.Create();
        using var fileStream = File.OpenRead(localPath);
        storage.UploadObject(bucketName, objectName, null, fileStream);
        Console.WriteLine($"Uploaded {objectName}.");
    }
}

Go

詳細については、Cloud Storage Go API のリファレンス ドキュメントをご覧ください。

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/storage"
)

// streamFileUpload uploads an object via a stream.
func streamFileUpload(w io.Writer, bucket, object string) error {
	// bucket := "bucket-name"
	// object := "object-name"
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("storage.NewClient: %v", err)
	}
	defer client.Close()

	b := []byte("Hello world.")
	buf := bytes.NewBuffer(b)

	ctx, cancel := context.WithTimeout(ctx, time.Second*50)
	defer cancel()

	// Upload an object with storage.Writer.
	wc := client.Bucket(bucket).Object(object).NewWriter(ctx)
	wc.ChunkSize = 0 // note retries are not supported for chunk size 0.

	if _, err = io.Copy(wc, buf); err != nil {
		return fmt.Errorf("io.Copy: %v", err)
	}
	// Data can continue to be added to the file until the writer is closed.
	if err := wc.Close(); err != nil {
		return fmt.Errorf("Writer.Close: %v", err)
	}
	fmt.Fprintf(w, "%v uploaded to %v.\n", object, bucket)

	return nil
}

Java

詳細については、Cloud Storage Java API のリファレンス ドキュメントをご覧ください。


import com.google.cloud.WriteChannel;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

public class StreamObjectUpload {

  public static void streamObjectUpload(
      String projectId, String bucketName, String objectName, String contents) 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 ID of your GCS object
    // String objectName = "your-object-name";

    // The string of contents you wish to upload
    // String contents = "Hello world!";

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
    BlobId blobId = BlobId.of(bucketName, objectName);
    BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
    byte[] content = contents.getBytes(StandardCharsets.UTF_8);
    try (WriteChannel writer = storage.writer(blobInfo)) {
      writer.write(ByteBuffer.wrap(content));
      System.out.println(
          "Wrote to " + objectName + " in bucket " + bucketName + " using a WriteChannel.");
    }
  }
}

Node.js

詳細については、Cloud Storage Node.js API のリファレンス ドキュメントをご覧ください。

/**
 * TODO(developer): Uncomment the following lines before running the sample
 */
// The ID of your GCS bucket
// const bucketName = 'your-unique-bucket-name';

// The new ID for your GCS file
// const destFileName = 'your-new-file-name';

// The content to be uploaded in the GCS file
// const contents = 'your file content';

// Imports the Google Cloud client library
const {Storage} = require('@google-cloud/storage');

// Import Node.js stream
const stream = require('stream');

// Creates a client
const storage = new Storage();

// Get a reference to the bucket
const myBucket = storage.bucket(bucketName);

// Create a reference to a file object
const file = myBucket.file(destFileName);

// Create a pass through stream from a string
const passthroughStream = new stream.PassThrough();
passthroughStream.write(contents);
passthroughStream.end();

async function streamFileUpload() {
  passthroughStream.pipe(file.createWriteStream()).on('finish', () => {
    // The file upload is complete
  });

  console.log(`${destFileName} uploaded to ${bucketName}`);
}

streamFileUpload().catch(console.error);

PHP

詳細については、Cloud Storage PHP API のリファレンス ドキュメントをご覧ください。

use Google\Cloud\Storage\StorageClient;
use Google\Cloud\Storage\WriteStream;

/**
 * Upload a chunked file stream.
 *
 * @param string $bucketName The name of your Cloud Storage bucket.
 *        (e.g. 'my-bucket')
 * @param string $objectName The name of your Cloud Storage object.
 *        (e.g. 'my-object')
 * @param string $contents The contents to upload via stream chunks.
 *        (e.g. 'these are my contents')
 */
function upload_object_stream(string $bucketName, string $objectName, string $contents): void
{
    $storage = new StorageClient();
    $bucket = $storage->bucket($bucketName);
    $writeStream = new WriteStream(null, [
        'chunkSize' => 1024 * 256, // 256KB
    ]);
    $uploader = $bucket->getStreamableUploader($writeStream, [
        'name' => $objectName,
    ]);
    $writeStream->setUploader($uploader);
    $stream = fopen('data://text/plain,' . $contents, 'r');
    while (($line = stream_get_line($stream, 1024 * 256)) !== false) {
        $writeStream->write($line);
    }
    $writeStream->close();

    printf('Uploaded %s to gs://%s/%s' . PHP_EOL, $contents, $bucketName, $objectName);
}

Python

詳細については、Cloud Storage Python API のリファレンス ドキュメントをご覧ください。

from google.cloud import storage

def upload_blob_from_stream(bucket_name, file_obj, destination_blob_name):
    """Uploads bytes from a stream or other file-like object to a blob."""
    # The ID of your GCS bucket
    # bucket_name = "your-bucket-name"

    # The stream or file (file-like object) from which to read
    # import io
    # file_obj = io.BytesIO()
    # file_obj.write(b"This is test data.")

    # The desired name of the uploaded GCS object (blob)
    # destination_blob_name = "storage-object-name"

    # Construct a client-side representation of the blob.
    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.blob(destination_blob_name)

    # Rewind the stream to the beginning. This step can be omitted if the input
    # stream will always be at a correct position.
    file_obj.seek(0)

    # Upload data from the stream to your bucket.
    blob.upload_from_file(file_obj)

    print(
        f"Stream data uploaded to {destination_blob_name} in bucket {bucket_name}."
    )

Ruby

詳細については、Cloud Storage Ruby API のリファレンス ドキュメントをご覧ください。


# The ID of your GCS bucket
# bucket_name = "your-unique-bucket-name"

# The stream or file (file-like object) from which to read
# local_file_obj = StringIO.new "This is test data."

# Name of a file in the Storage bucket
# file_name   = "some_file.txt"

require "google/cloud/storage"

storage = Google::Cloud::Storage.new
bucket  = storage.bucket bucket_name

local_file_obj.rewind
bucket.create_file local_file_obj, file_name

puts "Stream data uploaded to #{file_name} in bucket #{bucket_name}"

REST API

JSON API

ストリーミング アップロードを行うには、次の点を考慮したうえで、再開可能なアップロードの手順を行います。

  • ファイルデータ自体をアップロードする場合は、複数のチャンクのアップロードを使用します。

  • 最終チャンクになるまで合計のファイルサイズがわからないため、中間チャンクの Content-Range ヘッダーの合計ファイルサイズに * を使用します。

    たとえば、最初にアップロードしたチャンクのサイズが 512 KiB の場合、チャンクの Content-Range ヘッダーは bytes 0-524287/* になります。最初のチャンクのアップロード後に 64,000 バイト残っている場合は、残りのバイトを含む最終チャンクを送信します。Content-Range ヘッダーには bytes 524288-588287/588288 という値が設定されます。

XML API

ストリーミング アップロードを実行するには、次のいずれかの方法を使用します。

  • XML API マルチパート アップロード

  • 次の調整を行った再開可能なアップロード:

    • ファイルデータ自体をアップロードする場合は、複数のチャンクのアップロードを使用します。

    • 最終チャンクになるまで合計のファイルサイズがわからないため、中間チャンクの Content-Range ヘッダーの合計ファイルサイズに * を使用します。

      たとえば、最初にアップロードしたチャンクのサイズが 512 KiB の場合、チャンクの Content-Range ヘッダーは bytes 0-524287/* になります。最初のチャンクのアップロード後に 64,000 バイト残っている場合は、残りのバイトを含む最終チャンクを送信します。Content-Range ヘッダーには bytes 524288-588287/588288 という値が設定されます。

ストリーミング ダウンロード

次の例は、Cloud Storage オブジェクトからプロセスへのダウンロードを実行する方法を示しています。

コンソール

Google Cloud コンソールでは、ストリーミング ダウンロードはサポートされていません。代わりに gcloud CLI を使用してください。

コマンドライン

gcloud

  1. リンク先 URL にダッシュを使用して gcloud storage cp コマンドを実行し、データをプロセスに連結します。

    gcloud storage cp gs://BUCKET_NAME/OBJECT_NAME - | PROCESS_NAME

    ここで

    • BUCKET_NAME は、オブジェクトを含むバケットの名前です。例: my_app_bucket
    • OBJECT_NAME は、プロセスにストリーミングするオブジェクトの名前です。例: data_measurements
    • PROCESS_NAME は、データをフィードするプロセスの名前です。例: analyze_data

Cloud Storage オブジェクトのデータを、sort などの Linux の標準コマンドにストリーミングすることもできます。

gcloud storage cp gs://my_app_bucket/data_measurements - | sort

gsutil

  1. リンク先 URL にダッシュを使用して gsutil cp コマンドを実行し、データをプロセスに連結します。

    gsutil cp gs://BUCKET_NAME/OBJECT_NAME - | PROCESS_NAME

    ここで

    • BUCKET_NAME は、オブジェクトを含むバケットの名前です。例: my_app_bucket
    • OBJECT_NAME は、プロセスにストリーミングするオブジェクトの名前です。例: data_measurements
    • PROCESS_NAME は、データをフィードするプロセスの名前です。例: analyze_data

Cloud Storage オブジェクトのデータを、sort などの Linux の標準コマンドにストリーミングすることもできます。

gsutil cp gs://my_app_bucket/data_measurements - | sort

コードサンプル

C++

詳細については、Cloud Storage C++ API のリファレンス ドキュメントをご覧ください。

namespace gcs = ::google::cloud::storage;
[](gcs::Client client, std::string const& bucket_name,
   std::string const& object_name) {
  gcs::ObjectReadStream stream = client.ReadObject(bucket_name, object_name);

  int count = 0;
  std::string line;
  while (std::getline(stream, line, '\n')) {
    ++count;
  }

  std::cout << "The object has " << count << " lines\n";
}

C#

詳細については、Cloud Storage C# API のリファレンス ドキュメントをご覧ください。


using Google.Cloud.Storage.V1;
using System;
using System.IO;

public class DownloadFileSample
{
    public void DownloadFile(
        string bucketName = "your-unique-bucket-name",
        string objectName = "my-file-name",
        string localPath = "my-local-path/my-file-name")
    {
        var storage = StorageClient.Create();
        using var outputFile = File.OpenWrite(localPath);
        storage.DownloadObject(bucketName, objectName, outputFile);
        Console.WriteLine($"Downloaded {objectName} to {localPath}.");
    }
}

Go

詳細については、Cloud Storage Go API のリファレンス ドキュメントをご覧ください。


import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"time"

	"cloud.google.com/go/storage"
)

// downloadFileIntoMemory downloads an object.
func downloadFileIntoMemory(w io.Writer, bucket, object string) ([]byte, error) {
	// bucket := "bucket-name"
	// object := "object-name"
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("storage.NewClient: %v", err)
	}
	defer client.Close()

	ctx, cancel := context.WithTimeout(ctx, time.Second*50)
	defer cancel()

	rc, err := client.Bucket(bucket).Object(object).NewReader(ctx)
	if err != nil {
		return nil, fmt.Errorf("Object(%q).NewReader: %v", object, err)
	}
	defer rc.Close()

	data, err := ioutil.ReadAll(rc)
	if err != nil {
		return nil, fmt.Errorf("ioutil.ReadAll: %v", err)
	}
	fmt.Fprintf(w, "Blob %v downloaded.\n", object)
	return data, nil
}

Java

詳細については、Cloud Storage Java API のリファレンス ドキュメントをご覧ください。


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.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class StreamObjectDownload {

  public static void streamObjectDownload(
      String projectId, String bucketName, String objectName, String targetFile)
      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 ID of your GCS object
    // String objectName = "your-object-name";

    // The path to the file to download the object to
    // String targetFile = "path/to/your/file";
    Path targetFilePath = Paths.get(targetFile);

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
    try (ReadChannel reader = storage.reader(BlobId.of(bucketName, objectName));
        FileChannel targetFileChannel =
            FileChannel.open(targetFilePath, StandardOpenOption.WRITE)) {

      ByteStreams.copy(reader, targetFileChannel);

      System.out.println(
          "Downloaded object "
              + objectName
              + " from bucket "
              + bucketName
              + " to "
              + targetFile
              + " using a ReadChannel.");
    }
  }
}

Node.js

詳細については、Cloud Storage Node.js API のリファレンス ドキュメントをご覧ください。

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// The ID of your GCS bucket
// const bucketName = 'your-unique-bucket-name';

// The ID of your GCS file
// const fileName = 'your-file-name';

// The filename and file path where you want to download the file
// const destFileName = '/local/path/to/file.txt';

// Imports the Google Cloud client library
const {Storage} = require('@google-cloud/storage');

// Creates a client
const storage = new Storage();

async function streamFileDownload() {
  // The example below demonstrates how we can reference a remote file, then
  // pipe its contents to a local file.
  // Once the stream is created, the data can be piped anywhere (process, sdout, etc)
  await storage
    .bucket(bucketName)
    .file(fileName)
    .createReadStream() //stream is created
    .pipe(fs.createWriteStream(destFileName))
    .on('finish', () => {
      // The file download is complete
    });

  console.log(
    `gs://${bucketName}/${fileName} downloaded to ${destFileName}.`
  );
}

streamFileDownload().catch(console.error);

PHP

詳細については、Cloud Storage PHP API のリファレンス ドキュメントをご覧ください。

use Google\Cloud\Storage\StorageClient;

/**
 * Download an object from Cloud Storage and save it as a local file.
 *
 * @param string $bucketName The name of your Cloud Storage bucket.
 *        (e.g. 'my-bucket')
 * @param string $objectName The name of your Cloud Storage object.
 *        (e.g. 'my-object')
 * @param string $destination The local destination to save the object.
 *        (e.g. '/path/to/your/file')
 */
function download_object(string $bucketName, string $objectName, string $destination): void
{
    $storage = new StorageClient();
    $bucket = $storage->bucket($bucketName);
    $object = $bucket->object($objectName);
    $object->downloadToFile($destination);
    printf(
        'Downloaded gs://%s/%s to %s' . PHP_EOL,
        $bucketName,
        $objectName,
        basename($destination)
    );
}

Python

詳細については、Cloud Storage Python API のリファレンス ドキュメントをご覧ください。

from google.cloud import storage

def download_blob_to_stream(bucket_name, source_blob_name, file_obj):
    """Downloads a blob to a stream or other file-like object."""

    # The ID of your GCS bucket
    # bucket_name = "your-bucket-name"

    # The ID of your GCS object (blob)
    # source_blob_name = "storage-object-name"

    # The stream or file (file-like object) to which the blob will be written
    # import io
    # file_obj = io.BytesIO()

    storage_client = storage.Client()

    bucket = storage_client.bucket(bucket_name)

    # Construct a client-side representation of a blob.
    # Note `Bucket.blob` differs from `Bucket.get_blob` in that it doesn't
    # retrieve metadata from Google Cloud Storage. As we don't use metadata in
    # this example, using `Bucket.blob` is preferred here.
    blob = bucket.blob(source_blob_name)
    blob.download_to_file(file_obj)

    print(f"Downloaded blob {source_blob_name} to file-like object.")

    return file_obj
    # Before reading from file_obj, remember to rewind with file_obj.seek(0).

Ruby

詳細については、Cloud Storage Ruby API のリファレンス ドキュメントをご覧ください。

# Downloads a blob to a stream or other file-like object.

# The ID of your GCS bucket
# bucket_name = "your-unique-bucket-name"

# Name of a file in the Storage bucket
# file_name   = "some_file.txt"

# The stream or file (file-like object) to which the contents will be written
# local_file_obj = StringIO.new

require "google/cloud/storage"

storage = Google::Cloud::Storage.new
bucket  = storage.bucket bucket_name
file    = bucket.file file_name

file.download local_file_obj, verify: :none

# rewind the object before starting to read the downloaded contents
local_file_obj.rewind
puts "The full downloaded file contents are: #{local_file_obj.read.inspect}"

REST API

JSON API

ストリーミング ダウンロードを行う場合は、次の点を考慮して、オブジェクトのダウンロード手順を行います。

  • ダウンロードを開始する前に、オブジェクトのメタデータを取得し、オブジェクトの世代番号を保存しておきます。元のリクエストに上書きされるときに異なる 2 世代のデータがダウンロードされないように、各リクエストにこの世代番号を含めます。

  • リクエストで Range ヘッダーを使用してオブジェクト全体の一部を取得し、それを目的のローカル プロセスに送信します。

  • オブジェクト全体が取得されるまで、オブジェクトの連続部分に対してリクエストを続行します。

XML API

ストリーミング ダウンロードを行う場合は、次の点を考慮して、オブジェクトのダウンロード手順を行います。

  • ダウンロードを開始する前に、オブジェクトのメタデータを取得し、オブジェクトの世代番号を保存しておきます。元のリクエストに上書きされるときに異なる 2 世代のデータがダウンロードされないように、各リクエストにこの世代番号を含めます。

  • リクエストで Range ヘッダーを使用してオブジェクト全体の一部を取得し、それを目的のローカル プロセスに送信します。

  • オブジェクト全体が取得されるまで、オブジェクトの連続部分に対してリクエストを続行します。

次のステップ