Redactar objetos

Descripción general

En esta página, se muestra cómo componer varios objetos de Cloud Storage en un solo objeto. Una solicitud de composición toma entre 1 y 32 objetos y crea un objeto compuesto nuevo. El objeto compuesto es una concatenación de los objetos de origen en el orden en que se especificaron en la solicitud.

Los objetos de origen no se ven afectados, a menos que decidas borrarlos durante el proceso de composición.

Consideraciones de costos para objetos temporales

Si los objetos de origen están destinados a ser temporales, ten en cuenta las siguientes consideraciones de costos cuando compongas objetos:

  • Los objetos de origen están sujetos a duraciones mínimas de almacenamiento, según la clase de almacenamiento, y pueden generar tarifas de eliminación temprana.

  • Si está habilitada la eliminación no definitiva o el control de versiones de objetos, borrar los objetos de origen después de que finalice la composición puede hacer que los objetos de origen se borren de forma no definitiva o no estén actualizados, lo que podría generar cargos de almacenamiento adicionales.

  • Para minimizar la facturación de objetos temporales, borra de forma definitiva los objetos temporales durante el proceso de composición con la opción deleteSourceObjects. Los objetos que se borran con esta opción no están sujetos a tarifas de eliminación temprana. Además, la eliminación no definitiva ni el control de versiones de objetos no conservan los objetos que se borran con esta opción, ya que los datos se conservan en el objeto compuesto.

Roles obligatorios

Para obtener los permisos que necesitas a fin de redactar objetos, pídele a tu administrador que te otorgue el rol de IAM de usuario de objetos de almacenamiento (roles/storage.objectUser) en el bucket. Este rol predefinido contiene los permisos necesarios para redactar objetos. Para ver los permisos exactos que son necesarios, expande la sección Permisos requeridos:

Permisos necesarios

  • storage.objects.create
  • storage.objects.delete
    • Este permiso solo es necesario si deseas darle al objeto que compones el mismo nombre que un objeto que ya existe en tu bucket.
  • storage.objects.get
  • storage.objects.list
    • Este permiso solo es necesario si deseas usar comodines para componer objetos con un prefijo común sin tener que enumerar cada objeto por separado en tu comando Google Cloud CLI.

Si deseas establecer una configuración de retención para el objeto que redactas, también necesitarás el permiso storage.objects.setRetention. Para obtener este permiso, pídele a tu administrador que te otorgue el rol de administrador de objetos de almacenamiento (roles/storage.objectAdmin) en lugar de la función de usuario de objetos de almacenamiento (roles/storage.objectUser).

También puedes obtener estos permisos con otros roles predefinidos o roles personalizados.

Para obtener información sobre cómo otorgar roles en los buckets, consulta Configura y administra políticas de IAM en buckets.

Crea un objeto compuesto

Línea de comandos

Usa el comando 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

Aquí:

  • BUCKET_NAME es el nombre del bucket que contiene los objetos de origen.
  • SOURCE_OBJECT_1 y SOURCE_OBJECT_2 son los nombres de los objetos de origen que se usarán en la composición del objeto.
  • COMPOSITE_OBJECT_NAME es el nombre que le asignas al resultado de la composición del objeto.

Para borrar los objetos de origen como parte del proceso de composición, incluye la marca --delete-source-objects en el comando anterior.

Bibliotecas cliente

C++

Si deseas obtener más información, consulta la documentación de referencia de la API de Cloud Storage C++.

Para autenticarte en Cloud Storage, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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#

Si deseas obtener más información, consulta la documentación de referencia de la API de Cloud Storage de C#.

Para autenticarte en Cloud Storage, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.


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

Si deseas obtener más información, consulta la documentación de referencia de la API de Cloud Storage de Go.

Para autenticarte en Cloud Storage, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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

Si deseas obtener más información, consulta la documentación de referencia de la API de Cloud Storage de Java.

Para autenticarte en Cloud Storage, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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

Si deseas obtener más información, consulta la documentación de referencia de la API de Cloud Storage de Node.js.

Para autenticarte en Cloud Storage, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

/**
 * 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

Si deseas obtener más información, consulta la documentación de referencia de la API de Cloud Storage de PHP.

Para autenticarte en Cloud Storage, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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

Si deseas obtener más información, consulta la documentación de referencia de la API de Cloud Storage de Python.

Para autenticarte en Cloud Storage, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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

Si deseas obtener más información, consulta la documentación de referencia de la API de Cloud Storage de Ruby.

Para autenticarte en Cloud Storage, configura las credenciales predeterminadas de la aplicación. Si deseas obtener más información, consulta Configura la autenticación para bibliotecas cliente.

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 de REST

API de JSON

  1. Ten la gcloud CLI instalada e inicializada, lo que te permite generar un token de acceso para el encabezado Authorization.

  2. Crea un archivo JSON que contenga la siguiente información:

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

    Aquí:

  3. Usa cURL para llamar a la API de JSON con una POST solicitud de objeto:

    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"

    Aquí:

    • JSON_FILE_NAME es el nombre del archivo que creaste en el paso anterior.
    • BUCKET_NAME es el nombre del bucket que contiene los objetos de origen.
    • COMPOSITE_OBJECT_NAME es el nombre que le asignas al resultado de la composición del objeto.

Si se ejecuta de forma correcta, la respuesta es un recurso de objeto para el objeto compuesto resultante.

API de XML

  1. Ten la gcloud CLI instalada e inicializada, lo que te permite generar un token de acceso para el encabezado Authorization.

  2. Crea un archivo en formato XML que contenga la siguiente información:

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

    Aquí:

    • SOURCE_OBJECT_1 y SOURCE_OBJECT_2 son los nombres de los objetos de origen que se usarán en la composición del objeto.
  3. Usa cURL para llamar a la API de XML con una PUT solicitud de objeto que incluya el parámetro de cadena de consulta 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"

    Aquí:

    • XML_FILE_NAME es el nombre del archivo que creaste en el paso anterior.
    • COMPOSITE_OBJECT_CONTENT_TYPE es el tipo de contenido del objeto compuesto resultante.
    • BUCKET_NAME es el nombre del bucket que contiene los objetos de origen.
    • COMPOSITE_OBJECT_NAME es el nombre que le asignas al resultado de la composición del objeto.

Si se ejecuta de forma correcta, se muestra una respuesta vacía.

¿Qué sigue?