0
# Specialized Blob Clients
1
2
Azure Blob Storage supports three specialized blob types, each optimized for different use cases. This documentation covers BlockBlobClient, AppendBlobClient, and PageBlobClient for both synchronous and asynchronous operations.
3
4
## Block Blobs - BlockBlobClient
5
6
Block blobs are optimized for uploading large amounts of data efficiently and are ideal for streaming scenarios.
7
8
### Creating Block Blob Clients
9
10
```java
11
import com.azure.storage.blob.specialized.BlockBlobClient;
12
import com.azure.storage.blob.specialized.BlockBlobAsyncClient;
13
import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder;
14
15
// From base blob client (recommended)
16
BlobClient blobClient = containerClient.getBlobClient("document.pdf");
17
BlockBlobClient blockBlobClient = blobClient.getBlockBlobClient();
18
19
// Using specialized builder
20
BlockBlobClient blockBlobClient = new SpecializedBlobClientBuilder()
21
.blobClient(blobClient)
22
.buildBlockBlobClient();
23
24
// Async version
25
BlockBlobAsyncClient asyncBlockBlobClient = new SpecializedBlobClientBuilder()
26
.blobAsyncClient(blobAsyncClient)
27
.buildBlockBlobAsyncClient();
28
```
29
30
### Block Blob Upload Operations
31
32
```java
33
import com.azure.storage.blob.models.*;
34
import com.azure.core.util.BinaryData;
35
36
// Simple upload (entire blob in one operation)
37
String content = "Complete document content for block blob";
38
BlockBlobItem uploadResult = blockBlobClient.upload(
39
BinaryData.fromString(content),
40
true // overwrite if exists
41
);
42
43
System.out.println("Block blob uploaded: " + uploadResult.getETag());
44
System.out.println("Content MD5: " + Arrays.toString(uploadResult.getContentMd5()));
45
System.out.println("Version ID: " + uploadResult.getVersionId());
46
47
// Upload with comprehensive options
48
BlobHttpHeaders headers = new BlobHttpHeaders()
49
.setContentType("application/pdf")
50
.setContentDisposition("attachment; filename=document.pdf")
51
.setCacheControl("public, max-age=31536000");
52
53
Map<String, String> metadata = Map.of(
54
"document-type", "invoice",
55
"department", "accounting",
56
"year", "2023"
57
);
58
59
BlobRequestConditions conditions = new BlobRequestConditions()
60
.setIfNoneMatch("*"); // Only upload if blob doesn't exist
61
62
Response<BlockBlobItem> uploadResponse = blockBlobClient.uploadWithResponse(
63
BinaryData.fromString(content),
64
content.length(),
65
headers,
66
metadata,
67
AccessTier.HOT,
68
null, // contentMd5
69
conditions,
70
Duration.ofMinutes(10),
71
Context.NONE
72
);
73
74
System.out.println("Upload status: " + uploadResponse.getStatusCode());
75
```
76
77
### Upload from URL
78
79
```java
80
// Upload from another URL (server-side copy)
81
String sourceUrl = "https://example.com/source-file.pdf";
82
83
BlockBlobItem urlUploadResult = blockBlobClient.uploadFromUrl(sourceUrl);
84
System.out.println("Upload from URL completed: " + urlUploadResult.getETag());
85
86
// Upload from URL with options
87
BlobUploadFromUrlOptions urlOptions = new BlobUploadFromUrlOptions(sourceUrl)
88
.setHeaders(new BlobHttpHeaders().setContentType("application/pdf"))
89
.setMetadata(Map.of("source", "external"))
90
.setTags(Map.of("imported", "true"))
91
.setTier(AccessTier.HOT)
92
.setRequestConditions(new BlobRequestConditions().setIfNoneMatch("*"))
93
.setSourceRequestConditions(new BlobRequestConditions()
94
.setIfModifiedSince(OffsetDateTime.now().minusDays(1)));
95
96
Response<BlockBlobItem> urlUploadResponse = blockBlobClient.uploadFromUrlWithResponse(
97
urlOptions,
98
Duration.ofMinutes(5),
99
Context.NONE
100
);
101
```
102
103
### Block-Level Operations
104
105
```java
106
import java.util.Base64;
107
import java.util.List;
108
import java.util.ArrayList;
109
110
// Stage individual blocks (for large file uploads)
111
List<String> blockIds = new ArrayList<>();
112
113
// Block 1
114
String blockId1 = Base64.getEncoder().encodeToString("block-001".getBytes());
115
byte[] blockData1 = "First part of the content".getBytes();
116
blockBlobClient.stageBlock(blockId1, BinaryData.fromBytes(blockData1));
117
blockIds.add(blockId1);
118
119
// Block 2
120
String blockId2 = Base64.getEncoder().encodeToString("block-002".getBytes());
121
byte[] blockData2 = "Second part of the content".getBytes();
122
blockBlobClient.stageBlock(blockId2, BinaryData.fromBytes(blockData2));
123
blockIds.add(blockId2);
124
125
// Stage block with options
126
String blockId3 = Base64.getEncoder().encodeToString("block-003".getBytes());
127
byte[] blockData3 = "Third part with checksum".getBytes();
128
byte[] blockMd5 = MessageDigest.getInstance("MD5").digest(blockData3);
129
130
Response<Void> stageResponse = blockBlobClient.stageBlockWithResponse(
131
blockId3,
132
BinaryData.fromBytes(blockData3),
133
blockMd5,
134
null, // leaseId
135
Duration.ofMinutes(2),
136
Context.NONE
137
);
138
blockIds.add(blockId3);
139
140
// Commit all blocks to create the final blob
141
BlockBlobItem commitResult = blockBlobClient.commitBlockList(blockIds);
142
System.out.println("Blocks committed: " + commitResult.getETag());
143
144
// Commit with additional options
145
Response<BlockBlobItem> commitResponse = blockBlobClient.commitBlockListWithResponse(
146
blockIds,
147
new BlobHttpHeaders().setContentType("text/plain"),
148
Map.of("blocks-count", String.valueOf(blockIds.size())),
149
AccessTier.HOT,
150
new BlobRequestConditions().setIfNoneMatch("*"),
151
Duration.ofMinutes(5),
152
Context.NONE
153
);
154
```
155
156
### Block Management
157
158
```java
159
// List current blocks
160
BlockList blockList = blockBlobClient.listBlocks(BlockListType.ALL);
161
162
System.out.println("Committed blocks:");
163
for (Block block : blockList.getCommittedBlocks()) {
164
System.out.println(" Block ID: " + block.getName());
165
System.out.println(" Size: " + block.getSizeLong() + " bytes");
166
}
167
168
System.out.println("Uncommitted blocks:");
169
for (Block block : blockList.getUncommittedBlocks()) {
170
System.out.println(" Block ID: " + block.getName());
171
System.out.println(" Size: " + block.getSizeLong() + " bytes");
172
}
173
174
// List blocks with lease ID
175
String leaseId = acquiredLeaseId; // From lease operations
176
Response<BlockList> blockListResponse = blockBlobClient.listBlocksWithResponse(
177
BlockListType.COMMITTED,
178
leaseId,
179
Duration.ofSeconds(30),
180
Context.NONE
181
);
182
183
// Stage block from URL
184
String sourceBlockUrl = "https://source.blob.core.windows.net/container/source.txt";
185
BlobRange sourceRange = new BlobRange(0, 1024L); // First 1KB
186
187
blockBlobClient.stageBlockFromUrl(blockId1, sourceBlockUrl, sourceRange);
188
189
// Stage block from URL with options
190
BlockBlobStageBlockFromUrlOptions stageFromUrlOptions = new BlockBlobStageBlockFromUrlOptions(
191
blockId2, sourceBlockUrl)
192
.setSourceRange(new BlobRange(1024, 1024L)) // Next 1KB
193
.setSourceContentMd5(sourceMd5Hash)
194
.setLeaseId(leaseId)
195
.setSourceRequestConditions(new BlobRequestConditions()
196
.setIfMatch(sourceETag));
197
198
Response<Void> stageFromUrlResponse = blockBlobClient.stageBlockFromUrlWithResponse(
199
stageFromUrlOptions,
200
Duration.ofMinutes(2),
201
Context.NONE
202
);
203
```
204
205
### Block Blob Streaming
206
207
```java
208
// Get output stream for writing
209
BlobOutputStream blobOutputStream = blockBlobClient.getBlobOutputStream();
210
211
try (blobOutputStream) {
212
// Write data in chunks
213
blobOutputStream.write("First chunk of data\n".getBytes());
214
blobOutputStream.write("Second chunk of data\n".getBytes());
215
blobOutputStream.write("Final chunk of data\n".getBytes());
216
217
// Stream automatically commits blocks when closed
218
} catch (IOException ex) {
219
System.err.println("Stream write failed: " + ex.getMessage());
220
}
221
222
// Get output stream with options
223
ParallelTransferOptions streamTransferOptions = new ParallelTransferOptions()
224
.setBlockSizeLong(2 * 1024 * 1024L) // 2MB blocks
225
.setMaxConcurrency(4);
226
227
BlobHttpHeaders streamHeaders = new BlobHttpHeaders()
228
.setContentType("text/plain")
229
.setContentEncoding("utf-8");
230
231
Map<String, String> streamMetadata = Map.of(
232
"streaming", "true",
233
"created", OffsetDateTime.now().toString()
234
);
235
236
BlobOutputStream configuredStream = blockBlobClient.getBlobOutputStream(
237
streamTransferOptions,
238
streamHeaders,
239
streamMetadata,
240
AccessTier.HOT,
241
new BlobRequestConditions().setIfNoneMatch("*"),
242
Context.NONE
243
);
244
245
try (configuredStream) {
246
// Write large amounts of data
247
for (int i = 0; i < 1000; i++) {
248
configuredStream.write(("Line " + i + " of streaming data\n").getBytes());
249
}
250
}
251
```
252
253
## Append Blobs - AppendBlobClient
254
255
Append blobs are optimized for append operations and are ideal for logging scenarios.
256
257
### Creating Append Blob Clients
258
259
```java
260
import com.azure.storage.blob.specialized.AppendBlobClient;
261
import com.azure.storage.blob.specialized.AppendBlobAsyncClient;
262
263
// From base blob client
264
AppendBlobClient appendBlobClient = blobClient.getAppendBlobClient();
265
266
// Using specialized builder
267
AppendBlobClient appendBlobClient = new SpecializedBlobClientBuilder()
268
.blobClient(blobClient)
269
.buildAppendBlobClient();
270
271
// Async version
272
AppendBlobAsyncClient asyncAppendBlobClient = new SpecializedBlobClientBuilder()
273
.blobAsyncClient(blobAsyncClient)
274
.buildAppendBlobAsyncClient();
275
```
276
277
### Append Blob Lifecycle
278
279
```java
280
// Create append blob
281
AppendBlobItem createResult = appendBlobClient.create();
282
System.out.println("Append blob created: " + createResult.getETag());
283
284
// Create with options
285
BlobHttpHeaders appendHeaders = new BlobHttpHeaders()
286
.setContentType("text/plain")
287
.setContentEncoding("utf-8");
288
289
Map<String, String> appendMetadata = Map.of(
290
"log-type", "application",
291
"service", "web-api",
292
"environment", "production"
293
);
294
295
Response<AppendBlobItem> createResponse = appendBlobClient.createWithResponse(
296
appendHeaders,
297
appendMetadata,
298
new BlobRequestConditions().setIfNoneMatch("*"),
299
Duration.ofSeconds(30),
300
Context.NONE
301
);
302
303
// Create if not exists
304
AppendBlobItem createIfNotExistsResult = appendBlobClient.createIfNotExists();
305
if (createIfNotExistsResult != null) {
306
System.out.println("New append blob created");
307
} else {
308
System.out.println("Append blob already exists");
309
}
310
311
// Create if not exists with options
312
AppendBlobCreateOptions createOptions = new AppendBlobCreateOptions()
313
.setHeaders(appendHeaders)
314
.setMetadata(appendMetadata);
315
316
Response<AppendBlobItem> createIfNotExistsResponse = appendBlobClient.createIfNotExistsWithResponse(
317
createOptions,
318
Duration.ofSeconds(30),
319
Context.NONE
320
);
321
```
322
323
### Append Operations
324
325
```java
326
// Simple append operation
327
String logEntry = "[" + OffsetDateTime.now() + "] INFO: User logged in\n";
328
AppendBlobItem appendResult = appendBlobClient.appendBlock(BinaryData.fromString(logEntry));
329
330
System.out.println("Append completed: " + appendResult.getBlobAppendOffset());
331
System.out.println("Blob committed block count: " + appendResult.getBlobCommittedBlockCount());
332
333
// Append with conditions
334
AppendBlobRequestConditions appendConditions = new AppendBlobRequestConditions()
335
.setIfMatch(appendResult.getETag())
336
.setAppendPositionEqual(appendResult.getBlobAppendOffset() + logEntry.getBytes().length);
337
338
String nextLogEntry = "[" + OffsetDateTime.now() + "] WARN: High memory usage\n";
339
byte[] logBytes = nextLogEntry.getBytes(StandardCharsets.UTF_8);
340
byte[] logMd5 = MessageDigest.getInstance("MD5").digest(logBytes);
341
342
Response<AppendBlobItem> appendResponse = appendBlobClient.appendBlockWithResponse(
343
BinaryData.fromBytes(logBytes),
344
logMd5,
345
appendConditions,
346
Duration.ofSeconds(30),
347
Context.NONE
348
);
349
350
// Append from URL
351
String sourceLogUrl = "https://source.blob.core.windows.net/logs/app.log";
352
BlobRange sourceRange = new BlobRange(0, 1024L); // First 1KB
353
354
AppendBlobItem urlAppendResult = appendBlobClient.appendBlockFromUrl(sourceLogUrl, sourceRange);
355
356
// Append from URL with options
357
AppendBlobAppendBlockFromUrlOptions urlAppendOptions = new AppendBlobAppendBlockFromUrlOptions(
358
sourceLogUrl, sourceRange)
359
.setSourceContentMd5(sourceMd5)
360
.setDestinationRequestConditions(new AppendBlobRequestConditions()
361
.setMaxSize(100 * 1024 * 1024L)) // Max 100MB
362
.setSourceRequestConditions(new BlobRequestConditions()
363
.setIfUnmodifiedSince(OffsetDateTime.now()));
364
365
Response<AppendBlobItem> urlAppendResponse = appendBlobClient.appendBlockFromUrlWithResponse(
366
urlAppendOptions,
367
Duration.ofMinutes(2),
368
Context.NONE
369
);
370
```
371
372
### Append Blob Sealing
373
374
```java
375
// Seal append blob (make it read-only)
376
appendBlobClient.seal();
377
System.out.println("Append blob sealed - no more appends allowed");
378
379
// Seal with conditions
380
AppendBlobSealOptions sealOptions = new AppendBlobSealOptions()
381
.setRequestConditions(new AppendBlobRequestConditions()
382
.setIfMatch(currentETag)
383
.setLeaseId(leaseId));
384
385
Response<Void> sealResponse = appendBlobClient.sealWithResponse(
386
sealOptions,
387
Duration.ofSeconds(30),
388
Context.NONE
389
);
390
391
System.out.println("Seal operation status: " + sealResponse.getStatusCode());
392
393
// Check if blob is sealed
394
BlobProperties properties = appendBlobClient.getProperties();
395
if (properties.isSealed()) {
396
System.out.println("Blob is sealed");
397
} else {
398
System.out.println("Blob is not sealed");
399
}
400
```
401
402
### Logging Pattern with Append Blobs
403
404
```java
405
// Complete logging example
406
public class BlobLogger {
407
private final AppendBlobClient logBlobClient;
408
private final String logFormat = "[%s] %s: %s%n";
409
410
public BlobLogger(BlobContainerClient containerClient, String logFileName) {
411
this.logBlobClient = containerClient.getBlobClient(logFileName).getAppendBlobClient();
412
413
// Ensure log file exists
414
try {
415
logBlobClient.createIfNotExists();
416
} catch (Exception ex) {
417
throw new RuntimeException("Failed to initialize log file", ex);
418
}
419
}
420
421
public void log(String level, String message) {
422
String logEntry = String.format(logFormat,
423
OffsetDateTime.now(), level, message);
424
425
try {
426
AppendBlobItem result = logBlobClient.appendBlock(BinaryData.fromString(logEntry));
427
System.out.println("Log written at offset: " + result.getBlobAppendOffset());
428
} catch (Exception ex) {
429
System.err.println("Failed to write log: " + ex.getMessage());
430
}
431
}
432
433
public void info(String message) { log("INFO", message); }
434
public void warn(String message) { log("WARN", message); }
435
public void error(String message) { log("ERROR", message); }
436
}
437
438
// Usage
439
BlobLogger logger = new BlobLogger(containerClient, "application.log");
440
logger.info("Application started");
441
logger.warn("High memory usage detected");
442
logger.error("Database connection failed");
443
```
444
445
## Page Blobs - PageBlobClient
446
447
Page blobs provide random read/write access and are ideal for VHD files and database scenarios.
448
449
### Creating Page Blob Clients
450
451
```java
452
import com.azure.storage.blob.specialized.PageBlobClient;
453
import com.azure.storage.blob.specialized.PageBlobAsyncClient;
454
455
// From base blob client
456
PageBlobClient pageBlobClient = blobClient.getPageBlobClient();
457
458
// Using specialized builder
459
PageBlobClient pageBlobClient = new SpecializedBlobClientBuilder()
460
.blobClient(blobClient)
461
.buildPageBlobClient();
462
463
// Async version
464
PageBlobAsyncClient asyncPageBlobClient = new SpecializedBlobClientBuilder()
465
.blobAsyncClient(blobAsyncClient)
466
.buildPageBlobAsyncClient();
467
```
468
469
### Page Blob Creation and Sizing
470
471
```java
472
// Create page blob with specific size (must be multiple of 512 bytes)
473
long pageBlobSize = 1024 * 1024 * 512L; // 512MB
474
PageBlobItem createResult = pageBlobClient.create(pageBlobSize);
475
476
System.out.println("Page blob created: " + createResult.getETag());
477
System.out.println("Sequence number: " + createResult.getBlobSequenceNumber());
478
479
// Create with options
480
BlobHttpHeaders pageHeaders = new BlobHttpHeaders()
481
.setContentType("application/octet-stream");
482
483
Map<String, String> pageMetadata = Map.of(
484
"type", "vhd",
485
"vm-name", "web-server-01",
486
"size-mb", String.valueOf(pageBlobSize / (1024 * 1024))
487
);
488
489
Long sequenceNumber = 0L;
490
491
Response<PageBlobItem> createResponse = pageBlobClient.createWithResponse(
492
pageBlobSize,
493
sequenceNumber,
494
pageHeaders,
495
pageMetadata,
496
AccessTier.PREMIUM,
497
new BlobRequestConditions().setIfNoneMatch("*"),
498
Duration.ofMinutes(2),
499
Context.NONE
500
);
501
502
// Create if not exists
503
PageBlobItem createIfNotExistsResult = pageBlobClient.createIfNotExists(pageBlobSize);
504
if (createIfNotExistsResult != null) {
505
System.out.println("New page blob created");
506
} else {
507
System.out.println("Page blob already exists");
508
}
509
510
// Create if not exists with options
511
PageBlobCreateOptions createOptions = new PageBlobCreateOptions(pageBlobSize)
512
.setSequenceNumber(0L)
513
.setHeaders(pageHeaders)
514
.setMetadata(pageMetadata)
515
.setTier(AccessTier.PREMIUM);
516
517
Response<PageBlobItem> createIfNotExistsResponse = pageBlobClient.createIfNotExistsWithResponse(
518
createOptions,
519
Duration.ofMinutes(2),
520
Context.NONE
521
);
522
```
523
524
### Page Operations
525
526
```java
527
import com.azure.storage.blob.models.PageRange;
528
529
// Upload pages (must be 512-byte aligned)
530
PageRange pageRange1 = new PageRange().setStart(0).setEnd(511); // First page (512 bytes)
531
byte[] pageData1 = new byte[512];
532
Arrays.fill(pageData1, (byte) 0xAA); // Fill with pattern
533
534
PageBlobItem uploadResult = pageBlobClient.uploadPages(pageRange1, BinaryData.fromBytes(pageData1));
535
System.out.println("Page uploaded: " + uploadResult.getETag());
536
537
// Upload multiple pages
538
PageRange pageRange2 = new PageRange().setStart(512).setEnd(1023); // Second page
539
byte[] pageData2 = new byte[512];
540
Arrays.fill(pageData2, (byte) 0xBB);
541
542
byte[] pageMd5 = MessageDigest.getInstance("MD5").digest(pageData2);
543
PageBlobRequestConditions pageConditions = new PageBlobRequestConditions()
544
.setIfSequenceNumberEqual(uploadResult.getBlobSequenceNumber());
545
546
Response<PageBlobItem> uploadResponse = pageBlobClient.uploadPagesWithResponse(
547
pageRange2,
548
BinaryData.fromBytes(pageData2),
549
pageMd5,
550
pageConditions,
551
Duration.ofMinutes(2),
552
Context.NONE
553
);
554
555
// Upload pages from URL
556
String sourcePageUrl = "https://source.blob.core.windows.net/vhds/template.vhd";
557
Long sourceOffset = 0L;
558
559
PageBlobItem urlUploadResult = pageBlobClient.uploadPagesFromUrl(
560
pageRange1,
561
sourcePageUrl,
562
sourceOffset
563
);
564
565
// Upload pages from URL with options
566
PageBlobUploadPagesFromUrlOptions urlUploadOptions = new PageBlobUploadPagesFromUrlOptions(
567
pageRange2, sourcePageUrl, sourceOffset + 512L)
568
.setSourceContentMd5(sourceMd5)
569
.setDestinationRequestConditions(new PageBlobRequestConditions()
570
.setIfMatch(uploadResult.getETag()))
571
.setSourceRequestConditions(new BlobRequestConditions()
572
.setIfUnmodifiedSince(OffsetDateTime.now()));
573
574
Response<PageBlobItem> urlUploadResponse = pageBlobClient.uploadPagesFromUrlWithResponse(
575
urlUploadOptions,
576
Duration.ofMinutes(5),
577
Context.NONE
578
);
579
```
580
581
### Page Management
582
583
```java
584
// Get page ranges (find which pages contain data)
585
PageList pageList = pageBlobClient.getPageRanges(new BlobRange(0, 2048L));
586
587
System.out.println("Page ranges with data:");
588
for (PageRange range : pageList.getPageRanges()) {
589
System.out.println(" Pages " + range.getStart() + " to " + range.getEnd());
590
}
591
592
System.out.println("Clear page ranges:");
593
for (PageRange range : pageList.getClearRanges()) {
594
System.out.println(" Clear pages " + range.getStart() + " to " + range.getEnd());
595
}
596
597
// Get page ranges with conditions
598
Response<PageList> pageListResponse = pageBlobClient.getPageRangesWithResponse(
599
new BlobRange(0),
600
new BlobRequestConditions().setIfMatch(currentETag),
601
Duration.ofSeconds(30),
602
Context.NONE
603
);
604
605
// Clear pages (deallocate storage)
606
PageRange clearRange = new PageRange().setStart(1024).setEnd(1535); // Third page
607
PageBlobItem clearResult = pageBlobClient.clearPages(clearRange);
608
System.out.println("Pages cleared: " + clearResult.getETag());
609
610
// Clear pages with conditions
611
Response<PageBlobItem> clearResponse = pageBlobClient.clearPagesWithResponse(
612
clearRange,
613
new PageBlobRequestConditions().setIfSequenceNumberLessThan(100L),
614
Duration.ofSeconds(30),
615
Context.NONE
616
);
617
618
// Get page ranges diff (compare with snapshot)
619
String previousSnapshot = "2023-12-01T10:30:00.0000000Z";
620
PageList pageRangesDiff = pageBlobClient.getPageRangesDiff(
621
new BlobRange(0),
622
previousSnapshot
623
);
624
625
System.out.println("Pages modified since snapshot:");
626
for (PageRange modifiedRange : pageRangesDiff.getPageRanges()) {
627
System.out.println(" Modified: " + modifiedRange.getStart() + " to " + modifiedRange.getEnd());
628
}
629
```
630
631
### Page Blob Resizing
632
633
```java
634
// Resize page blob
635
long newSize = 2 * 1024 * 1024 * 512L; // 1GB
636
PageBlobItem resizeResult = pageBlobClient.resize(newSize);
637
System.out.println("Blob resized: " + resizeResult.getETag());
638
639
// Resize with conditions
640
Response<PageBlobItem> resizeResponse = pageBlobClient.resizeWithResponse(
641
newSize,
642
new BlobRequestConditions().setIfUnmodifiedSince(OffsetDateTime.now()),
643
Duration.ofMinutes(2),
644
Context.NONE
645
);
646
647
// Get current size
648
BlobProperties properties = pageBlobClient.getProperties();
649
System.out.println("Current size: " + properties.getBlobSize() + " bytes");
650
System.out.println("Current sequence number: " + properties.getBlobSequenceNumber());
651
```
652
653
### Sequence Number Management
654
655
```java
656
import com.azure.storage.blob.models.SequenceNumberActionType;
657
658
// Update sequence number (for optimistic concurrency control)
659
Long newSequenceNumber = 42L;
660
661
// Set to specific value
662
PageBlobItem updateResult = pageBlobClient.updateSequenceNumber(
663
SequenceNumberActionType.UPDATE,
664
newSequenceNumber
665
);
666
667
// Increment by 1
668
PageBlobItem incrementResult = pageBlobClient.updateSequenceNumber(
669
SequenceNumberActionType.INCREMENT,
670
null // ignored for increment
671
);
672
673
// Set to maximum of current and provided value
674
PageBlobItem maxResult = pageBlobClient.updateSequenceNumber(
675
SequenceNumberActionType.MAX,
676
newSequenceNumber
677
);
678
679
System.out.println("New sequence number: " + updateResult.getBlobSequenceNumber());
680
681
// Update with conditions
682
Response<PageBlobItem> updateResponse = pageBlobClient.updateSequenceNumberWithResponse(
683
SequenceNumberActionType.UPDATE,
684
100L,
685
new BlobRequestConditions().setIfSequenceNumberEqual(incrementResult.getBlobSequenceNumber()),
686
Duration.ofSeconds(30),
687
Context.NONE
688
);
689
```
690
691
### Incremental Copy (Page Blob Snapshots)
692
693
```java
694
// Perform incremental copy (copy only changed pages)
695
String sourcePageBlobUrl = "https://source.blob.core.windows.net/vhds/base.vhd";
696
String sourceSnapshot = "2023-12-01T10:30:00.0000000Z";
697
698
CopyStatusType copyStatus = pageBlobClient.copyIncremental(sourcePageBlobUrl, sourceSnapshot);
699
System.out.println("Incremental copy status: " + copyStatus);
700
701
// Incremental copy with options
702
PageBlobCopyIncrementalOptions copyOptions = new PageBlobCopyIncrementalOptions(
703
sourcePageBlobUrl, sourceSnapshot)
704
.setRequestConditions(new BlobRequestConditions()
705
.setIfNoneMatch("*"));
706
707
Response<CopyStatusType> copyResponse = pageBlobClient.copyIncrementalWithResponse(
708
copyOptions,
709
Duration.ofMinutes(10),
710
Context.NONE
711
);
712
713
// Monitor copy progress
714
BlobProperties copyProperties = pageBlobClient.getProperties();
715
while (copyProperties.getCopyStatus() == CopyStatusType.PENDING) {
716
System.out.println("Copy progress: " + copyProperties.getCopyProgress());
717
Thread.sleep(5000); // Wait 5 seconds
718
copyProperties = pageBlobClient.getProperties();
719
}
720
721
System.out.println("Final copy status: " + copyProperties.getCopyStatus());
722
```
723
724
## Async Specialized Clients
725
726
### Async Block Blob Operations
727
728
```java
729
import reactor.core.publisher.Mono;
730
import reactor.core.publisher.Flux;
731
732
// Async block blob operations
733
BlockBlobAsyncClient asyncBlockBlobClient = asyncBlobClient.getBlockBlobAsyncClient();
734
735
// Async upload
736
Mono<BlockBlobItem> uploadMono = asyncBlockBlobClient.upload(
737
BinaryData.fromString("Async block blob content"),
738
true
739
);
740
741
uploadMono
742
.doOnSuccess(result -> System.out.println("Async upload: " + result.getETag()))
743
.doOnError(ex -> System.err.println("Upload failed: " + ex.getMessage()))
744
.subscribe();
745
746
// Async block staging and committing
747
List<String> blockIds = new ArrayList<>();
748
String blockId = Base64.getEncoder().encodeToString("async-block".getBytes());
749
750
Mono<Void> stageBlockMono = asyncBlockBlobClient.stageBlock(blockId, BinaryData.fromString("Block content"));
751
Mono<BlockBlobItem> commitMono = stageBlockMono.then(
752
asyncBlockBlobClient.commitBlockList(List.of(blockId))
753
);
754
755
commitMono
756
.doOnSuccess(result -> System.out.println("Async blocks committed: " + result.getETag()))
757
.subscribe();
758
```
759
760
### Async Append Blob Operations
761
762
```java
763
// Async append blob operations
764
AppendBlobAsyncClient asyncAppendBlobClient = asyncBlobClient.getAppendBlobAsyncClient();
765
766
// Create and append in sequence
767
Mono<Void> appendSequence = asyncAppendBlobClient.createIfNotExists()
768
.then(asyncAppendBlobClient.appendBlock(BinaryData.fromString("First log entry\n")))
769
.then(asyncAppendBlobClient.appendBlock(BinaryData.fromString("Second log entry\n")))
770
.then(asyncAppendBlobClient.appendBlock(BinaryData.fromString("Third log entry\n")))
771
.then();
772
773
appendSequence
774
.doOnSuccess(v -> System.out.println("Async append sequence completed"))
775
.doOnError(ex -> System.err.println("Append sequence failed: " + ex.getMessage()))
776
.subscribe();
777
778
// Reactive logging pattern
779
Flux<String> logMessages = Flux.just(
780
"Application started",
781
"User authenticated",
782
"Data processed",
783
"Application shutdown"
784
);
785
786
logMessages
787
.map(msg -> "[" + OffsetDateTime.now() + "] " + msg + "\n")
788
.map(BinaryData::fromString)
789
.flatMap(data -> asyncAppendBlobClient.appendBlock(data))
790
.doOnNext(result -> System.out.println("Log appended at: " + result.getBlobAppendOffset()))
791
.doOnComplete(() -> System.out.println("All log messages written"))
792
.subscribe();
793
```
794
795
### Async Page Blob Operations
796
797
```java
798
// Async page blob operations
799
PageBlobAsyncClient asyncPageBlobClient = asyncBlobClient.getPageBlobAsyncClient();
800
801
// Create and upload pages
802
long pageSize = 1024 * 512L; // 512KB
803
PageRange range = new PageRange().setStart(0).setEnd(511);
804
byte[] pageData = new byte[512];
805
806
Mono<Void> pageSequence = asyncPageBlobClient.create(pageSize)
807
.then(asyncPageBlobClient.uploadPages(range, BinaryData.fromBytes(pageData)))
808
.then();
809
810
pageSequence
811
.doOnSuccess(v -> System.out.println("Async page blob created and page uploaded"))
812
.doOnError(ex -> System.err.println("Page operation failed: " + ex.getMessage()))
813
.subscribe();
814
815
// Parallel page uploads
816
List<Mono<PageBlobItem>> pageUploads = new ArrayList<>();
817
for (int i = 0; i < 10; i++) {
818
PageRange pageRange = new PageRange()
819
.setStart(i * 512L)
820
.setEnd((i + 1) * 512L - 1);
821
byte[] data = new byte[512];
822
Arrays.fill(data, (byte) i);
823
824
pageUploads.add(asyncPageBlobClient.uploadPages(pageRange, BinaryData.fromBytes(data)));
825
}
826
827
Mono<Void> allPagesUploaded = Mono.when(pageUploads);
828
allPagesUploaded
829
.doOnSuccess(v -> System.out.println("All pages uploaded in parallel"))
830
.subscribe();
831
```
832
833
## Performance Considerations
834
835
### Optimal Block Sizes
836
837
```java
838
// Optimize block sizes based on file size and network conditions
839
public ParallelTransferOptions getOptimalTransferOptions(long fileSize) {
840
ParallelTransferOptions options = new ParallelTransferOptions();
841
842
if (fileSize < 32 * 1024 * 1024) { // < 32MB
843
options.setBlockSizeLong(1 * 1024 * 1024L); // 1MB blocks
844
options.setMaxConcurrency(4);
845
} else if (fileSize < 512 * 1024 * 1024) { // < 512MB
846
options.setBlockSizeLong(4 * 1024 * 1024L); // 4MB blocks
847
options.setMaxConcurrency(8);
848
} else { // >= 512MB
849
options.setBlockSizeLong(8 * 1024 * 1024L); // 8MB blocks
850
options.setMaxConcurrency(16);
851
}
852
853
return options;
854
}
855
856
// Usage for large file uploads
857
long fileSize = Files.size(Paths.get("largefile.dat"));
858
ParallelTransferOptions optimizedOptions = getOptimalTransferOptions(fileSize);
859
860
BlobUploadFromFileOptions uploadOptions = new BlobUploadFromFileOptions("largefile.dat")
861
.setParallelTransferOptions(optimizedOptions);
862
863
blockBlobClient.uploadFromFileWithResponse(uploadOptions, Duration.ofMinutes(30), Context.NONE);
864
```
865
866
## Related Documentation
867
868
- [← Back to Overview](index.md)
869
- [← Blob Operations](blob-client.md)
870
- [Streaming & Advanced I/O →](streaming.md)
871
- [Model Classes & Enums →](models.md)
872
- [Configuration Options →](options.md)