【问题标题】:Reading line by line from blob Storage in Windows Azure从 Windows Azure 中的 blob 存储逐行读取
【发布时间】:2020-08-11 08:10:08
【问题描述】:

有什么方法可以逐行读取windows Azure中blob存储中的文本文件??

谢谢

【问题讨论】:

    标签: windows azure


    【解决方案1】:

    是的,您可以使用流来执行此操作,并且不一定要求您拉取整个文件,但请阅读到最后(答案的......不是有问题的文件),因为您可能想要无论如何拉整个文件。

    代码如下:

    StorageCredentialsAccountAndKey credentials = new StorageCredentialsAccountAndKey(
        "YourStorageAccountName",
        "YourStorageAccountKey"
    );
    CloudStorageAccount account = new CloudStorageAccount(credentials, true);
    CloudBlobClient client = new CloudBlobClient(account.BlobEndpoint.AbsoluteUri, account.Credentials);
    CloudBlobContainer container = client.GetContainerReference("test");
    
    CloudBlob blob = container.GetBlobReference("CloudBlob.txt");
    using (var stream = blob.OpenRead())
    {
        using (StreamReader reader = new StreamReader(stream))
        {
            while (!reader.EndOfStream)
            {
                Console.WriteLine(reader.ReadLine());
            }
        }
    }
    

    我将名为 CloudBlob.txt 的文本文件上传到名为 test 的容器中。该文件大小约为 1.37 MB(我实际上使用了 GitHub 上的 CloudBlob.cs 文件,将其复制到同一个文件中六七次)。我使用 BlockBlob 进行了尝试,这很可能是您将要处理的内容,因为您正在谈论一个文本文件。

    这会像往常一样获得对 BLOB 的引用,然后我从 CloudBlob 对象中调用 OpenRead() 方法,该方法会返回一个 BlobStream ,然后您可以将其包装在 StreamReader 中以获取 ReadLine 方法。我用这个运行 fiddler 并注意到它最终调用了 3 次来获取额外的块来完成文件。看起来 BlobStream 有一些属性,您可以使用这些属性来调整您必须执行的预读量,但我没有尝试调整它们。根据one reference,我发现重试策略也适用于最后一次读取级别,因此它不会再次尝试重新读取整个内容,只是最后一次失败的请求。在此引用:

    最后,DownloadToFile/ByteArray/Stream/Text() 方法在单个流式获取中执行整个下载。如果您使用 CloudBlob.OpenRead() 方法,它将利用 BlobReadStream 抽象,该抽象将在消耗 Blob 时一次下载一个块。如果发生连接错误,则只需要重新下载一个块(根据配置的 RetryPolicy)。此外,这可能有助于提高性能,因为客户端可能不需要在本地缓存大量数据。对于大型 blob,这可能会有很大帮助,但请注意,您将对服务执行更多的整体事务。 ——乔·贾迪诺

    我认为重要的是要注意 Joe 指出的警告,因为这将导致针对您的存储帐户的总体交易数量增加。但是,根据您的要求,这可能仍然是您正在寻找的选项。

    如果这些是大量文件并且您正在执行大量此类操作,那么它可能会执行很多很多事务(尽管您可以查看是否可以调整 BlobStream 上的属性以增加一次检索的块数量等) .在 CloudBlob 上执行 DownloadFromStream 可能仍然有意义(这将拉下整个内容),然后以与我上面相同的方式从该流中读取。

    唯一真正的区别是一个是一次提取较小的块,另一个是立即提取整个文件。每个都有优点和缺点,这在很大程度上取决于这些文件的大小以及您是否计划在读取文件中间的某个时间点停止(例如“是的,我找到了我正在搜索的字符串!)或者如果您仍然打算读取整个文件。如果您打算无论如何都提取整个文件(例如,因为您正在处理整个文件),那么只需使用 DownloadToStream 并将其包装在 StreamReader 中。

    注意:我使用 1.7 SDK 进行了尝试。我不确定这些选项是由哪个 SDK 引入的。

    【讨论】:

    • 非常感谢,它在本地运行良好,但是当将其部署到云时,它给了我错误。我认为是因为程序花费了很长时间从 blob 中逐行读取。所以我正在考虑您提到的第二个选项,即一次读取整个 blob,然后从流中逐行读取。要阅读整个 blob,我看到它应该在 FileSram 中并将内容保存在 file 中。如果我在云中运行程序,我无法理解文件在哪里以及应该使用哪个路径!!
    • 如何读取整个 blob 并将其保存在流中,然后使用您的方式逐行读取?
    • 我如何使用 DownloadToStream 并将其包装在 StreamReade 中
    • 嗯,我针对云存储帐户而不是模拟器测试了该代码。一些事情:1)你得到什么错误,2)这些文件有多大? 3) 你的应用在读出一行文本时需要多长时间?
    • 1- 它说它是运行时错误。错误发生在服务器上。此应用程序的当前自定义错误设置可防止远程查看应用程序错误的详细信息 2- 它包含 1000 行,每次读取一行执行一些操作,然后执行下一行
    【解决方案2】:

    要直接回答您的问题,您必须先编写代码以在本地下载 blob,然后再读取其中的内容。这主要是因为您不能只进入一个 blob 并在中间读取它的内容。如果您使用过 Windows Azure 表存储,您肯定可以读取表中的具体内容。

    由于您的文本文件是一个 blob 并且位于 Azure Blob 存储中,您真正需要的是在本地下载 blob(作为本地 blob 或内存流),然后读取其中的内容。您必须完全或部分下载 blob,具体取决于您上传的 blob 类型。使用页面 blob,您可以在本地下载特定大小的内容并对其进行处理。很高兴在这方面了解difference between block and page blob

    【讨论】:

    • 谢谢,我从你那里了解到,如果 blob 存储,我必须读取内容并将其保存为流,那么如何从流中逐行读取?
    • 这实际上是不正确的,因为 blob 存储(对于两种 blob 类型)都支持范围请求。但这将是一种非常低效的方法,并且没有办法“读取直到下一个换行符”,只能“读取 N 个字节”。
    【解决方案3】:

    这是我用来逐行获取文件的代码。该文件存储在 Azure 存储中。使用了文件服务,而不是 blob 服务。

    //https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-how-to-use-files
    //https://<storage account>.file.core.windows.net/<share>/<directory/directories>/<file>
    public void ReadAzureFile() {
    
        CloudStorageAccount account = CloudStorageAccount.Parse(
        CloudConfigurationManager.GetSetting("StorageConnectionString"));
        CloudFileClient fileClient = account.CreateCloudFileClient();
        CloudFileShare share = fileClient.GetShareReference("jiosongdetails");
        if (share.Exists()) {
            CloudFileDirectory rootDir = share.GetRootDirectoryReference();
            CloudFile file = rootDir.GetFileReference("songdetails(1).csv");
            if (file.Exists()) {
                using(var stream = file.OpenRead()) {
                    using(StreamReader reader = new StreamReader(stream)) {
                        while (!reader.EndOfStream) {
                            Console.WriteLine(reader.ReadLine());
                    }
                    }
                }
        }
    }
    

    【讨论】:

      【解决方案4】:

      如果有人发现自己在这里,适用于 Azure Blob 存储 (v12) 的 Python SDK 现在具有简单的 download_blob() 方法,它接受两个参数 - 偏移量和长度。

      使用 Python,我的目标是从 blob 存储中的(许多)文件中提取标题行。我知道所有文件的位置,所以我创建了一个 blob 客户端列表——每个文件一个。然后,我遍历列表并运行 download_blob 方法。

      创建 Blob 客户端后(directly via connection string 或使用 BlobServiceClient.get_blob_client() 方法),只需下载前(例如)4k 字节以覆盖任何长标题行,然后使用行尾拆分文本字符('\n')。结果列表的第一个元素将是标题行。我的工作代码(仅针对单个文件)如下所示:

      from azure.storage.blob import BlobServiceClient
      
      MAX_LINE_SIZE = 4096 # You can change this..
      my_blob_service_client = BlobServiceClient(account_url=my_url, credential=my_shared_access_key)
      my_blob_client = my_blob_service_client.get_blob_client('my-container','my_file.csv')
      
      file_size = my_blob_client.size
      offset = 0
      

      然后您可以编写一个循环来逐行下载文本,方法是计算第一个行尾的字节偏移量,并获取下一个 MAX_LINE_SIZE 个字节。为了获得最佳效率,最好知道一条线的最大长度,但如果不知道,请猜测一个足够大的长度。

      while offset < file_size - 1:
          next_text_block = my_blob_client.download_blob(offset=offset, length=MAX_LINE_SIZE)
          line = next_text_block.split('\n')[0]
          offset = len(line) + 1
      
          # Do something with your line..
      

      希望对您有所帮助。这里明显的权衡是网络开销,每次调用一行文本并不快,但它达到了你逐行阅读的要求。

      【讨论】:

        猜你喜欢
        • 2019-07-29
        • 2019-09-21
        • 2021-08-26
        • 2012-06-16
        • 1970-01-01
        • 1970-01-01
        • 2021-02-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多