调用listBlobsByHierarchy

问题描述

在尝试删除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()]);

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...