The File class represents a Cloud Storage object/file with comprehensive methods for upload, download, management, encryption, and access control.
class File extends ServiceObject {
constructor(bucket: Bucket, name: string, options?: FileOptions);
// Properties
name: string;
bucket: Bucket;
storage: Storage;
acl: Acl;
generation?: number;
kmsKeyName?: string;
userProject?: string;
// Upload/Download methods
save(data: SaveData, options?: SaveOptions): Promise<void>;
createWriteStream(options?: CreateWriteStreamOptions): Writable;
createResumableUpload(options?: CreateResumableUploadOptions): Promise<CreateResumableUploadResponse>;
download(options?: DownloadOptions): Promise<DownloadResponse>;
createReadStream(options?: CreateReadStreamOptions): Readable;
// File management methods
exists(options?: FileExistsOptions): Promise<FileExistsResponse>;
get(options?: GetFileOptions): Promise<GetFileResponse>;
getMetadata(options?: GetFileMetadataOptions): Promise<GetFileMetadataResponse>;
setMetadata(metadata: FileMetadata, options?: SetFileMetadataOptions): Promise<SetFileMetadataResponse>;
copy(destination: string | Bucket | File, options?: CopyOptions): Promise<CopyResponse>;
move(destination: string | Bucket | File, options?: MoveOptions): Promise<MoveResponse>;
delete(options?: DeleteFileOptions): Promise<DeleteFileResponse>;
}
interface FileOptions {
encryptionKey?: string | Buffer;
generation?: number | string;
kmsKeyName?: string;
userProject?: string;
}save(data: SaveData, options?: SaveOptions): Promise<void>
type SaveData = string | Buffer | Uint8Array;
interface SaveOptions {
encryptionKey?: string | Buffer;
gzip?: boolean;
metadata?: FileMetadata;
offset?: number;
predefinedAcl?: PredefinedAcl;
private?: boolean;
public?: boolean;
resumable?: boolean;
timeout?: number;
uri?: string;
userProject?: string;
validation?: string | boolean;
preconditionOpts?: PreconditionOptions;
}
// Save string data
await file.save('Hello, World!');
// Save buffer data
const buffer = Buffer.from('Binary data', 'utf8');
await file.save(buffer);
// Save with metadata
await file.save('File content', {
metadata: {
contentType: 'text/plain',
cacheControl: 'no-cache',
metadata: {
author: 'user-123',
version: '1.0'
}
}
});
// Save with compression
await file.save('Large text content...', {
gzip: true,
metadata: {
contentEncoding: 'gzip'
}
});
// Save with encryption
await file.save('Secret data', {
encryptionKey: crypto.randomBytes(32).toString('base64')
});
// Save with access control
await file.save('Public content', {
public: true
});createWriteStream(options?: CreateWriteStreamOptions): Writable
interface CreateWriteStreamOptions {
chunkSize?: number;
encryptionKey?: string | Buffer;
gzip?: boolean;
metadata?: FileMetadata;
offset?: number;
predefinedAcl?: PredefinedAcl;
private?: boolean;
public?: boolean;
resumable?: boolean;
timeout?: number;
uri?: string;
userProject?: string;
validation?: string | boolean;
preconditionOpts?: PreconditionOptions;
}
// Basic write stream
const writeStream = file.createWriteStream();
writeStream.write('First chunk\n');
writeStream.write('Second chunk\n');
writeStream.end();
// Stream from file with metadata
const writeStream = file.createWriteStream({
metadata: {
contentType: 'application/json'
}
});
fs.createReadStream('/local/file.json').pipe(writeStream);
// Resumable upload for large files
const writeStream = file.createWriteStream({
resumable: true,
chunkSize: 256 * 1024, // 256KB chunks
metadata: {
contentType: 'video/mp4'
}
});
writeStream.on('error', (err) => {
console.error('Upload failed:', err);
});
writeStream.on('finish', () => {
console.log('Upload completed');
});
// Compressed upload
const writeStream = file.createWriteStream({
gzip: true,
metadata: {
contentEncoding: 'gzip'
}
});
// Pipeline with transformation
const zlib = require('zlib');
fs.createReadStream('/large/file.txt')
.pipe(zlib.createGzip())
.pipe(writeStream);createResumableUpload(options?: CreateResumableUploadOptions): Promise<CreateResumableUploadResponse>
interface CreateResumableUploadOptions {
chunkSize?: number;
configPath?: string;
encryptionKey?: string | Buffer;
generation?: number;
kmsKeyName?: string;
metadata?: FileMetadata;
offset?: number;
origin?: string;
predefinedAcl?: PredefinedAcl;
private?: boolean;
public?: boolean;
uri?: string;
userProject?: string;
preconditionOpts?: PreconditionOptions;
}
type CreateResumableUploadResponse = [string]; // [resumeUri]
// Create resumable upload session
const [resumeUri] = await file.createResumableUpload({
chunkSize: 1024 * 1024, // 1MB chunks
metadata: {
contentType: 'application/octet-stream'
}
});
console.log('Resume URI:', resumeUri);
// Resume upload later
const writeStream = file.createWriteStream({
uri: resumeUri
});download(options?: DownloadOptions): Promise<DownloadResponse>
interface DownloadOptions {
destination?: string;
start?: number;
end?: number;
validation?: string | boolean;
userProject?: string;
decompress?: boolean;
}
type DownloadResponse = [Buffer]; // [fileContents]
// Download entire file
const [contents] = await file.download();
console.log('File contents:', contents.toString());
// Download to local file
await file.download({
destination: '/local/path/downloaded-file.txt'
});
// Download byte range
const [partialContents] = await file.download({
start: 0,
end: 1023 // First 1KB
});
// Download with decompression
const [contents] = await file.download({
decompress: true // Auto-decompress gzipped files
});
// Download without validation (faster)
const [contents] = await file.download({
validation: false
});createReadStream(options?: CreateReadStreamOptions): Readable
interface CreateReadStreamOptions {
start?: number;
end?: number;
validation?: string | boolean;
userProject?: string;
decompress?: boolean;
}
// Basic read stream
const readStream = file.createReadStream();
readStream.pipe(fs.createWriteStream('/local/output.txt'));
// Stream byte range
const readStream = file.createReadStream({
start: 1024,
end: 2047 // Bytes 1024-2047
});
// Stream with decompression
const readStream = file.createReadStream({
decompress: true
});
// Stream processing
file.createReadStream()
.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes`);
})
.on('end', () => {
console.log('Download completed');
})
.on('error', (err) => {
console.error('Download failed:', err);
});
// Transform stream
const zlib = require('zlib');
file.createReadStream()
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('/local/uncompressed.txt'));exists(options?: FileExistsOptions): Promise<FileExistsResponse>
interface FileExistsOptions {
userProject?: string;
}
type FileExistsResponse = [boolean]; // [exists]
// Check if file exists
const [exists] = await file.exists();
if (exists) {
console.log('File exists');
} else {
console.log('File does not exist');
}get(options?: GetFileOptions): Promise<GetFileResponse>
interface GetFileOptions extends GetFileMetadataOptions {
autoCreate?: boolean;
generation?: number;
}
type GetFileResponse = [File, unknown]; // [file, apiResponse]
// Get file (create empty file if doesn't exist)
const [file] = await file.get({
autoCreate: true
});getMetadata(options?: GetFileMetadataOptions): Promise<GetFileMetadataResponse>
setMetadata(metadata: FileMetadata, options?: SetFileMetadataOptions): Promise<SetFileMetadataResponse>
interface GetFileMetadataOptions {
userProject?: string;
generation?: number;
ifGenerationMatch?: number;
ifGenerationNotMatch?: number;
ifMetagenerationMatch?: number;
ifMetagenerationNotMatch?: number;
}
interface FileMetadata {
acl?: AclMetadata[];
bucket?: string;
cacheControl?: string;
componentCount?: number;
contentDisposition?: string;
contentEncoding?: string;
contentLanguage?: string;
contentType?: string;
crc32c?: string;
customTime?: string;
customerEncryption?: {
encryptionAlgorithm?: string;
keySha256?: string;
};
etag?: string;
eventBasedHold?: boolean;
generation?: string;
id?: string;
kmsKeyName?: string;
md5Hash?: string;
mediaLink?: string;
metadata?: { [key: string]: string };
metageneration?: string;
name?: string;
owner?: {
entity?: string;
entityId?: string;
};
retentionExpirationTime?: string;
selfLink?: string;
size?: string;
storageClass?: string;
temporaryHold?: boolean;
timeCreated?: string;
timeDeleted?: string;
updated?: string;
}
type GetFileMetadataResponse = [FileMetadata, unknown]; // [metadata, apiResponse]
type SetFileMetadataResponse = [FileMetadata, unknown]; // [metadata, apiResponse]
// Get file metadata
const [metadata] = await file.getMetadata();
console.log('File size:', metadata.size);
console.log('Content type:', metadata.contentType);
console.log('Created:', metadata.timeCreated);
console.log('MD5 hash:', metadata.md5Hash);
// Set custom metadata
await file.setMetadata({
metadata: {
author: 'john-doe',
version: '2.1',
category: 'document'
}
});
// Update content headers
await file.setMetadata({
contentType: 'application/pdf',
contentDisposition: 'attachment; filename="report.pdf"',
cacheControl: 'public, max-age=3600'
});
// Set custom time (for lifecycle rules)
await file.setMetadata({
customTime: '2023-12-31T23:59:59Z'
});
// Set holds (for retention)
await file.setMetadata({
temporaryHold: true,
eventBasedHold: false
});copy(destination: string | Bucket | File, options?: CopyOptions): Promise<CopyResponse>
interface CopyOptions {
destinationKmsKeyName?: string;
predefinedAcl?: PredefinedAcl;
token?: string;
userProject?: string;
preconditionOpts?: PreconditionOptions;
}
type CopyResponse = [File, unknown]; // [destinationFile, apiResponse]
// Copy within same bucket
const [copiedFile] = await file.copy('backup/copy-of-file.txt');
// Copy to different bucket
const destinationBucket = storage.bucket('other-bucket');
const [copiedFile] = await file.copy(destinationBucket.file('copied-file.txt'));
// Copy with different encryption
const [copiedFile] = await file.copy('encrypted-copy.txt', {
destinationKmsKeyName: 'projects/PROJECT_ID/locations/us/keyRings/ring/cryptoKeys/key'
});
// Copy with ACL
const [copiedFile] = await file.copy('public-copy.txt', {
predefinedAcl: 'publicRead'
});move(destination: string | Bucket | File, options?: MoveOptions): Promise<MoveResponse>
interface MoveOptions {
destinationKmsKeyName?: string;
predefinedAcl?: PredefinedAcl;
userProject?: string;
preconditionOpts?: PreconditionOptions;
}
type MoveResponse = [File, unknown]; // [destinationFile, apiResponse]
// Move within same bucket
const [movedFile] = await file.move('new-location/file.txt');
// Move to different bucket
const destinationBucket = storage.bucket('archive-bucket');
const [movedFile] = await file.move(destinationBucket.file('archived-file.txt'));
// Move with encryption change
const [movedFile] = await file.move('encrypted/file.txt', {
destinationKmsKeyName: 'projects/PROJECT_ID/locations/us/keyRings/ring/cryptoKeys/key'
});delete(options?: DeleteFileOptions): Promise<DeleteFileResponse>
interface DeleteFileOptions {
ignoreNotFound?: boolean;
userProject?: string;
ifGenerationMatch?: number;
ifGenerationNotMatch?: number;
ifMetagenerationMatch?: number;
ifMetagenerationNotMatch?: number;
}
type DeleteFileResponse = [unknown]; // [apiResponse]
// Delete file
await file.delete();
// Delete specific generation
await file.delete({
ifGenerationMatch: 1234567890
});
// Delete ignoring not found errors
await file.delete({
ignoreNotFound: true
});makePublic(): Promise<MakeFilePublicResponse>
makePrivate(options?: MakeFilePrivateOptions): Promise<MakeFilePrivateResponse>
interface MakeFilePrivateOptions {
strict?: boolean;
userProject?: string;
}
type MakeFilePublicResponse = [unknown]; // [apiResponse]
type MakeFilePrivateResponse = [unknown]; // [apiResponse]
// Make file publicly readable
await file.makePublic();
// Make file private
await file.makePrivate();
// Strict private (remove all access)
await file.makePrivate({
strict: true
});
// Check if file is public
const [isPublic] = await file.isPublic();
console.log('File is public:', isPublic);setStorageClass(storageClass: string, options?: SetStorageClassOptions): Promise<SetStorageClassResponse>
interface SetStorageClassOptions {
userProject?: string;
ifGenerationMatch?: number;
ifGenerationNotMatch?: number;
ifMetagenerationMatch?: number;
ifMetagenerationNotMatch?: number;
}
type SetStorageClassResponse = [unknown]; // [apiResponse]
// Available storage classes
const storageClasses = [
'STANDARD',
'NEARLINE',
'COLDLINE',
'ARCHIVE',
'DURABLE_REDUCED_AVAILABILITY'
];
// Change storage class
await file.setStorageClass('COLDLINE');
// Change with precondition
await file.setStorageClass('ARCHIVE', {
ifGenerationMatch: file.generation
});rotateEncryptionKey(encryptionKey?: string | Buffer, options?: RotateEncryptionKeyOptions): Promise<RotateEncryptionKeyResponse>
interface RotateEncryptionKeyOptions {
kmsKeyName?: string;
userProject?: string;
}
type RotateEncryptionKeyResponse = [File, unknown]; // [file, apiResponse]
// Generate new encryption key
const newKey = crypto.randomBytes(32).toString('base64');
const [file] = await file.rotateEncryptionKey(newKey);
// Rotate to KMS key
const [file] = await file.rotateEncryptionKey(undefined, {
kmsKeyName: 'projects/PROJECT_ID/locations/us/keyRings/ring/cryptoKeys/key'
});
// Remove encryption (make unencrypted)
const [file] = await file.rotateEncryptionKey();getSignedUrl(config: GetSignedUrlConfig): Promise<GetSignedUrlResponse>
interface GetSignedUrlConfig {
version: 'v2' | 'v4';
action: 'read' | 'write' | 'delete' | 'resumable';
expires: string | number | Date;
accessibleAt?: string | number | Date;
contentMd5?: string;
contentType?: string;
extensionHeaders?: { [key: string]: string };
promptSaveAs?: string;
queryParams?: { [key: string]: string };
responseDisposition?: string;
responseType?: string;
virtualHostedStyle?: boolean;
cname?: string;
}
type GetSignedUrlResponse = [string]; // [signedUrl]
// Read access (download)
const [url] = await file.getSignedUrl({
version: 'v4',
action: 'read',
expires: Date.now() + 15 * 60 * 1000 // 15 minutes
});
// Write access (upload)
const [url] = await file.getSignedUrl({
version: 'v4',
action: 'write',
expires: Date.now() + 60 * 60 * 1000, // 1 hour
contentType: 'image/jpeg'
});
// With custom response headers
const [url] = await file.getSignedUrl({
version: 'v4',
action: 'read',
expires: Date.now() + 3600000,
responseType: 'application/pdf',
responseDisposition: 'attachment; filename="document.pdf"'
});
// Resumable upload
const [url] = await file.getSignedUrl({
version: 'v4',
action: 'resumable',
expires: Date.now() + 24 * 60 * 60 * 1000 // 24 hours
});
// With query parameters
const [url] = await file.getSignedUrl({
version: 'v4',
action: 'read',
expires: Date.now() + 3600000,
queryParams: {
'response-cache-control': 'no-cache'
}
});generateSignedPostPolicyV2(options: GenerateSignedPostPolicyV2Options): Promise<GenerateSignedPostPolicyV2Response>
generateSignedPostPolicyV4(options: GenerateSignedPostPolicyV4Options): Promise<GenerateSignedPostPolicyV4Response>
interface GenerateSignedPostPolicyV2Options {
expires: string | number | Date;
equals?: string[][];
startsWith?: string[][];
acl?: string;
successRedirect?: string;
successStatus?: string;
contentLengthRange?: {
min?: number;
max?: number;
};
}
interface GenerateSignedPostPolicyV4Options {
expires: string | number | Date;
conditions?: (string | string[])[];
fields?: { [key: string]: string };
virtualHostedStyle?: boolean;
bucketBoundHostname?: string;
}
interface PolicyDocument {
expiration: string;
conditions: (string | string[] | { [key: string]: string })[];
}
interface PolicyFields {
[key: string]: string;
}
interface SignedPostPolicyV4Output {
url: string;
fields: PolicyFields;
}
type GenerateSignedPostPolicyV2Response = [PolicyDocument, string]; // [policy, signature]
type GenerateSignedPostPolicyV4Response = [SignedPostPolicyV4Output]; // [signedPostPolicy]
// V2 POST policy
const [policy, signature] = await file.generateSignedPostPolicyV2({
expires: Date.now() + 60 * 60 * 1000, // 1 hour
contentLengthRange: {
min: 1,
max: 10 * 1024 * 1024 // 10MB
}
});
// V4 POST policy (recommended)
const [signedPostPolicy] = await file.generateSignedPostPolicyV4({
expires: Date.now() + 60 * 60 * 1000,
conditions: [
['content-length-range', 1, 10 * 1024 * 1024],
['starts-with', '$content-type', 'image/']
],
fields: {
'x-goog-meta-user': 'user-123'
}
});
console.log('POST URL:', signedPostPolicy.url);
console.log('Form fields:', signedPostPolicy.fields);getExpirationDate(): Promise<GetExpirationDateResponse>
type GetExpirationDateResponse = [Date]; // [expirationDate]
// Get file expiration date (from lifecycle rules)
const [expirationDate] = await file.getExpirationDate();
if (expirationDate) {
console.log('File expires on:', expirationDate);
} else {
console.log('File does not have an expiration date');
}isPublic(): Promise<[boolean]>
// Check if file is publicly accessible
const [isPublic] = await file.isPublic();
console.log('File is public:', isPublic);type PredefinedAcl =
| 'authenticatedRead'
| 'bucketOwnerFullControl'
| 'bucketOwnerRead'
| 'private'
| 'projectPrivate'
| 'publicRead'
| 'publicReadWrite';
// Usage in upload operations
await file.save('content', {
predefinedAcl: 'publicRead'
});
// Usage in copy operations
await file.copy('new-file.txt', {
predefinedAcl: 'bucketOwnerFullControl'
});import { ApiError } from '@google-cloud/storage';
try {
const [contents] = await file.download();
} catch (error) {
if (error instanceof ApiError) {
if (error.code === 404) {
console.log('File not found');
} else if (error.code === 403) {
console.log('Access denied');
} else {
console.error(`API Error ${error.code}: ${error.message}`);
}
}
}All async methods support both Promise and callback patterns:
// Promise pattern (recommended)
const [contents] = await file.download();
// Callback pattern
file.download((err, contents) => {
if (err) {
console.error('Error:', err);
return;
}
console.log('Downloaded file contents');
});
// Callback types
interface DownloadCallback {
(err: Error | null, contents?: Buffer): void;
}
interface CopyCallback {
(err: Error | null, copiedFile?: File, apiResponse?: unknown): void;
}
interface DeleteFileCallback {
(err: Error | null, apiResponse?: unknown): void;
}