从Azure Blob获取最新修改的文件

25

假设我每天在我的Blob存储中生成几个json文件,我想要做的是获取任何目录中最新修改的文件。因此,我的Blob中会有类似于以下内容:

2016/01/02/test.json
2016/01/02/test2.json
2016/02/03/test.json

我想获取2016/02/03/test.json。所以一种方法是获取文件的完整路径,并进行正则表达式检查以找到最新创建的目录,但如果每个目录中有多个json文件,则此方法无效。是否有类似于File.GetLastWriteTime的方法可获取最近修改的文件? 我正在使用以下代码获取所有文件:

public static CloudBlobContainer GetBlobContainer(string accountName, string accountKey, string containerName)
{
    CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
    // blob client
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    // container
    CloudBlobContainer blobContainer = blobClient.GetContainerReference(containerName);
    return blobContainer;
}

public static IEnumerable<IListBlobItem> GetBlobItems(CloudBlobContainer container)
{
    IEnumerable<IListBlobItem> items = container.ListBlobs(useFlatBlobListing: true);
    return items;
}

public static List<string> GetAllBlobFiles(IEnumerable<IListBlobItem> blobs)
{
    var listOfFileNames = new List<string>();

    foreach (var blob in blobs)
    {
        var blobFileName = blob.Uri.Segments.Last();
        listOfFileNames.Add(blobFileName);
    }
    return listOfFileNames;
}

1
最终,您如何实现具有最后修改属性的多个文件夹路径的这些情况? - Neo
所有当前的答案都已经过期,无法适用于新的V12 Azure Blob Nuget包。 - rollsch
8个回答

33
每个IListBlobItem将是一个CloudBlockBlob、CloudPageBlob或CloudBlobDirectory。
在向块或页blob转换后,或者使用其共享的基类CloudBlob(最好使用as关键字并检查null),您可以通过blockBlob.Properties.LastModified访问修改日期。
请注意,您的实现将在容器中扫描所有blob,这可能需要一段时间,如果有数十万个文件。目前没有更有效地查询blob存储的方法,(除非您滥用文件命名并以这种方式编码日期,使得较新的日期按字母顺序排在首位)。实际上,如果您需要更好的查询性能,我建议保留一个数据库表,该表将所有文件列表表示为行,其中包括索引的DateModified列进行搜索和具有blob路径的列以便轻松访问文件。
更新(2022):据看来,微软现在提供可自定义的 Blob 索引标签。这应该允许在 Blob 元数据上添加自定义的 DateModified 属性或类似属性,并对您的 Blob 执行高效的“大于”/“小于”查询,无需使用单独的数据库。(注意:它似乎只支持字符串值,因此对于日期值,您需要确保将它们保存为词典排序格式,例如“yyyy-MM-dd”。)

目录怎么样?如何访问它们的最后修改时间? - Shmil The Cat
1
目录?你是指容器吗?还是指 Blob 名称可以具有的人工路径分隔符构造? - Mike Asdf
1
后者(blob名称可以具有的人工路径分隔符构造) - Shmil The Cat
1
所以一个“目录”实际上是共享某个字符串前缀的一组 blob,因此您需要枚举这些 blob 并聚合 blob 时间戳(按最小值、最大值或适合您情况的其他方式)。请注意,通过前缀过滤 blob 是由 API 支持的。 - Mike Asdf
所有其他答案都没有提到强制转换 - 这非常有帮助。 - VSO
这对于Azure V12 NuGet包已经过时了。 - rollsch

17

像Yar所说,您可以使用单个blob对象的LastModified属性。以下是一段代码片段,显示了如何在获得正确容器的引用后执行此操作:

像 Yar 所说,您可以使用单个 blob 对象的 LastModified 属性。下面是代码片段,演示了如何在获取正确容器的引用后执行该操作:

var latestBlob = container.ListBlobs()
    .OfType<CloudBlockBlob>()
    .OrderByDescending(m => m.Properties.LastModified)
    .ToList()
    .First();

注意:blob类型可能不是<CloudBlockBlob>。如有必要,请确保更改。


我正在尝试使用 AZURE FILE SHARE STORAGE 实现相同的功能,但是出现了错误 'Sequence contains no elements',有什么线索吗? - Neo
1
LastModified 为空。 - Neo

3
之前的答案已经过时了,针对新的V12 Nuget包,我使用了以下指南协助从9版本升级到12版本: https://elcamino.cloud/articles/2020-03-30-azure-storage-blobs-net-sdk-v12-upgrade-guide-and-tips.html 新的Nuget包是Azure.Storage.Blobs,我使用的是12.8.4版本。
下面的代码将获取您的最后修改日期。这段代码也有一个异步版本。
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Azure.Storage.Blobs;
using Azure.Storage.Sas;
using Azure.Storage.Blobs.Specialized;

DateTimeOffset? GetLastModified()
{
    BlobServiceClient blobServiceClient = new BlobServiceClient("connectionstring")
    BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient("blobname");
    BlobClient blobClient = blobContainerClient.GetBlobClient("file.txt");
    if (blobClient == null || !blobClient.Exists()) return null;
    DateTimeOffset lastModified = blobClient.GetProperties().Value.LastModified;
    return lastModified;
}

2
OP的问题是获取最新修改的文件,而这里你只是获取特定文件的最后修改日期?不确定它如何解决OP的问题。 - user1075613
1
循环遍历块。我主要是想展示新的API。 - rollsch

3
       //connection string
        string storageAccount_connectionString = "**NOTE: CONNECTION STRING**";

        // Retrieve storage account from connection string.
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccount_connectionString);

        // Create the blob client.
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

        // Retrieve reference to a previously created container.
        CloudBlobContainer container = blobClient.GetContainerReference("**NOTE:NAME OF CONTAINER**");
        //The specified container does not exist

        try
        {
            //root directory
            CloudBlobDirectory dira = container.GetDirectoryReference(string.Empty);
            //true for all sub directories else false 
            var rootDirFolders = dira.ListBlobsSegmentedAsync(true, BlobListingDetails.Metadata, null, null, null, null).Result;

            foreach (var blob in rootDirFolders.Results)
            {
                if (blob is CloudBlockBlob blockBlob)

                {
                    var time = blockBlob.Properties.LastModified;
                    Console.WriteLine("Data", time);

                }
            }

        }
        catch (Exception e)
        {
            //  Block of code to handle errors
            Console.WriteLine("Error", e);

        }

2

我想在Azure文件共享存储中使用相同的内容,我该如何使用Azure Web Jobs SDK? - Neo

1

如果出现问题,请使用 blockBlob.Container.Properties.LastModified


这将返回容器的LastModified日期。 - Jorn.Beyers

0
使用rollsch和hbd的方法,我能够轻松地生成最新的图像。
public string File;

public async Task OnGetAsync()
{
    var gettingLastModified = _blobServiceClient
        .GetBlobContainerClient("images")
        .GetBlobs()
        .OrderByDescending(m => m.Properties.LastModified)
        .First();

    LatestImageFromAzure = gettingLastModified.Name;

    File = await _blobService.GetBlob(LatestImageFromAzure, "images");
}

我也在使用这些方法https://www.youtube.com/watch?v=B_yDG35lb5I&t=1864s


0

使用Microsoft.Azure.Storage.Blob,您可以按如下方式获取:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;

namespace ListLastModificationOnBlob
{
    class Program
    {
        static void Main(string[] args)
        {
            MainAsync().Wait();
        }

        static async Task MainAsync()
        {
            string storageAccount_connectionString = @"Your connection string";

            // Retrieve storage account from connection string.
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccount_connectionString);

            // Create the blob client.
            CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

            var containers = await ListContainersAsync(blobClient);

            foreach (var container in containers)
            {
                Console.WriteLine(container.Name);

                try
                {
                    //root directory
                    CloudBlobDirectory dira = container.GetDirectoryReference(string.Empty);
                    //true for all sub directories else false 
                    var rootDirFolders = dira.ListBlobsSegmentedAsync(true, BlobListingDetails.Metadata, null, null, null, null).Result;

                    using (var w = new StreamWriter($"{container.Name}.csv"))
                    {
                        foreach (var blob in rootDirFolders.Results)
                        {
                            if (blob is CloudBlob blockBlob)
                            {
                                var time = blockBlob.Properties.LastModified;
                                var created = blockBlob.Properties.Created;

                                var line = $"{blockBlob.Name},{created},{time}";
                                await w.WriteLineAsync(line);
                                await w.FlushAsync();
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    //  Block of code to handle errors
                    Console.WriteLine("Error", e);

                }
            }
        }

        private static async Task<IEnumerable<CloudBlobContainer>> ListContainersAsync(CloudBlobClient cloudBlobClient)
        {
            BlobContinuationToken continuationToken = null;
            var containers = new List<CloudBlobContainer>();

            do
            {
                ContainerResultSegment response = await cloudBlobClient.ListContainersSegmentedAsync(continuationToken);
                continuationToken = response.ContinuationToken;
                containers.AddRange(response.Results);

            } while (continuationToken != null);

            return containers;
        }
    }
}

给定存储帐户的上述代码:

  • 获取帐户中的所有容器
  • 获取容器中的所有 Blob
  • 将 Blob 名称、CreatedLastModified 保存在 CSV 文件中(文件名类似于容器)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接