如何列出blob容器中的所有目录和子目录?
这是我到目前为止所做的:
public List<CloudBlobDirectory> Folders { get; set; }
public List<CloudBlobDirectory> GetAllFoldersAndSubFoldersFromBlobStorageContainer()
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("mycontainer");
if (container.Exists())
{
Folders = new List<CloudBlobDirectory>();
foreach (var item in container.ListBlobs())
{
if (item is CloudBlobDirectory)
{
var folder = (CloudBlobDirectory)item;
Folders.Add(folder);
GetSubFolders(folder);
}
}
}
return Folders;
}
private void GetSubFolders(CloudBlobDirectory folder)
{
foreach (var item in folder.ListBlobs())
{
if (item is CloudBlobDirectory)
{
var subfolder = (CloudBlobDirectory)item;
Folders.Add(subfolder);
GetSubFolders(subfolder);
}
}
}
上面的代码片段给出了我想要的列表,但我不确定递归方法和其他.NET / C#语法和最佳实践编程模式。简而言之,我希望最终结果尽可能优雅和高效。
如何改进上述代码段?
答案 0 :(得分:5)
只有您的优雅代码才会问到,它会对存储服务进行过多调用以获取数据。对于每个文件夹/子文件夹,它将转到存储服务并获取数据。
您可以通过列出容器中的所有blob来避免这种情况,然后确定它是否是客户端上的目录或blob。例如,在这里看一下这段代码(它不像你的优雅,但希望它可以让你知道我想传达的内容):
static void FetchCloudBlobDirectories()
{
var account = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
var containerName = "container-name";
var blobClient = account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(containerName);
var containerUrl = container.Uri.AbsoluteUri;
BlobContinuationToken token = null;
List<string> blobDirectories = new List<string>();
List<CloudBlobDirectory> cloudBlobDirectories = new List<CloudBlobDirectory>();
do
{
var blobPrefix = "";//We want to fetch all blobs.
var useFlatBlobListing = true;//This will ensure all blobs are listed.
var blobsListingResult = container.ListBlobsSegmented(blobPrefix, useFlatBlobListing, BlobListingDetails.None, 500, token, null, null);
token = blobsListingResult.ContinuationToken;
var blobsList = blobsListingResult.Results;
foreach (var item in blobsList)
{
var blobName = (item as CloudBlob).Name;
var blobNameArray = blobName.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
//If the blob is in a virtual folder/sub folder, it will have a "/" in its name.
//By splitting it, we are making sure that it is indeed the case.
if (blobNameArray.Length > 1)
{
StringBuilder sb = new StringBuilder();
//Since the blob name (somefile.png) will be the last element of this array and we're not interested in this,
//We only iterate through 2nd last element.
for (var i=0; i<blobNameArray.Length-1; i++)
{
sb.AppendFormat("{0}/", blobNameArray[i]);
var blobDirectory = sb.ToString();
if (blobDirectories.IndexOf(blobDirectory) == -1)//We check if we have already added this to our list or not
{
blobDirectories.Add(blobDirectory);
var cloudBlobDirectory = container.GetDirectoryReference(blobDirectory);
cloudBlobDirectories.Add(cloudBlobDirectory);
Console.WriteLine(cloudBlobDirectory.Uri);
}
}
}
}
}
while (token != null);
}
答案 1 :(得分:1)
我用来获取所有文件和子目录的函数。 请注意在运行函数之前在构造函数或某处分配BlobContainer对象,以便它不会为每个文件/目录调用它
public IEnumerable<String> getAllFiles(string prefix, bool slash = false) //Prefix for, slash for recur, see folders
{
List<String> FileList = new List<string>();
if (!BlobContainer.Exists()) return FileList; //BlobContainer is defined in class before this is run
var items = BlobContainer.ListBlobs(prefix);
foreach (var blob in items)
{
String FileName = "";
if (blob.GetType() == typeof(CloudBlockBlob))
{
FileName = ((CloudBlockBlob)blob).Name;
if (slash) FileName.Remove(0, 1); //remove slash if file
FileList.Add(FileName);
}
else if (blob.GetType() == typeof(CloudBlobDirectory))
{
FileName = ((CloudBlobDirectory)blob).Prefix;
IEnumerable<String> SubFileList = getAllFiles(FileName, true);
foreach (String s in SubFileList)
{
FileList.Add(s);
}
}
}
return FileList;
}