8

我正在尝试编写一个 C# Azure 函数来使用 OpenXml-SDK 下载和打开一个 excel 文件。

Office 互操作在此处不起作用,因为 Office 不适用于 Azure 函数。

我正在尝试使用 OpenXml-SDK 打开和读取文件,该文件似乎需要保存文件的路径,而不是从远程 url 下载的 url 或流。

鉴于我不知道在 Azure Functions 中临时存储 excel 文件的方法,我使用了 Azure 文件存储。

我将 url 中的 excel 文件上传到 Azure 文件存储,但是我无法使用 OpenXML-SDK 打开 excel 文件。

我测试了 Azure 文件存储中的 excel 文件是否正常工作,但是,当我尝试从 MemoryStream 打开 OpenXML.SpreadsheetDocument 时,我收到错误消息,表明文件已损坏。

如果我尝试打开 SpreadsheetDocument 传递文件 Uri ( https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-how-to-use-files#develop-with-file-storage )然后地址超过 260 个字符的限制。

我愿意使用 OpenXML 以外的库,理想情况下我宁愿不必存储 excel 文件。

4

2 回答 2

7

Open XML SDK 在 Azure Function 中运行良好。我在我身边测试了它。这是完整的代码。

#r "DocumentFormat.OpenXml.dll"
#r "WindowsBase.dll"

using System.Net;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");

    WebClient client = new WebClient();

    byte[] buffer = client.DownloadData("http://amor-webapp-test.azurewebsites.net/Content/hello.xlsx");
    MemoryStream stream = new MemoryStream();
    stream.Write(buffer, 0, buffer.Length);
    stream.Position = 0;
    using (SpreadsheetDocument doc = SpreadsheetDocument.Open(stream, false))
    {
        WorkbookPart workbookPart = doc.WorkbookPart;
        SharedStringTablePart sstpart = workbookPart.GetPartsOfType<SharedStringTablePart>().First();
        SharedStringTable sst = sstpart.SharedStringTable;

        WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
        Worksheet sheet = worksheetPart.Worksheet;

        var cells = sheet.Descendants<Cell>();
        var rows = sheet.Descendants<Row>();

        log.Info(string.Format("Row count = {0}", rows.LongCount()));
        log.Info(string.Format("Cell count = {0}", cells.LongCount()));

        // One way: go through each cell in the sheet
        foreach (Cell cell in cells)
        {
            if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString))
            {
                int ssid = int.Parse(cell.CellValue.Text);
                string str = sst.ChildElements[ssid].InnerText;
                log.Info(string.Format("Shared string {0}: {1}", ssid, str));
            }
            else if (cell.CellValue != null)
            {
                log.Info(string.Format("Cell contents: {0}", cell.CellValue.Text));
            }
        }
    }

    return req.CreateResponse(HttpStatusCode.OK, "Hello ");
}

在此处输入图像描述

要使用 Open XML,请确保您在函数文件夹下创建了 bin 文件夹,并将 DocumentFormat.OpenXml.dll 和 WindowsBase.dll 上传到其中。

“文件包含损坏的数据”。

您是否尝试过另一个 excel 文件来检查问题是否与特定的 excel 文件有关。我建议您创建一个新的简单 excel 来再次测试您的代码。

“它不适用于我的文件,并显示相同的“文件包含损坏的数据”消息。“

我下载了您的 excel 文件,发现它是旧版本(.xls)的 excel 文件。

要修复异常,您可以将 excel 转换为最新版本 (.xlsx) 或选择另一个 excel 解析库。ExcelDataReader可以适用于任何版本的 excel 文件。您可以通过搜索“ExcelDataReader”使用 NuGet 安装此库。以下是如何解析 .xls 格式的 excel 文件的示例代码。我在 Azure Function 上对其进行了测试,它确实运行良好。

#r "Excel.dll"
#r "System.Data"

using System.Net;
using System.IO;
using Excel;
using System.Data;

public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");

    WebClient client = new WebClient();

    byte[] buffer = client.DownloadData("http://amor-webapp-test.azurewebsites.net/Content/abcdefg.xls");
    MemoryStream stream = new MemoryStream();
    stream.Write(buffer, 0, buffer.Length);
    stream.Position = 0;

    IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);

    DataSet result = excelReader.AsDataSet();

    for (int i = 0; i < result.Tables.Count; i++)
    {
        log.Info(result.Tables[i].TableName +" has " + result.Tables[i].Rows.Count + " rows.");
    }

    return req.CreateResponse(HttpStatusCode.OK, "Hello ");
}

请在执行上层代码之前将“Excel.dll”文件添加到函数的 bin 文件夹中。

于 2017-04-05T10:25:58.040 回答
4

如果确实需要保存临时文件,Azure Functions 有一个%TEMP%环境变量,其中包含指向临时文件夹的路径。这是运行您的函数的虚拟机的本地文件夹,不会被持久化。

但是,无需将文件保存在本地/Azure 文件中。您应该能够从对 get 请求的响应中获取流并将其直接传递给OpenXML

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(originalExcelUrl);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream()) 
{
    var doc = SpreadsheetDocument.Open(stream, true);
    // etc
}
于 2017-04-02T22:12:29.580 回答