65.9K
CodeProject 正在变化。 阅读更多。
Home

利用 Azure Blob 和 WebJob 将 Excel 文件转换为平面文件格式

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2020 年 2 月 24 日

CPOL

4分钟阅读

viewsIcon

12770

downloadIcon

140

如何在不将 Excel 文件存储在本地硬盘驱动器上的情况下, 将 Excel 文件转换为逗号分隔的文件

引言

我相信已经有很多文章或博客展示了如何使用 C# 将 Excel 文件转换为逗号分隔文件,并且在所有情况下(我参考的),Excel 都是从本地机器的硬盘驱动器读取的,CSV 文件保存回同一个硬盘驱动器。但即便如此,我还是要再写一篇帖子。

想知道为什么吗?

嗯,这篇文章在读取和保存文件的方式上会略有不同。以下是这篇文章的主要内容

  • 如果我们要转换很多 Excel 文件,但磁盘空间不足以保存所有这些文件怎么办?转换输出也是如此。
  • 如果我们没有权限将转换后的文件保存到本地机器上怎么办?
  • 我们如何使用 WebJobs 运行这个转换实用程序?

为了解决上述挑战,我们可以利用 Azure 的功能,即我们将在运行时完成所有操作,而无需使用磁盘空间作为文件的存储。 让我们一步一步地看看所有这些操作。

问题陈述

从 Azure Blob 存储读取 Excel 文件,将其转换为 CSV 格式,然后将其上传回 Azure Blob 存储。 整个过程必须通过触发的 WebJob 运行,以便在需要 Excel 到 CSV 转换时重复执行。

设置环境

我正在使用 Visual Studio 2019 v16.4.0,并且拥有有效的 Azure 订阅。

高级任务

以下是我们将要执行的高级任务列表

  • 在 Azure 存储中创建容器
  • 从 Azure 存储读取 Excel
  • 将 Excel 转换为 CSV 格式
  • 将 CSV 上传到 Azure 存储
  • 创建 Azure WebJob
  • 触发 Azure WebJob

在 Azure 存储中创建容器

必须在 Blob 服务下创建一个容器,用于存储所有需要转换为 CSV 格式的 Excel 文件。 现在有两种方法可以创建容器 - 一种是通过 Azure 门户,另一种是使用 C#。 由于这两种方法都可以在 MSDN 上轻松找到,因此我不会重复整个过程。 有关如何创建容器的详细步骤,请参阅参考部分

对于我们的练习,我在一个存储帐户下创建了两个名为 excelcontainercsvcontainer 的容器,其中

  • excelcontainer – 保存要转换为 CSV 的 Excel 文件
  • csvcontainer – 保存转换后的 CSV 文件

以下是我的 excelcontainer 的屏幕截图,其中包含三个 Excel 工作簿

从 Azure 存储读取 Excel

现在我们已经准备好了带有上传文件的 excelcontainer,是时候从所有这些文件读取数据了,这是执行此操作的代码

public async Task<List<BlobOutput>> Download(string containerName)
        {
            var downloadedData = new List<BlobOutput>();
            try
            {
                // Create service and container client for blob
                BlobContainerClient blobContainerClient = 
                        _blobServiceClient.GetBlobContainerClient(containerName);

                // List all blobs in the container
                await foreach (BlobItem item in blobContainerClient.GetBlobsAsync())
                {
                    // Download the blob's contents and save it to a file
                    BlobClient blobClient = blobContainerClient.GetBlobClient(item.Name);
                    BlobDownloadInfo downloadedInfo = await blobClient.DownloadAsync();
                    downloadedData.Add(new BlobOutput 
                       { BlobName = item.Name, BlobContent = downloadedInfo.Content });
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return downloadedData;
        }

其中 BlobOutput 是具有以下成员的 DTO

public class BlobOutput
{        
      public string BlobName { get; set; }
      public Stream BlobContent { get; set; }
}

将 Excel 转换为 CSV 格式

在上面的步骤中,我们已经将每个 blob 对象中的数据收集到一个流中。 因此,在这一步中,我们将把流式数据转换为 CSV 格式,这是实现此目的的代码

public static List<BlobInput> Convert(List<BlobOutput> inputs)
        {
            var dataForBlobInput = new List<BlobInput>();
            try
            {
                foreach (BlobOutput item in inputs)
                {
                    using (SpreadsheetDocument document = 
                           SpreadsheetDocument.Open(item.BlobContent, false))
                    {
                        foreach (Sheet _Sheet in 
                                 document.WorkbookPart.Workbook.Descendants<Sheet>())
                        {
                            WorksheetPart _WorksheetPart = 
                               (WorksheetPart)document.WorkbookPart.GetPartById(_Sheet.Id);
                            Worksheet _Worksheet = _WorksheetPart.Worksheet;

                            SharedStringTablePart _SharedStringTablePart = 
                                     document.WorkbookPart.GetPartsOfType
                                               <SharedStringTablePart>().First();
                            SharedStringItem[] _SharedStringItem = 
                                     _SharedStringTablePart.SharedStringTable.Elements
                                               <SharedStringItem>().ToArray();

                            StringBuilder stringBuilder = new StringBuilder();
                            foreach (var row in _Worksheet.Descendants<Row>())
                            {
                                foreach (Cell _Cell in row)
                                {
                                    string Value = string.Empty;
                                    if (_Cell.CellValue != null)
                                    {
                                        if (_Cell.DataType != null && 
                                            _Cell.DataType.Value == CellValues.SharedString)
                                            Value = _SharedStringItem[int.Parse
                                                    (_Cell.CellValue.Text)].InnerText;
                                        else
                                            Value = _Cell.CellValue.Text;
                                    }
                                    stringBuilder.Append(string.Format("{0},", Value.Trim()));
                                }
                                stringBuilder.Append("\n");
                            }

                            byte[] data = Encoding.UTF8.GetBytes
                                               (stringBuilder.ToString().Trim());
                            string fileNameWithoutExtn = item.BlobName.ToString().Substring
                                             (0, item.BlobName.ToString().IndexOf("."));
                            string newFilename = $"{fileNameWithoutExtn}_{_Sheet.Name}.csv";
                            dataForBlobInput.Add(new BlobInput { BlobName = newFilename, 
                                                                 BlobContent = data });
                        }
                    }
                }
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
            return dataForBlobInput;
        }   

其中 BlobInput 是具有以下成员的 DTO

public class BlobInput
 {
        public string BlobName { get; set; }
        public byte[] BlobContent { get; set; }
 }

如果一个工作簿包含多个工作表,那么将为每个工作表创建一个单独的 CSV 文件,文件名格式为 <ExcelFileName>_<SheetName>. csv。

将 CSV 上传到 Azure 存储

一旦数据被转换为 CSV,我们就可以将 CSV 文件上传回容器了,这是执行此操作的代码

public async Task Upload(string containerName, List<BlobInput> inputs)
        {
            try
            {
                // Create service and container client for blob
                BlobContainerClient blobContainerClient = 
                         _blobServiceClient.GetBlobContainerClient(containerName);

                foreach (BlobInput item in inputs)
                {
                    // Get a reference to a blob and upload
                    BlobClient blobClient = 
                        blobContainerClient.GetBlobClient(item.BlobName.ToString());

                    using(var ms=new MemoryStream(item.BlobContent))
                    {
                        await blobClient.UploadAsync(ms, overwrite: true);
                    }                    
                }                
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

到目前为止,我们已经从容器读取了 Excel 文件,将其转换为 CSV 格式,并将其上传回另一个容器。 一切都很好。 下一个任务是使用触发的 WebJob 自动化这个过程。

创建 Azure WebJob

可以通过右键单击项目并选择 发布…来使用 Visual Studio 创建 WebJob

除此之外,还有很多方法可以创建触发的 WebJob,所有方法都在 MSDN 上的此处提到。

触发 Azure WebJob

如果一切设置正确,您将能够在您的 Azure 门户上看到以下屏幕

由于这是触发的 WebJob,点击 运行 按钮将触发这个作业,并将创建如下所示的输出

要点

使用 Azure 存储和 WebJob,我们已经将文件从一种格式转换为另一种格式,而无需在此整个转换过程中利用本地磁盘空间来保存文件。

参考文献

历史

  • 2020 年 2 月 24 日:初始版本
© . All rights reserved.