Для этого контейнера включено управление версиями и обратимое удаление
Использование приведенного ниже кода для удаления всей версии файла
Код: Выделить всё
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import com.azure.core.http.HttpClient;
import com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder;
import com.azure.core.http.rest.Response;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobContainerClientBuilder;
import com.azure.storage.blob.batch.BlobBatch;
import com.azure.storage.blob.batch.BlobBatchClient;
import com.azure.storage.blob.batch.BlobBatchClientBuilder;
import com.azure.storage.blob.models.BlobListDetails;
import com.azure.storage.blob.models.ListBlobsOptions;
import com.azure.storage.common.StorageSharedKeyCredential;
public class BlobVersionBatchDeleteWithBatchAPI2 {
private static final String CONTAINER = "#####";
private static final String ACCOUNT = "######";
private static final HttpClient HTTP_CLIENT = new OkHttpAsyncHttpClientBuilder().build();
public static void main(String[] args) {
if (args.length < 1) {
System.err.println("Usage: BlobVersionBatchDelete ");
return;
}
String blobName = "2147850/version_10_soft_del_1/20";
BlobContainerClient containerClient = getBlobContainerClient(args[0]);
BlobBatchClient batchClient = new BlobBatchClientBuilder(containerClient).buildClient();
List versionUrls = new ArrayList();
List currentversionUrls = new ArrayList();
// Step 1: Collect version URLs
containerClient
.listBlobs(new ListBlobsOptions().setPrefix(blobName).setDetails(
new BlobListDetails().setRetrieveVersions(true).setRetrieveDeletedBlobs(true)), null)
.forEach(blobItem -> {
boolean skip = false;
if (!blobName.equals(blobItem.getName())) {
skip = true;
}
if (blobItem.getVersionId() == null) {
skip = true;
}
// skip current version
if (Boolean.TRUE.equals(blobItem.isCurrentVersion())) {
System.out.printf("[SKIP] Current version: %s%n", blobItem.getVersionId());
skip = true;
}
// Skip soft-deleted
if (Boolean.TRUE.equals(blobItem.isDeleted())) {
System.out.printf("[SKIP] Deleted entry: %s%n", blobItem.getVersionId());
skip = true;
}
System.out.printf("[LIST] Version: [%s] | isCurrentVersion: %s,%b%n", blobItem.getVersionId(),
blobItem.isCurrentVersion(), skip);
String versionUrl = containerClient.getBlobClient(blobName)
.getVersionClient(blobItem.getVersionId()).getBlobUrl();
if (!skip) {
versionUrls.add(versionUrl);
}
else if (Boolean.TRUE.equals(blobItem.isCurrentVersion())) {
currentversionUrls.add(versionUrl);
}
});
BlobBatch batchOp = batchClient.getBlobBatch();
Response deleteResponse1 = null;
for (String url : versionUrls) {
System.out.println("Adding to batch delete: " + url);
deleteResponse1 = batchOp.deleteBlob(url);
}
batchClient.submitBatch(batchOp);
System.out.printf("Delete operation 1 completed with status code: %d%n", deleteResponse1.getStatusCode());
// Step 3: Delete base blob
// containerClient.getBlobClient(blobName).deleteIfExists();
BlobClient blobClient = containerClient.getBlobClient(blobName);
blobClient.delete();
batchOp = batchClient.getBlobBatch();
for (String url : currentversionUrls) {
System.out.println("Adding to batch delete: " + url);
batchOp.deleteBlob(url);
}
batchClient.submitBatch(batchOp);
System.out.println("All versions deleted using batch.");
}
private static BlobContainerClient getBlobContainerClient(String accessKey) {
String endPoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net/%s", ACCOUNT, CONTAINER);
StorageSharedKeyCredential storageCreds = new StorageSharedKeyCredential(ACCOUNT, accessKey);
return new BlobContainerClientBuilder().endpoint(endPoint).httpClient(HTTP_CLIENT).credential(storageCreds)
.buildClient();
}
}
Но при удалении базового объекта возникает ошибка
BlobClient blobClient = containerClient.getBlobClient(blobName);
blobClient.delete();
Вывод и ОШИБКА
[LIST] Version: [2026-03-26T13:27:28.5647481Z] | isCurrentVersion: null,false
[SKIP] Current version: 2026-03-26T13:27:39.8043318Z
[LIST] Version: [2026-03-26T13:27:39.8043318Z] | isCurrentVersion: true,true
Adding to batch delete: https://account.blob.core.windows.net/test-container/2147850%2Fversion_10_soft_del_1%2F20?versionid=2026-03-26T13:27:28.5647481Z
Delete operation 1 completed with status code: 202
Exception in thread "main" com.azure.storage.blob.models.BlobStorageException: Status code 404, "BlobNotFoundRequestId:
Time:2026-03-27T06:55:50.4122729Z"
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733)
at com.azure.core.implementation.MethodHandleReflectiveInvoker.invokeWithArguments(MethodHandleReflectiveInvoker.java:35)
at com.azure.core.implementation.http.rest.ResponseExceptionConstructorCache.invoke(ResponseExceptionConstructorCache.java:51)
at com.azure.core.implementation.http.rest.RestProxyBase.instantiateUnexpectedException(RestProxyBase.java:356)
at com.azure.core.implementation.http.rest.AsyncRestProxy.lambda$ensureExpectedStatus$1(AsyncRestProxy.java:128)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:113)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2398)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:171)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2194)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:2068)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:55)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onNext(FluxHide.java:137)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
at reactor.core.publisher.FluxHide$SuppressFuseableSubscriber.onNext(FluxHide.java:137)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:151)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:129)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1816)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:151)
at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:172)
at com.azure.core.http.okhttp.OkHttpAsyncHttpClient$OkHttpCallback.onResponse(OkHttpAsyncHttpClient.java:270)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
at java.base/java.lang.Thread.run(Thread.java:1583)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:99)
at reactor.core.publisher.Mono.block(Mono.java:1707)
at com.azure.storage.common.implementation.StorageImplUtils.blockWithOptionalTimeout(StorageImplUtils.java:147)
at com.azure.storage.blob.specialized.BlobClientBase.deleteWithResponse(BlobClientBase.java:1265)
at com.azure.storage.blob.specialized.BlobClientBase.delete(BlobClientBase.java:1230)
at BlobVersionBatchDeleteWithBatchAPI2.main(BlobVersionBatchDeleteWithBatchAPI2.java:97)