Andi Ariffin
Andi Ariffin

Reputation: 98

Lists all Blobs inside Azure Container with directory-level support using web front-end

I'm currently working on developing some set of codes to display all blobs inside specified Azure Container using web front-end. I'm expecting the final output to be something like this:

Directory listing with Apache Mod_autoindex

I started by creating a dummy storage account and populates it with some dummy files for me to play around with.

https://alicebob.blob.core.windows.net/documents  
├── docx  
│   ├── 201801_Discussion.docx  
│   ├── 201802_Discussion.docx  
├── xlsx  
│   ├── 201801_Summary.xlsx  
│   ├── 201802_Summary.xlsx  
│   ├── 201803_Summary.xlsx  
├── 201801_Review.pdf  
├── 201802_Review.pdf  
├── 201803_Review.pdf  

To develop file listing function, I'm using Azure Storage JavaScript client library from here and put all the necessary codes (.html and .js files) in Azure Static website $web container and set index.html as Index document name and Error document path in the Static website configuration.

https://alicebob.z23.web.core.windows.net/  
├── azure-storage.blob.min.js  
├── azure-storage.common.min.js  
├── index.html  

The problem is that the function to do the listing is only either listBlobsSegmentedWithPrefix or listBlobDirectoriesSegmentedWithPrefix. So, in my case, I assume it wouldn't work straightforwardly to list all the blobs and directories in a well-structured / tree format.

My current approach is that I trick the code to keep using listBlobDirectoriesSegmentedWithPrefix until there is no more directory to list inside, then continue to list using listBlobsSegmentedWithPrefix

So far I'm quite satisfied that my code can list all the Blobs at the leaf-level and also list all the directories if it isn't on the leaf-level. You can take a look at the blob listing here and feel free to go for 'View Source' to see the codes I built so far.

The only problem that I face is that this set of code fails to list the Blobs if it wasn't on the leaf-level. For example, it fails to list these blobs on alicebob storage account:

├── 201801_Review.pdf  
├── 201802_Review.pdf  
├── 201803_Review.pdf  

This is an expected issue as I'm not running listBlobsSegmentedWithPrefix if it isn't on the leaf-level. The reason is that it will produces the output with something like this which isn't what I want:

├── docx/201801_Discussion.docx  
├── docx/201802_Discussion.docx  
├── xlsx/201801_Summary.xlsx  
├── xlsx/201802_Summary.xlsx  
├── xlsx/201803_Summary.xlsx  
├── 201801_Review.pdf  
├── 201802_Review.pdf  
├── 201803_Review.pdf 

Any suggestion on how to overcome this issue? The real implementation would involves a huge amount of data so I think a simple if-then-else wouldn't be efficient on this case.

sorry for the long description but I just want to describe my problem as clear as possible :)

Upvotes: 3

Views: 2678

Answers (2)

Ari
Ari

Reputation: 583

You can also do this with out the overhead of the whole storage api using a fetch request as follows.

  fetch("https://cvworkshop.blob.core.windows.net/telaviv-bw/?restype=container&comp=list")
    .then(response => response.text())
    .then(str => new window.DOMParser().parseFromString(str, "text/xml"))
    .then(data => console.log(data));

Upvotes: 0

Jerry Liu
Jerry Liu

Reputation: 17800

There's an option called delimiter when listing blobs. Let's get down to code.

blobService.listBlobsSegmentedWithPrefix('documents',null,null,{delimiter:'/'},(error,result,response)=>{
    console.log(result);
    console.log(response.body.EnumerationResults.Blobs.BlobPrefix);
})

With delimiter /, listing operation returns results of two parts.

  1. result, contains info of blobs under the root directory of container, e.g. 201801_Review.pdf, etc. in your case.
  2. BlobPrefix in response body, contains directory names of single level with delimiter.

    [ { Name: 'docx/' }, { Name: 'xlsx/' } ]
    

Use BlobPrefix as prefix, we can continue listing content of current subdirectory.

    blobService.listBlobsSegmentedWithPrefix('documents','docx/',null,{delimiter:'/'},(error,result,response)=>{
        console.log(result);
        console.log(response.body.EnumerationResults.Blobs.BlobPrefix);
    }) 

Basically point 1 result is enough, you don't necessarily have to use BlobPrefix to refactor your code. See more info in section Using a Delimiter to Traverse the Blob Namespace of list blobs.

Upvotes: 6

Related Questions