问题描述
在尝试删除Azure Blob存储中特定前缀/目录下的所有Blob时遇到问题。当运行下面的代码时,item.isPrefix()返回null。
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);
PagedIterable<BlobItem> blobItems = containerClient.listBlobsByHierarchy(folderKey);
Iterator<BlobItem> iterator = blobItems.iterator();
while (iterator.hasNext()) {
BlobItem item = iterator.next();
if (item.isPrefix() == false) {
BlockBlobClient blobClient = containerClient.getBlobClient(item.getName()).getBlockBlobClient();
blobClient.delete();
}
}
但是,调试此代码时,isPrefix实际上设置了一个值(false)。这使我相信,正常运行时BloblItem的状态不会最终确定,但在调试时,调试器会停止执行,这样就可以完全设置BlobItem。我在the docs中读到listBlobsByHierarchy返回了一个“反应性发布者”,但不确定如何处理。
如何安全删除特定目录下的所有Blob?
注意:如果我不检查isPrefix并删除所有内容,则listBlobsByHierarchy返回时,尝试删除代表目录的BlobItem时会收到404错误。
更新:
容器内的文件层次结构:
Container/
- directory1
- sub-directory1
- file1
- file2
- directory2
- sub-directory1
- file3
解决方法
用于删除具有特定前缀的blob的简单代码:
package testbowman;
import com.azure.storage.blob.*;
import com.azure.storage.blob.models.*;
import java.io.*;
import java.time.Duration;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
String connectStr = "DefaultEndpointsProtocol=https;AccountName=0730bowmanwindow;AccountKey=OczyRTeVtOxJpGaoq39QFExdTbIWNeKpVuTQdeco1hPfMkXci2hqSi3w5U2DGrYilnJKanueDFurzPXLWbTa8w==;EndpointSuffix=core.windows.net";
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().connectionString(connectStr).buildClient();
String containerName = "test";
ListBlobsOptions options = new ListBlobsOptions()
.setPrefix("test/")
.setDetails(new BlobListDetails()
.setRetrieveDeletedBlobs(true)
);
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);
containerClient.listBlobsByHierarchy("/",options,Duration.ofSeconds(30l)).forEach(blob -> {
BlobClient blobClient = containerClient.getBlobClient(blob.getName());
blobClient.delete();
});
System.out.println( "Hello World!" );
}
}
上面的代码对我而言效果很好,您可以尝试一下。
,我遇到了同样的问题。对我来说,对于实际 blob(非目录),BlobItem.IsPrefix
属性看起来仍然是 null
,对于目录设置为 Boolean.TRUE
。这是列出我的容器时的调试输出,使用前缀 70000/10000/file-1.pdf/
(内部有 3 个 blob 和 1 个目录):
XXX bi.getName(): 70000/10000/file-1.pdf/1.0
XXX bi.isPrefix(): null
XXX bi.getName(): 70000/10000/file-1.pdf/1.1
XXX bi.isPrefix(): null
XXX bi.getName(): 70000/10000/file-1.pdf/1.2
XXX bi.isPrefix(): null
XXX bi.getName(): 70000/10000/file-1.pdf/1.3/
XXX bi.isPrefix(): true
调试代码(有足够的时间“最终确定”正在迭代的对象)对我来说没有任何改变,对于 blob 仍然是 null
。
作为最终结果,我使用这个(更具防御性的)代码迭代项目:
PagedIterable<BlobItem> blobItems =
_blobContainerClient.listBlobsByHierarchy(
PATH_DELIMITER,opts,null);
// fetch all blobs under given directory; only take non-directories; drop the shared prefix
List<String> versions = blobItems.stream()
.filter(bi -> bi.isPrefix() == null || !bi.isPrefix())
.map(bi -> bi.getName().substring(blobsPrefix.length()))
.collect(Collectors.toList());
return versions.toArray(new String[versions.size()]);