首页 > 解决方案 > 我可以同时在 Azure 存储中创建和保存文件吗?

问题描述

我正在尝试创建 CSV 文件并将其导入 Azure 存储帐户。

public static void ExportCsvToStorageAccount(string fileName, CloudBlobContainer container, IEnumerable<ReportRow> reportEntries)
{
    using (var ms = new MemoryStream())
    {
        using (var file = new StreamWriter(ms))
        {
            file.WriteLine("Date,StoreId,ItemId,SalesQuantity");

            foreach (var row in reportEntries)
            {
                var line = $"\"{row.Date}\",\"{row.StoreId}\",\"{row.ItemId}\",\"{row.SalesQuantity}\"";
                file.WriteLine(line);
            }

            var blockBlob = container.GetBlockBlobReference($"{fileName}.csv");
            ms.Position = 0;
            blockBlob.UploadFromStream(ms);
        }
    }
}

我在内存中创建文件,然后将其复制并上传到天蓝色。

我的“问题”是为此我需要首先将整个文件保存在内存中,然后才开始复制(如果文件太大并且机器内存不足,这可能是一个问题)。

理想情况下,我可以直接写入 azure,或者一旦我填满内存流缓冲区,我就会将其复制到 azure,然后在其顶部再次写入,而不是在我的内存流缓冲区中分配更多空间。

有没有办法直接写入 Azure?(目标是节省内存)

编辑:

通过 Gaurav Mantri-AIS 输入的答案,我想出了这个(因为我有超过 50000 个条目,这是块的限制),

public static void ExportCSVToStorageAccount(string fileName, CloudBlobContainer container, IEnumerable<RawReportRow> reportEntries)
{
    var blob = container.GetAppendBlobReference($"{fileName}.csv");
    blob.CreateOrReplace();

    blob.AppendText($"Date,StoreId,ItemId,SalesQuantity{Environment.NewLine}");
    foreach (var row in reportEntries)
    {
        var line = $"\"{row.Date}\",\"{row.StoreId}\",\"{row.ItemId}\",\"{row.SalesQuantity}\"{Environment.NewLine}";
        blob.AppendText(line);
    }
}

这个解决方案的问题是它需要的时间太长,从 5 分钟到一个多小时。我可能做错了什么,因为 AppendBlob 应该执行良好的附加,但似乎并非如此。

关于如何提高写入速度的任何想法?

标签: c#streamazure-blob-storage

解决方案


这样做当然是可能的。一种解决方案是使用StringBuilder并继续向其中添加数据。添加完所有数据后,创建一个字节数组,然后从中创建一个内存流并上传该内存流。

这是示例代码(虽然未经测试):

    public static void ExportCsvToStorageAccount(string fileName, CloudBlobContainer container, IEnumerable<ReportRow> reportEntries)
    {
        using (var ms = new MemoryStream())
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("Date,StoreId,ItemId,SalesQuantity");
            foreach (var row in reportEntries)
            {
                var line = $"\"{row.Date}\",\"{row.StoreId}\",\"{row.ItemId}\",\"{row.SalesQuantity}\"";
                sb.AppendLine(line);
            }
            var buffer = Encoding.UTF8.GetBytes(sb.ToString());
            ms.Write(buffer, 0, buffer.Length);
            var blockBlob = container.GetBlockBlobReference($"{fileName}.csv");
            ms.Position = 0;
            blockBlob.UploadFromStream(ms);
        }
    }

更新

假设您使用的是 SDK 版本 9.3.3,您可以使用UploadText方法并将字符串直接上传到 Azure 存储。就像是:

    public static void ExportCsvToStorageAccount(string fileName, CloudBlobContainer container, IEnumerable<string> reportEntries)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("Date,StoreId,ItemId,SalesQuantity");
        foreach (var row in reportEntries)
        {
            var line = $"\"{row.Date}\",\"{row.StoreId}\",\"{row.ItemId}\",\"{row.SalesQuantity}\"";
            sb.AppendLine(line);
        }
        var blockBlob = container.GetBlockBlobReference($"{fileName}.csv");
        blockBlob.UploadText(sb.ToString());
    }

更新 2

另一种选择是将每一行作为单独的块上传,然后最终提交块列表。但是请记住,一个 blob 中只能有 50000 个块,如果您的数据中有超过 50000 条记录,此方法将失败。为了规避这个限制,您可能希望合并某些记录并将它们保存为一个块。

这是示例代码:

    public static void ExportCsvToStorageAccount(string fileName, CloudBlobContainer container, IEnumerable<string> reportEntries)
    {
        List<string> blockIds = new List<string>();
        CloudBlockBlob blob = container.GetBlockBlobReference(fileName);
        int counter = 0;
        foreach (var row in reportEntries)
        {
            var line = $"\"{row.Date}\",\"{row.StoreId}\",\"{row.ItemId}\",\"{row.SalesQuantity}\"";
            var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(counter.ToString("d6")));
            blob.PutBlock(blockId, new MemoryStream(Encoding.UTF8.GetBytes(line)), string.Empty);
            blockIds.Add(blockId);
            counter++;
        }
        blob.PutBlockList(blockIds);
    }

推荐阅读