or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

blob-client.mdcontainer-client.mdindex.mdmodels.mdoptions.mdsecurity.mdservice-client.mdspecialized-clients.mdstreaming.md

blob-client.mddocs/

0

# Blob Client Operations

1

2

Blob clients provide comprehensive functionality for working with individual blobs, including upload, download, metadata management, and content manipulation.

3

4

## BlobClient

5

6

The synchronous client for individual blob operations.

7

8

### Creating Blob Clients

9

10

```java

11

import com.azure.storage.blob.BlobClient;

12

import com.azure.storage.blob.BlobClientBuilder;

13

import com.azure.storage.blob.BlobContainerClient;

14

15

// From container client (recommended)

16

BlobContainerClient containerClient = serviceClient.getBlobContainerClient("mycontainer");

17

BlobClient blobClient = containerClient.getBlobClient("myblob.txt");

18

19

// From service client

20

BlobClient blobClient = serviceClient.getBlobContainerClient("mycontainer")

21

.getBlobClient("myblob.txt");

22

23

// Direct creation using builder

24

BlobClient blobClient = new BlobClientBuilder()

25

.connectionString("DefaultEndpointsProtocol=https;AccountName=myaccount;...")

26

.containerName("mycontainer")

27

.blobName("myblob.txt")

28

.buildClient();

29

30

// With snapshot or version

31

BlobClient snapshotClient = new BlobClientBuilder()

32

.connectionString("DefaultEndpointsProtocol=https;AccountName=myaccount;...")

33

.containerName("mycontainer")

34

.blobName("myblob.txt")

35

.snapshot("2023-12-01T10:30:00.1234567Z")

36

.buildClient();

37

38

BlobClient versionClient = new BlobClientBuilder()

39

.connectionString("DefaultEndpointsProtocol=https;AccountName=myaccount;...")

40

.containerName("mycontainer")

41

.blobName("myblob.txt")

42

.versionId("01D64EAD4C6B7A00")

43

.buildClient();

44

```

45

46

### Blob Upload Operations

47

48

```java

49

import com.azure.core.util.BinaryData;

50

import com.azure.storage.blob.models.*;

51

import com.azure.storage.blob.options.*;

52

53

// Simple upload from string

54

String content = "Hello, Azure Blob Storage!";

55

blobClient.upload(BinaryData.fromString(content), true); // overwrite if exists

56

57

// Upload from byte array

58

byte[] data = "Binary content".getBytes(StandardCharsets.UTF_8);

59

blobClient.upload(BinaryData.fromBytes(data), false); // don't overwrite

60

61

// Upload from InputStream

62

try (FileInputStream fileStream = new FileInputStream("localfile.txt")) {

63

long fileSize = Files.size(Paths.get("localfile.txt"));

64

BlockBlobItem uploadResult = blobClient.upload(fileStream, fileSize, true);

65

System.out.println("Upload completed. ETag: " + uploadResult.getETag());

66

}

67

68

// Upload from file

69

blobClient.uploadFromFile("localfile.txt");

70

71

// Upload with overwrite protection

72

try {

73

blobClient.uploadFromFile("localfile.txt", false); // don't overwrite

74

} catch (BlobStorageException ex) {

75

if (ex.getErrorCode() == BlobErrorCode.BLOB_ALREADY_EXISTS) {

76

System.out.println("Blob already exists, skipping upload");

77

} else {

78

throw ex;

79

}

80

}

81

```

82

83

### Advanced Upload with Options

84

85

```java

86

// Upload with comprehensive options

87

BlobHttpHeaders headers = new BlobHttpHeaders()

88

.setContentType("text/plain")

89

.setContentLanguage("en-US")

90

.setContentEncoding("utf-8")

91

.setCacheControl("no-cache, max-age=0")

92

.setContentDisposition("attachment; filename=data.txt");

93

94

Map<String, String> metadata = Map.of(

95

"author", "system",

96

"category", "logs",

97

"environment", "production"

98

);

99

100

Map<String, String> tags = Map.of(

101

"department", "engineering",

102

"project", "webapp",

103

"cost-center", "12345"

104

);

105

106

ParallelTransferOptions transferOptions = new ParallelTransferOptions()

107

.setBlockSizeLong(4 * 1024 * 1024L) // 4MB blocks

108

.setMaxConcurrency(8)

109

.setProgressListener(bytesTransferred ->

110

System.out.println("Uploaded: " + bytesTransferred + " bytes"));

111

112

BlobRequestConditions conditions = new BlobRequestConditions()

113

.setIfNoneMatch("*"); // Only upload if blob doesn't exist

114

115

// Upload with all options

116

BlobParallelUploadOptions uploadOptions = new BlobParallelUploadOptions(

117

BinaryData.fromString("Content with all options"))

118

.setHeaders(headers)

119

.setMetadata(metadata)

120

.setTags(tags)

121

.setTier(AccessTier.HOT)

122

.setParallelTransferOptions(transferOptions)

123

.setRequestConditions(conditions);

124

125

Response<BlockBlobItem> uploadResponse = blobClient.uploadWithResponse(

126

uploadOptions,

127

Duration.ofMinutes(10),

128

Context.NONE

129

);

130

131

System.out.println("Upload status: " + uploadResponse.getStatusCode());

132

System.out.println("ETag: " + uploadResponse.getValue().getETag());

133

System.out.println("Version ID: " + uploadResponse.getValue().getVersionId());

134

```

135

136

### File Upload with Options

137

138

```java

139

// Upload large file with optimized settings

140

BlobUploadFromFileOptions fileUploadOptions = new BlobUploadFromFileOptions("largefile.dat")

141

.setParallelTransferOptions(new ParallelTransferOptions()

142

.setBlockSizeLong(8 * 1024 * 1024L) // 8MB blocks for large files

143

.setMaxConcurrency(6)

144

.setMaxSingleUploadSizeLong(256 * 1024 * 1024L)) // 256MB single upload threshold

145

.setHeaders(new BlobHttpHeaders()

146

.setContentType("application/octet-stream"))

147

.setMetadata(Map.of(

148

"upload-date", OffsetDateTime.now().toString(),

149

"file-size", String.valueOf(Files.size(Paths.get("largefile.dat")))))

150

.setTier(AccessTier.HOT)

151

.setRequestConditions(new BlobRequestConditions()

152

.setIfNoneMatch("*"));

153

154

Response<BlockBlobItem> fileUploadResponse = blobClient.uploadFromFileWithResponse(

155

fileUploadOptions,

156

Duration.ofMinutes(30),

157

Context.NONE

158

);

159

```

160

161

### Blob Download Operations

162

163

```java

164

// Download to BinaryData

165

BinaryData downloadedData = blobClient.downloadContent();

166

String content = downloadedData.toString();

167

byte[] bytes = downloadedData.toBytes();

168

169

// Download to OutputStream

170

try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

171

BlobProperties properties = blobClient.download(outputStream);

172

byte[] downloadedBytes = outputStream.toByteArray();

173

System.out.println("Downloaded " + downloadedBytes.length + " bytes");

174

System.out.println("Content type: " + properties.getContentType());

175

}

176

177

// Download to file

178

BlobProperties downloadProperties = blobClient.downloadToFile("downloaded-file.txt");

179

System.out.println("File downloaded, size: " + downloadProperties.getBlobSize());

180

181

// Download with overwrite protection

182

try {

183

blobClient.downloadToFile("downloaded-file.txt", false); // don't overwrite

184

} catch (UncheckedIOException ex) {

185

System.err.println("File already exists: " + ex.getMessage());

186

}

187

188

// Streaming download

189

try (InputStream inputStream = blobClient.openInputStream()) {

190

// Process stream incrementally

191

byte[] buffer = new byte[8192];

192

int bytesRead;

193

while ((bytesRead = inputStream.read(buffer)) != -1) {

194

// Process buffer content

195

System.out.println("Read " + bytesRead + " bytes");

196

}

197

}

198

```

199

200

### Advanced Download with Options

201

202

```java

203

// Download specific range

204

BlobRange range = new BlobRange(1024, 4096L); // Download bytes 1024-5120

205

BlobDownloadContentResponse rangeResponse = blobClient.downloadContentWithResponse(

206

new BlobDownloadOptions()

207

.setRange(range),

208

Duration.ofMinutes(5),

209

Context.NONE

210

);

211

212

BinaryData rangeData = rangeResponse.getValue();

213

System.out.println("Downloaded range: " + rangeData.getLength() + " bytes");

214

215

// Download to file with advanced options

216

DownloadRetryOptions retryOptions = new DownloadRetryOptions()

217

.setMaxRetryRequests(5);

218

219

BlobDownloadToFileOptions downloadOptions = new BlobDownloadToFileOptions("advanced-download.dat")

220

.setRange(new BlobRange(0)) // Download from start

221

.setParallelTransferOptions(new ParallelTransferOptions()

222

.setBlockSizeLong(4 * 1024 * 1024L)

223

.setMaxConcurrency(4))

224

.setDownloadRetryOptions(retryOptions)

225

.setRequestConditions(new BlobRequestConditions()

226

.setIfMatch(blobClient.getProperties().getETag())) // Download only if not modified

227

.setRetrieveContentMd5(true)

228

.setOpenOptions(Set.of(

229

StandardOpenOption.CREATE,

230

StandardOpenOption.WRITE,

231

StandardOpenOption.TRUNCATE_EXISTING));

232

233

Response<BlobProperties> advancedDownloadResponse = blobClient.downloadToFileWithResponse(

234

downloadOptions,

235

Duration.ofMinutes(15),

236

Context.NONE

237

);

238

239

System.out.println("Advanced download completed");

240

System.out.println("Content MD5: " + Arrays.toString(

241

advancedDownloadResponse.getValue().getContentMd5()));

242

```

243

244

### Blob Properties and Metadata

245

246

```java

247

// Get blob properties

248

BlobProperties properties = blobClient.getProperties();

249

System.out.println("Blob size: " + properties.getBlobSize() + " bytes");

250

System.out.println("Content type: " + properties.getContentType());

251

System.out.println("Last modified: " + properties.getLastModified());

252

System.out.println("ETag: " + properties.getETag());

253

System.out.println("Blob type: " + properties.getBlobType());

254

System.out.println("Access tier: " + properties.getAccessTier());

255

System.out.println("Creation time: " + properties.getCreationTime());

256

System.out.println("Is encrypted: " + properties.isServerEncrypted());

257

System.out.println("Metadata: " + properties.getMetadata());

258

259

// Check if blob exists

260

Boolean exists = blobClient.exists();

261

if (!exists) {

262

System.out.println("Blob does not exist");

263

return;

264

}

265

266

// Get properties with conditions

267

BlobRequestConditions conditions = new BlobRequestConditions()

268

.setIfModifiedSince(OffsetDateTime.now().minusDays(1));

269

270

Response<BlobProperties> propertiesResponse = blobClient.getPropertiesWithResponse(

271

conditions,

272

Duration.ofSeconds(30),

273

Context.NONE

274

);

275

```

276

277

### Setting Blob Properties

278

279

```java

280

// Set HTTP headers

281

BlobHttpHeaders newHeaders = new BlobHttpHeaders()

282

.setContentType("application/json")

283

.setContentLanguage("en-US")

284

.setContentEncoding("gzip")

285

.setCacheControl("public, max-age=3600")

286

.setContentDisposition("inline; filename=data.json");

287

288

blobClient.setHttpHeaders(newHeaders);

289

290

// Set HTTP headers with conditions

291

BlobRequestConditions headerConditions = new BlobRequestConditions()

292

.setIfMatch(properties.getETag());

293

294

Response<Void> headerResponse = blobClient.setHttpHeadersWithResponse(

295

newHeaders,

296

headerConditions,

297

Duration.ofSeconds(30),

298

Context.NONE

299

);

300

301

// Set metadata

302

Map<String, String> newMetadata = Map.of(

303

"processed", "true",

304

"processor", "batch-job-v2",

305

"processed-time", OffsetDateTime.now().toString(),

306

"checksum", "abc123def456"

307

);

308

309

blobClient.setMetadata(newMetadata);

310

311

// Set metadata with conditions

312

Response<Void> metadataResponse = blobClient.setMetadataWithResponse(

313

newMetadata,

314

new BlobRequestConditions().setIfUnmodifiedSince(OffsetDateTime.now()),

315

Duration.ofSeconds(30),

316

Context.NONE

317

);

318

```

319

320

### Blob Tags

321

322

```java

323

// Set tags

324

Map<String, String> tags = Map.of(

325

"environment", "production",

326

"team", "backend",

327

"cost-center", "12345",

328

"project", "webapp",

329

"classification", "internal"

330

);

331

332

blobClient.setTags(tags);

333

334

// Get current tags

335

Map<String, String> currentTags = blobClient.getTags();

336

System.out.println("Current tags: " + currentTags);

337

338

// Set tags with options

339

BlobSetTagsOptions setTagsOptions = new BlobSetTagsOptions(tags)

340

.setRequestConditions(new BlobRequestConditions()

341

.setTagsConditions("\"environment\" = 'staging'"));

342

343

Response<Void> setTagsResponse = blobClient.setTagsWithResponse(

344

setTagsOptions,

345

Duration.ofSeconds(30),

346

Context.NONE

347

);

348

349

// Get tags with options

350

BlobGetTagsOptions getTagsOptions = new BlobGetTagsOptions()

351

.setRequestConditions(new BlobRequestConditions()

352

.setIfMatch(blobClient.getProperties().getETag()));

353

354

Response<Map<String, String>> getTagsResponse = blobClient.getTagsWithResponse(

355

getTagsOptions,

356

Duration.ofSeconds(30),

357

Context.NONE

358

);

359

```

360

361

### Access Tier Management

362

363

```java

364

// Set access tier for cost optimization

365

blobClient.setAccessTier(AccessTier.COOL);

366

367

// Set access tier with options

368

BlobSetAccessTierOptions tierOptions = new BlobSetAccessTierOptions(AccessTier.ARCHIVE)

369

.setPriority(RehydratePriority.STANDARD)

370

.setLeaseId(leaseId)

371

.setTagsConditions("\"environment\" = 'development'");

372

373

Response<Void> tierResponse = blobClient.setAccessTierWithResponse(

374

tierOptions,

375

Duration.ofSeconds(30),

376

Context.NONE

377

);

378

379

// Check current access tier and archive status

380

BlobProperties tierProperties = blobClient.getProperties();

381

System.out.println("Current tier: " + tierProperties.getAccessTier());

382

System.out.println("Archive status: " + tierProperties.getArchiveStatus());

383

System.out.println("Tier inferred: " + tierProperties.getAccessTierInferred());

384

System.out.println("Tier change time: " + tierProperties.getAccessTierChangeTime());

385

```

386

387

### Blob Snapshots

388

389

```java

390

// Create snapshot

391

BlobClient snapshotClient = blobClient.createSnapshot();

392

String snapshotId = snapshotClient.getSnapshotId();

393

System.out.println("Created snapshot: " + snapshotId);

394

395

// Create snapshot with metadata

396

Map<String, String> snapshotMetadata = Map.of(

397

"snapshot-reason", "backup",

398

"created-by", "automated-backup",

399

"retention-days", "30"

400

);

401

402

Response<BlobClient> snapshotResponse = blobClient.createSnapshotWithResponse(

403

snapshotMetadata,

404

new BlobRequestConditions().setIfMatch(blobClient.getProperties().getETag()),

405

Duration.ofSeconds(30),

406

Context.NONE

407

);

408

409

BlobClient snapshotWithMetadata = snapshotResponse.getValue();

410

System.out.println("Snapshot with metadata: " + snapshotWithMetadata.getSnapshotId());

411

412

// Access existing snapshot

413

BlobClient existingSnapshot = containerClient.getBlobClient(blobName, snapshotId);

414

BlobProperties snapshotProps = existingSnapshot.getProperties();

415

System.out.println("Snapshot size: " + snapshotProps.getBlobSize());

416

```

417

418

### Copy Operations

419

420

```java

421

// Simple copy from another blob

422

String sourceUrl = "https://sourceaccount.blob.core.windows.net/sourcecontainer/sourceblob.txt";

423

String copyId = blobClient.copyFromUrl(sourceUrl);

424

System.out.println("Copy operation started: " + copyId);

425

426

// Synchronous copy with timeout

427

try {

428

String syncCopyId = blobClient.copyFromUrl(sourceUrl, Duration.ofMinutes(5));

429

System.out.println("Synchronous copy completed: " + syncCopyId);

430

} catch (Exception ex) {

431

System.err.println("Copy operation failed: " + ex.getMessage());

432

}

433

434

// Asynchronous copy with polling

435

SyncPoller<BlobCopyInfo, Void> copyPoller = blobClient.beginCopy(sourceUrl, Duration.ofMinutes(1));

436

437

// Poll for completion

438

copyPoller.waitForCompletion(Duration.ofMinutes(30));

439

BlobCopyInfo finalCopyInfo = copyPoller.getFinalResult();

440

441

System.out.println("Copy status: " + finalCopyInfo.getCopyStatus());

442

System.out.println("Copy progress: " + finalCopyInfo.getBytesTransferred() +

443

"/" + finalCopyInfo.getTotalBytes());

444

445

// Copy with options

446

Map<String, String> copyMetadata = Map.of(

447

"copy-source", sourceUrl,

448

"copy-time", OffsetDateTime.now().toString()

449

);

450

451

BlobBeginCopyOptions copyOptions = new BlobBeginCopyOptions(sourceUrl)

452

.setMetadata(copyMetadata)

453

.setTier(AccessTier.HOT)

454

.setRequestConditions(new BlobRequestConditions()

455

.setIfNoneMatch("*"))

456

.setSourceRequestConditions(new BlobRequestConditions()

457

.setIfModifiedSince(OffsetDateTime.now().minusDays(1)));

458

459

SyncPoller<BlobCopyInfo, Void> advancedCopyPoller = blobClient.beginCopy(copyOptions, Duration.ofSeconds(30));

460

```

461

462

### Blob Deletion

463

464

```java

465

// Simple delete

466

blobClient.delete();

467

468

// Delete if exists

469

boolean deleted = blobClient.deleteIfExists();

470

if (deleted) {

471

System.out.println("Blob was deleted");

472

} else {

473

System.out.println("Blob did not exist");

474

}

475

476

// Delete with options

477

DeleteSnapshotsOptionType snapshotOption = DeleteSnapshotsOptionType.INCLUDE;

478

BlobRequestConditions deleteConditions = new BlobRequestConditions()

479

.setIfUnmodifiedSince(OffsetDateTime.now().plusMinutes(1));

480

481

Response<Void> deleteResponse = blobClient.deleteWithResponse(

482

snapshotOption,

483

deleteConditions,

484

Duration.ofSeconds(30),

485

Context.NONE

486

);

487

488

System.out.println("Delete status: " + deleteResponse.getStatusCode());

489

490

// Delete if exists with options

491

BlobDeleteOptions deleteOptions = new BlobDeleteOptions()

492

.setDeleteSnapshotsOptions(DeleteSnapshotsOptionType.ONLY)

493

.setRequestConditions(new BlobRequestConditions()

494

.setLeaseId(leaseId));

495

496

Response<Boolean> deleteIfExistsResponse = blobClient.deleteIfExistsWithResponse(

497

deleteOptions,

498

Duration.ofSeconds(30),

499

Context.NONE

500

);

501

```

502

503

### Undelete Operations

504

505

```java

506

// Undelete soft-deleted blob (if soft delete is enabled)

507

try {

508

blobClient.undelete();

509

System.out.println("Blob restored from soft delete");

510

} catch (BlobStorageException ex) {

511

if (ex.getErrorCode() == BlobErrorCode.BLOB_NOT_FOUND) {

512

System.out.println("Blob was not found or not soft-deleted");

513

} else {

514

throw ex;

515

}

516

}

517

518

// Undelete with response

519

Response<Void> undeleteResponse = blobClient.undeleteWithResponse(

520

Duration.ofSeconds(30),

521

Context.NONE

522

);

523

524

System.out.println("Undelete status: " + undeleteResponse.getStatusCode());

525

```

526

527

## BlobAsyncClient

528

529

The asynchronous client for blob operations using reactive programming.

530

531

### Creating Async Blob Clients

532

533

```java

534

import com.azure.storage.blob.BlobAsyncClient;

535

import reactor.core.publisher.Mono;

536

import reactor.core.publisher.Flux;

537

538

// From container async client

539

BlobContainerAsyncClient asyncContainerClient = serviceAsyncClient.getBlobContainerAsyncClient("mycontainer");

540

BlobAsyncClient asyncBlobClient = asyncContainerClient.getBlobAsyncClient("myblob.txt");

541

542

// From sync client

543

BlobAsyncClient asyncBlobClient = blobClient.getAsyncClient();

544

545

// Direct creation

546

BlobAsyncClient asyncBlobClient = new BlobClientBuilder()

547

.connectionString("DefaultEndpointsProtocol=https;AccountName=myaccount;...")

548

.containerName("mycontainer")

549

.blobName("myblob.txt")

550

.buildAsyncClient();

551

```

552

553

### Async Upload Operations

554

555

```java

556

// Simple async upload

557

Mono<BlockBlobItem> uploadMono = asyncBlobClient.upload(

558

BinaryData.fromString("Async upload content"),

559

true

560

);

561

562

uploadMono

563

.doOnSuccess(result -> System.out.println("Upload completed: " + result.getETag()))

564

.doOnError(ex -> System.err.println("Upload failed: " + ex.getMessage()))

565

.subscribe();

566

567

// Upload with progress tracking

568

ParallelTransferOptions asyncTransferOptions = new ParallelTransferOptions()

569

.setBlockSizeLong(1024 * 1024L)

570

.setMaxConcurrency(4)

571

.setProgressListener(bytesTransferred ->

572

System.out.println("Async progress: " + bytesTransferred + " bytes"));

573

574

BlobParallelUploadOptions asyncUploadOptions = new BlobParallelUploadOptions(

575

BinaryData.fromString("Large content for async upload"))

576

.setParallelTransferOptions(asyncTransferOptions)

577

.setHeaders(new BlobHttpHeaders().setContentType("text/plain"))

578

.setMetadata(Map.of("async", "true"));

579

580

Mono<Response<BlockBlobItem>> asyncUploadResponse = asyncBlobClient.uploadWithResponse(

581

asyncUploadOptions

582

);

583

584

asyncUploadResponse

585

.doOnNext(response -> {

586

System.out.println("Async upload status: " + response.getStatusCode());

587

System.out.println("ETag: " + response.getValue().getETag());

588

})

589

.subscribe();

590

```

591

592

### Async Download Operations

593

594

```java

595

// Download content asynchronously

596

Mono<BinaryData> downloadMono = asyncBlobClient.downloadContent();

597

598

downloadMono

599

.doOnNext(data -> System.out.println("Downloaded " + data.getLength() + " bytes"))

600

.doOnError(ex -> System.err.println("Download failed: " + ex.getMessage()))

601

.subscribe();

602

603

// Streaming download

604

Flux<ByteBuffer> downloadFlux = asyncBlobClient.downloadStream();

605

606

downloadFlux

607

.doOnNext(buffer -> {

608

System.out.println("Received buffer: " + buffer.remaining() + " bytes");

609

// Process buffer

610

})

611

.doOnComplete(() -> System.out.println("Streaming download complete"))

612

.doOnError(ex -> System.err.println("Stream error: " + ex.getMessage()))

613

.subscribe();

614

615

// Download with reactive chains

616

asyncBlobClient.downloadContent()

617

.map(BinaryData::toString)

618

.filter(content -> content.contains("important"))

619

.doOnNext(content -> System.out.println("Processing important content"))

620

.flatMap(content -> {

621

// Chain with another async operation

622

return asyncBlobClient.setMetadata(Map.of("processed", "true"));

623

})

624

.subscribe();

625

```

626

627

### Async Properties and Operations

628

629

```java

630

// Get properties asynchronously

631

Mono<BlobProperties> propertiesMono = asyncBlobClient.getProperties();

632

633

propertiesMono

634

.doOnNext(props -> {

635

System.out.println("Async - Blob size: " + props.getBlobSize());

636

System.out.println("Async - Content type: " + props.getContentType());

637

System.out.println("Async - Last modified: " + props.getLastModified());

638

})

639

.subscribe();

640

641

// Chain multiple operations

642

asyncBlobClient.exists()

643

.filter(exists -> exists)

644

.flatMap(exists -> asyncBlobClient.getProperties())

645

.flatMap(props -> {

646

if (props.getBlobSize() > 1024 * 1024) { // > 1MB

647

return asyncBlobClient.setAccessTier(AccessTier.COOL);

648

} else {

649

return Mono.empty();

650

}

651

})

652

.doOnSuccess(v -> System.out.println("Large blob moved to cool tier"))

653

.subscribe();

654

655

// Parallel operations

656

Mono<BlobProperties> properties = asyncBlobClient.getProperties();

657

Mono<Map<String, String>> tags = asyncBlobClient.getTags();

658

659

Mono.zip(properties, tags)

660

.doOnNext(tuple -> {

661

BlobProperties props = tuple.getT1();

662

Map<String, String> blobTags = tuple.getT2();

663

System.out.println("Blob: " + props.getBlobSize() + " bytes, " +

664

blobTags.size() + " tags");

665

})

666

.subscribe();

667

```

668

669

### Error Handling with Async Client

670

671

```java

672

// Comprehensive error handling

673

asyncBlobClient.upload(BinaryData.fromString("content"), true)

674

.doOnSuccess(result -> System.out.println("Upload successful"))

675

.onErrorResume(BlobStorageException.class, ex -> {

676

System.err.println("Storage error: " + ex.getErrorCode());

677

if (ex.getStatusCode() == 409) {

678

System.out.println("Blob already exists, trying to update metadata instead");

679

return asyncBlobClient.setMetadata(Map.of("updated", "true"))

680

.then(Mono.empty()); // Convert to empty result

681

}

682

return Mono.error(ex);

683

})

684

.onErrorResume(Exception.class, ex -> {

685

System.err.println("Unexpected error: " + ex.getMessage());

686

return Mono.error(new RuntimeException("Upload operation failed", ex));

687

})

688

.subscribe();

689

690

// Retry with backoff

691

asyncBlobClient.getProperties()

692

.retryWhen(Retry.backoff(3, Duration.ofSeconds(1))) // Retry up to 3 times with exponential backoff

693

.doOnNext(props -> System.out.println("Properties retrieved after potential retries"))

694

.subscribe();

695

```

696

697

## Specialized Client Access

698

699

### Getting Specialized Clients

700

701

```java

702

// Get specialized clients from base blob client

703

BlockBlobClient blockBlobClient = blobClient.getBlockBlobClient();

704

AppendBlobClient appendBlobClient = blobClient.getAppendBlobClient();

705

PageBlobClient pageBlobClient = blobClient.getPageBlobClient();

706

707

// Async versions

708

BlockBlobAsyncClient asyncBlockBlobClient = asyncBlobClient.getBlockBlobAsyncClient();

709

AppendBlobAsyncClient asyncAppendBlobClient = asyncBlobClient.getAppendBlobAsyncClient();

710

PageBlobAsyncClient asyncPageBlobClient = asyncBlobClient.getPageBlobAsyncClient();

711

712

// Use specialized operations

713

blockBlobClient.upload(BinaryData.fromString("Block blob content"), true);

714

appendBlobClient.create();

715

appendBlobClient.appendBlock(BinaryData.fromString("Append content"));

716

pageBlobClient.create(512 * 1024); // 512KB page blob

717

```

718

719

## Blob URLs and SAS

720

721

### URL Management

722

723

```java

724

// Get blob URL

725

String blobUrl = blobClient.getBlobUrl();

726

System.out.println("Blob URL: " + blobUrl);

727

728

// Parse blob URL

729

BlobUrlParts urlParts = BlobUrlParts.parse(blobUrl);

730

System.out.println("Account name: " + urlParts.getAccountName());

731

System.out.println("Container: " + urlParts.getBlobContainerName());

732

System.out.println("Blob name: " + urlParts.getBlobName());

733

734

// Generate SAS token

735

OffsetDateTime expiryTime = OffsetDateTime.now().plusHours(1);

736

BlobSasPermission permission = new BlobSasPermission()

737

.setReadPermission(true)

738

.setWritePermission(true);

739

740

BlobServiceSasSignatureValues sasValues = new BlobServiceSasSignatureValues(expiryTime, permission)

741

.setStartTime(OffsetDateTime.now())

742

.setProtocol(SasProtocol.HTTPS_ONLY);

743

744

String sasToken = blobClient.generateSas(sasValues);

745

String sasUrl = blobUrl + "?" + sasToken;

746

System.out.println("SAS URL: " + sasUrl);

747

```

748

749

## Constants and Limits

750

751

```java

752

// Important blob constants

753

public static final int BLOB_DEFAULT_UPLOAD_BLOCK_SIZE = 4 * 1024 * 1024; // 4MB

754

public static final int BLOB_DEFAULT_NUMBER_OF_BUFFERS = 8;

755

public static final int BLOB_DEFAULT_HTBB_UPLOAD_BLOCK_SIZE = 100 * 1024 * 1024; // 100MB

756

757

// Use constants for configuration

758

ParallelTransferOptions transferOptions = new ParallelTransferOptions()

759

.setBlockSizeLong(BlobClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE)

760

.setMaxConcurrency(BlobClient.BLOB_DEFAULT_NUMBER_OF_BUFFERS);

761

```

762

763

## Account Information

764

765

```java

766

// Get storage account information through blob client

767

StorageAccountInfo accountInfo = blobClient.getAccountInfo();

768

System.out.println("Account kind: " + accountInfo.getAccountKind());

769

System.out.println("SKU name: " + accountInfo.getSkuName());

770

System.out.println("Hierarchical namespace: " + accountInfo.isHierarchicalNamespaceEnabled());

771

772

// Get account info with response details

773

Response<StorageAccountInfo> accountInfoResponse = blobClient.getAccountInfoWithResponse(

774

Duration.ofSeconds(30),

775

Context.NONE

776

);

777

778

System.out.println("Response status: " + accountInfoResponse.getStatusCode());

779

System.out.println("Request ID: " + accountInfoResponse.getHeaders().getValue("x-ms-request-id"));

780

```

781

782

## Related Documentation

783

784

- [← Back to Overview](index.md)

785

- [← Container Management](container-client.md)

786

- [Specialized Blob Types →](specialized-clients.md)

787

- [Security & Authentication →](security.md)

788

- [Streaming & Advanced I/O →](streaming.md)