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)