הרכבת אובייקטים

סקירה כללית

בדף הזה מוסבר איך להרכיב כמה אובייקטים ב-Cloud Storage לאובייקט אחד. בקשת הרכבה מקבלת בין 1 ל-32 אובייקטים ויוצרת אובייקט מורכב חדש. האובייקט המורכב הוא שרשור של אובייקטי המקור לפי הסדר שבו הם צוינו בבקשה.

האובייקטים במקור לא מושפעים, אלא אם מחליטים למחוק אותם במהלך תהליך ההרכבה.

שיקולי עלות לגבי אובייקטים זמניים

אם אובייקטי המקור אמורים להיות זמניים, חשוב לשים לב לשיקולי העלויות הבאים כשיוצרים אובייקטים:

  • אובייקטי המקור כפופים למשך אחסון מינימלי, בהתאם לסוג האחסון (storage class), ויכול להיות שיחולו עליהם עמלות מחיקה מוקדמת.

  • אם מופעלת מחיקה רכה או ניהול גרסאות של אובייקטים, מחיקת אובייקטי המקור אחרי סיום ההרכבה עלולה לגרום לאובייקטי המקור להימחק רכות או להפוך ללא עדכניים, מה שעלול לגרום לחיובים נוספים על אחסון.

  • כדי לצמצם את החיוב על אובייקטים זמניים, מוחקים אותם סופית במהלך תהליך ההרכבה באמצעות האפשרות deleteSourceObjects. אובייקטים שנמחקים באמצעות האפשרות הזו לא כפופים לחיובים על מחיקה מוקדמת. בנוסף, אובייקטים שנמחקים באמצעות האפשרות הזו לא נשמרים באמצעות מחיקה רכה או ניהול גרסאות של אובייקטים, כי הנתונים נשמרים באובייקט המורכב.

התפקידים הנדרשים

כדי לקבל את ההרשאות שדרושות לכם להרכבת אובייקטים, צריך לבקש מהאדמין להקצות לכם את תפקיד ה-IAM 'משתמש באובייקטים באחסון' (roles/storage.objectUser) בקטגוריה. התפקיד המוגדר מראש הזה מכיל את ההרשאות שנדרשות להרכבת אובייקטים. כדי לראות את ההרשאות הנדרשות, מרחיבים את הקטע ההרשאות הנדרשות:

ההרשאות הנדרשות

  • storage.objects.create
  • storage.objects.delete
    • ההרשאה הזו נדרשת רק אם רוצים לתת לאובייקט המורכב שם זהה לשם של אובייקט שכבר קיים בקטגוריה.
  • storage.objects.get
  • storage.objects.list
    • ההרשאה הזו נדרשת רק אם רוצים להשתמש בתווים כלליים כדי להרכיב אובייקטים עם קידומת משותפת, בלי שתצטרכו לרשום כל אחד מהם בנפרד בפקודה של Google Cloud CLI.

אם רוצים להגדיר הגדרת שמירה לאובייקט שיוצרים, צריך גם את ההרשאה storage.objects.setRetention. כדי לקבל את ההרשאה הזו, צריך לבקש מהאדמין להקצות לכם את התפקיד 'אדמין של אובייקט אחסון' (roles/storage.objectAdmin) במקום התפקיד 'משתמש באובייקט אחסון' (roles/storage.objectUser).

אפשר לקבל את ההרשאות האלה גם באמצעות תפקידים מוגדרים מראש אחרים או תפקידים בהתאמה אישית.

במאמר הגדרה וניהול של מדיניות IAM בקטגוריות מוסבר איך מקצים תפקידים בקטגוריות.

יצירת אובייקט מורכב

שורת הפקודה

משתמשים בפקודה gcloud storage objects compose:

gcloud storage objects compose \
    gs://BUCKET_NAME/SOURCE_OBJECT_1 gs://BUCKET_NAME/SOURCE_OBJECT_2 \
    gs://BUCKET_NAME/COMPOSITE_OBJECT_NAME

כאשר:

  • BUCKET_NAME הוא שם הקטגוריה שמכילה את האובייקטים של המקור.
  • SOURCE_OBJECT_1 ו-SOURCE_OBJECT_2 הם שמות האובייקטים של המקור שבהם צריך להשתמש בהרכבת האובייקט.
  • COMPOSITE_OBJECT_NAME הוא השם שנתתם לתוצאה של הרכבת האובייקט.

כדי למחוק את אובייקטי המקור כחלק מתהליך ההרכבה, מוסיפים את הדגל --delete-source-objects לפקודה הקודמת.

ספריות לקוח

C++

למידע נוסף, קראו את מאמרי העזרה של Cloud Storage C++ API.

כדי לבצע אימות ב-Cloud Storage, אתם צריכים להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

namespace gcs = ::google::cloud::storage;
using ::google::cloud::StatusOr;
[](gcs::Client client, std::string const& bucket_name,
   std::string const& destination_object_name,
   std::vector<gcs::ComposeSourceObject> const& compose_objects) {
  StatusOr<gcs::ObjectMetadata> composed_object = client.ComposeObject(
      bucket_name, compose_objects, destination_object_name);
  if (!composed_object) throw std::move(composed_object).status();

  std::cout << "Composed new object " << composed_object->name()
            << " in bucket " << composed_object->bucket()
            << "\nFull metadata: " << *composed_object << "\n";
}

C#

למידע נוסף, קראו את מאמרי העזרה של Cloud Storage C# API.

כדי לבצע אימות ב-Cloud Storage, אתם צריכים להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.


using Google.Apis.Storage.v1.Data;
using Google.Cloud.Storage.V1;
using System;
using System.Collections.Generic;

public class ComposeObjectSample
{
    /// <summary>
    /// Combines multiple source objects into a single target object within a specified bucket,
    /// with the option to delete the original source objects upon successful composition.
    /// </summary>
    /// <param name="bucketName">The name of the bucket containing the source objects.</param>
    /// <param name="firstObjectName">The name of the first source object to be composed.</param>
    /// <param name="secondObjectName">The name of the second source object to be composed.</param>
    /// <param name="targetObjectName">The name for the newly created composite object.</param>
    /// <param name="deleteSourceObjects">If set to <c>true</c>, the method will automatically delete <paramref name="firstObjectName"/> and <paramref name="secondObjectName"/> upon successful composition.
    /// Defaults to <c>false</c>.</param>
    public void ComposeObject(
        string bucketName = "your-bucket-name",
        string firstObjectName = "your-first-object-name",
        string secondObjectName = "your-second-object-name",
        string targetObjectName = "new-composite-object-name",
        bool deleteSourceObjects = false)
    {
        var storage = StorageClient.Create();

        var sourceObjects = new List<ComposeRequest.SourceObjectsData>
        {
            new ComposeRequest.SourceObjectsData { Name = firstObjectName },
            new ComposeRequest.SourceObjectsData { Name = secondObjectName }
        };
        //You could add as many sourceObjects as you want here, up to the max of 32.

        storage.Service.Objects.Compose(new ComposeRequest
        {
            DeleteSourceObjects = deleteSourceObjects,
            SourceObjects = sourceObjects,
            Destination = new Google.Apis.Storage.v1.Data.Object { ContentType = "text/plain" }
        }, bucketName, targetObjectName).Execute();

        string deletionMessage = deleteSourceObjects ? " and the source objects were deleted." : ".";
        Console.WriteLine($"New composite file {targetObjectName} was created in bucket {bucketName}" +
            $" by combining {firstObjectName} and {secondObjectName}{deletionMessage}");
    }
}

Go

למידע נוסף, קראו את מאמרי העזרה של Cloud Storage Go API.

כדי לבצע אימות ב-Cloud Storage, אתם צריכים להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

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

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

// composeFile composes source objects to create a composite object.
func composeFile(w io.Writer, bucket, object1, object2, toObject string) error {
	// bucket := "bucket-name"
	// object1 := "object-name-1"
	// object2 := "object-name-2"
	// toObject := "object-name-3"

	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("storage.NewClient: %w", err)
	}
	defer client.Close()

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

	src1 := client.Bucket(bucket).Object(object1)
	src2 := client.Bucket(bucket).Object(object2)
	dst := client.Bucket(bucket).Object(toObject)

	// ComposerFrom takes varargs, so you can put as many objects here
	// as you want.
	_, err = dst.ComposerFrom(src1, src2).Run(ctx)
	if err != nil {
		return fmt.Errorf("ComposerFrom: %w", err)
	}
	fmt.Fprintf(w, "New composite object %v was created by combining %v and %v\n", toObject, object1, object2)
	return nil
}

Java

למידע נוסף, קראו את מאמרי העזרה של Cloud Storage Java API.

כדי לבצע אימות ב-Cloud Storage, אתם צריכים להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

public class ComposeObject {
  public static void composeObject(
      String bucketName,
      String firstObjectName,
      String secondObjectName,
      String targetObjectName,
      String projectId) {
    // 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 the first GCS object to compose
    // String firstObjectName = "your-first-object-name";

    // The ID of the second GCS object to compose
    // String secondObjectName = "your-second-object-name";

    // The ID to give the new composite object
    // String targetObjectName = "new-composite-object-name";

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();

    // Optional: set a generation-match precondition to avoid potential race
    // conditions and data corruptions. The request returns a 412 error if the
    // preconditions are not met.
    Storage.BlobTargetOption precondition;
    if (storage.get(bucketName, targetObjectName) == null) {
      // For a target object that does not yet exist, set the DoesNotExist precondition.
      // This will cause the request to fail if the object is created before the request runs.
      precondition = Storage.BlobTargetOption.doesNotExist();
    } else {
      // If the destination already exists in your bucket, instead set a generation-match
      // precondition. This will cause the request to fail if the existing object's generation
      // changes before the request runs.
      precondition =
          Storage.BlobTargetOption.generationMatch(
              storage.get(bucketName, targetObjectName).getGeneration());
    }

    Storage.ComposeRequest composeRequest =
        Storage.ComposeRequest.newBuilder()
            // addSource takes varargs, so you can put as many objects here as you want, up to the
            // max of 32
            .addSource(firstObjectName, secondObjectName)
            .setTarget(BlobInfo.newBuilder(bucketName, targetObjectName).build())
            .setTargetOptions(precondition)
            .build();

    Blob compositeObject = storage.compose(composeRequest);

    System.out.println(
        "New composite object "
            + compositeObject.getName()
            + " was created by combining "
            + firstObjectName
            + " and "
            + secondObjectName);
  }
}

Node.js

למידע נוסף, קראו את מאמרי העזרה של Cloud Storage Node.js API.

כדי לבצע אימות ב-Cloud Storage, אתם צריכים להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

/**
 * 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 the first GCS file to compose
// const firstFileName = 'your-first-file-name';

// The ID of the second GCS file to compose
// const secondFileName = 'your-second-file-name';

// The ID to give the new composite file
// const destinationFileName = 'new-composite-file-name';

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

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

async function composeFile() {
  const bucket = storage.bucket(bucketName);
  const sources = [firstFileName, secondFileName];

  // Optional:
  // Set a generation-match precondition to avoid potential race conditions
  // and data corruptions. The request to compose is aborted if the object's
  // generation number does not match your precondition. For a destination
  // object that does not yet exist, set the ifGenerationMatch precondition to 0
  // If the destination object already exists in your bucket, set instead a
  // generation-match precondition using its generation number.
  const combineOptions = {
    ifGenerationMatch: destinationGenerationMatchPrecondition,
  };
  await bucket.combine(sources, destinationFileName, combineOptions);

  console.log(
    `New composite file ${destinationFileName} was created by combining ${firstFileName} and ${secondFileName}`
  );
}

composeFile().catch(console.error);

PHP

למידע נוסף, קראו את מאמרי העזרה של Cloud Storage PHP API.

כדי לבצע אימות ב-Cloud Storage, אתם צריכים להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

use Google\Cloud\Storage\StorageClient;

/**
 * Compose two objects into a single target object.
 *
 * @param string $bucketName The name of your Cloud Storage bucket.
 *        (e.g. 'my-bucket')
 * @param string $firstObjectName The name of the first GCS object to compose.
 *        (e.g. 'my-object-1')
 * @param string $secondObjectName The name of the second GCS object to compose.
 *        (e.g. 'my-object-2')
 * @param string $targetObjectName The name of the object to be created.
 *        (e.g. 'composed-my-object-1-my-object-2')
 */
function compose_file(string $bucketName, string $firstObjectName, string $secondObjectName, string $targetObjectName): void
{
    $storage = new StorageClient();
    $bucket = $storage->bucket($bucketName);

    // In this example, we are composing only two objects, but Cloud Storage supports
    // composition of up to 32 objects.
    $objectsToCompose = [$firstObjectName, $secondObjectName];

    $targetObject = $bucket->compose($objectsToCompose, $targetObjectName, [
        'destination' => [
            'contentType' => 'application/octet-stream'
        ]
    ]);

    if ($targetObject->exists()) {
        printf(
            'New composite object %s was created by combining %s and %s',
            $targetObject->name(),
            $firstObjectName,
            $secondObjectName
        );
    }
}

Python

למידע נוסף, קראו את מאמרי העזרה של Cloud Storage Python API.

כדי לבצע אימות ב-Cloud Storage, אתם צריכים להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

from google.cloud import storage


def compose_file(bucket_name, first_blob_name, second_blob_name, destination_blob_name):
    """Concatenate source blobs into destination blob."""
    # bucket_name = "your-bucket-name"
    # first_blob_name = "first-object-name"
    # second_blob_name = "second-blob-name"
    # destination_blob_name = "destination-object-name"

    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    destination = bucket.blob(destination_blob_name)
    destination.content_type = "text/plain"

    # Note sources is a list of Blob instances, up to the max of 32 instances per request
    sources = [bucket.blob(first_blob_name), bucket.blob(second_blob_name)]

    # Optional: set a generation-match precondition to avoid potential race conditions
    # and data corruptions. The request to compose is aborted if the object's
    # generation number does not match your precondition. For a destination
    # object that does not yet exist, set the if_generation_match precondition to 0.
    # If the destination object already exists in your bucket, set instead a
    # generation-match precondition using its generation number.
    # There is also an `if_source_generation_match` parameter, which is not used in this example.
    destination_generation_match_precondition = 0

    destination.compose(sources, if_generation_match=destination_generation_match_precondition)

    print(
        "New composite object {} in the bucket {} was created by combining {} and {}".format(
            destination_blob_name, bucket_name, first_blob_name, second_blob_name
        )
    )
    return destination

Ruby

למידע נוסף, קראו את מאמרי העזרה של Cloud Storage Ruby API.

כדי לבצע אימות ב-Cloud Storage, אתם צריכים להגדיר את Application Default Credentials. מידע נוסף זמין במאמר הגדרת אימות לספריות לקוח.

def compose_file bucket_name:, first_file_name:, second_file_name:, destination_file_name:
  # The ID of your GCS bucket
  # bucket_name = "your-unique-bucket-name"

  # The ID of the first GCS object to compose
  # first_file_name = "your-first-file-name"

  # The ID of the second GCS object to compose
  # second_file_name = "your-second-file-name"

  # The ID to give the new composite object
  # destination_file_name = "new-composite-file-name"

  require "google/cloud/storage"

  storage = Google::Cloud::Storage.new
  bucket = storage.bucket bucket_name, skip_lookup: true

  destination = bucket.compose [first_file_name, second_file_name], destination_file_name do |f|
    f.content_type = "text/plain"
  end

  puts "Composed new file #{destination.name} in the bucket #{bucket_name} " \
       "by combining #{first_file_name} and #{second_file_name}"
end

Rust

use google_cloud_storage::client::StorageControl;
use google_cloud_storage::model::{Object, compose_object_request::SourceObject};

pub async fn sample(client: &StorageControl, bucket_id: &str) -> anyhow::Result<()> {
    const COMPOSE_SOURCE_1: &str = "compose-source-object-1";
    const COMPOSE_SOURCE_2: &str = "compose-source-object-2";
    const DESTINATION_NAME: &str = "compose-destination-object";
    let object = client
        .compose_object()
        .set_destination(
            Object::new()
                .set_bucket(format!("projects/_/buckets/{bucket_id}"))
                .set_name(DESTINATION_NAME),
        )
        .set_source_objects([
            SourceObject::new().set_name(COMPOSE_SOURCE_1),
            SourceObject::new().set_name(COMPOSE_SOURCE_2),
        ])
        // Consider .set_generation() to make request idempotent
        // Consider .set_delete_source_objects() to automatically delete the source objects
        .send()
        .await?;
    println!(
        "successfully composed {COMPOSE_SOURCE_1} and {COMPOSE_SOURCE_2} into object {object:?}"
    );
    Ok(())
}

ממשקי API ל-REST

‫API בפורמט JSON

  1. התקנה והפעלה של ה-CLI של gcloud, שמאפשרות ליצור אסימון גישה לכותרת Authorization.

  2. יוצרים קובץ JSON שמכיל את הפרטים הבאים:

    {
      "sourceObjects": [
        {
          "name": "SOURCE_OBJECT_1"
        },
        {
          "name": "SOURCE_OBJECT_2"
        }
      ],
      "destination": {
        "contentType": "COMPOSITE_OBJECT_CONTENT_TYPE"
      },
      "deleteSourceObjects": DELETE_SOURCE_OBJECTS_BOOLEAN
    }

    כאשר:

  3. משתמשים ב-cURL כדי לשלוח קריאה ל-API בפורמט JSON באמצעות בקשה של אובייקט POST:

    curl -X POST --data-binary @JSON_FILE_NAME \
      -H "Authorization: Bearer $(gcloud auth print-access-token)" \
      -H "Content-Type: application/json" \
      "https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o/COMPOSITE_OBJECT_NAME/compose"

    כאשר:

    • JSON_FILE_NAME הוא שם הקובץ שיצרתם בשלב הקודם.
    • BUCKET_NAME הוא שם הקטגוריה שמכילה את האובייקטים של המקור.
    • COMPOSITE_OBJECT_NAME הוא השם שנתתם לתוצאה של הרכבת האובייקט.

אם הפעולה בוצעה ללא שגיאות, התגובה היא משאב אובייקט לאובייקט המורכב שמתקבל.

‫API בפורמט XML

  1. התקנה והפעלה של ה-CLI של gcloud, שמאפשרות ליצור אסימון גישה לכותרת Authorization.

  2. יוצרים קובץ XML שמכיל את הפרטים הבאים:

      <ComposeRequest>
        <Component>
          <Name>SOURCE_OBJECT_1</Name>
        </Component>
        <Component>
          <Name>SOURCE_OBJECT_2</Name>
        </Component>
      </ComposeRequest>

    כאשר:

    • SOURCE_OBJECT_1 ו-SOURCE_OBJECT_2 הם שמות האובייקטים של המקור שבהם צריך להשתמש בהרכבת האובייקט.
  3. משתמשים ב- cURL כדי לשלוח קריאה ל-API בפורמט XML באמצעות בקשת אובייקט PUT שכוללת את פרמטר מחרוזת השאילתה compose:

    curl -X PUT --data-binary @XML_FILE_NAME \
      -H "Authorization: Bearer $(gcloud auth print-access-token)" \
      -H "Content-Type: COMPOSITE_OBJECT_CONTENT_TYPE" \
      "https://storage.googleapis.com/BUCKET_NAME/COMPOSITE_OBJECT_NAME?compose"

    כאשר:

    • XML_FILE_NAME הוא שם הקובץ שיצרתם בשלב הקודם.
    • COMPOSITE_OBJECT_CONTENT_TYPE הוא סוג התוכן של האובייקט המורכב שמתקבל.
    • BUCKET_NAME הוא שם הקטגוריה שמכילה את האובייקטים של המקור.
    • COMPOSITE_OBJECT_NAME הוא השם שנתתם לתוצאה של הרכבת האובייקט.

אם הפעולה בוצעה ללא שגיאות, מוחזר גוף תגובה ריק.

המאמרים הבאים