在Windows Phone 8中以编程方式逐单元格读取/导入现有的Excel文件

3
我正在开发一个Windows Phone 8应用程序,用于读/写Excel文件。我在这里提出了一个问题,评论中提供的信息和许多其他链接引导我使用OpenXml
所有这些都让我知道如何创建一个Excel文件以及如何启动它。但是现在我卡在了最基本的地方,即如何逐个单元格地读取现有的Excel文件(可能是在MS Excel之外创建的),即我想通过我的代码访问每个单元格及其值。在openXML中,我做到了这一点:
Stream localFile = App.GetResourceStream(new Uri("/ReadExcel;component/jai.xlsx"
                                                    ,UriKind.Relative)).Stream;
MemoryStream ms = new MemoryStream();
localFile.CopyTo(ms);

DocumentFormat.OpenXml.Packaging.SpreadsheetDocument spreadsheetDoc =
DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(localFile, true);
{
    var a = spreadsheetDoc.Package;
    // Do work here
}

但是它给我报错了:
The type 'System.IO.Packaging.Package' is defined in an assembly that is not 
referenced. You must add a reference to assembly 'WindowsBase, Version=4.0.0.0

基本上我卡在了WindowsBase.dll这里。我尝试了各种导入程序集的方式,例如解除锁定等,但都没有用。

所以我的目的就是在我的代码中逐个单元格地以编程方式访问现有Excel文件的内容。

请帮忙或建议是否可以在WP8中实现。


根据异常信息,您只需要添加对WindowsBase程序集的引用。您尝试过添加此引用并将“复制本地”设置为true吗? - termit
2个回答

1
我使用以下方法在Windows Phone 8上从xlsx Excel文件中读取单元格:
  1. 使用NuGet将Microsoft Compression library添加到您的项目中
  2. 根据您的需求调整来自developer network的代码示例 - 它展示了如何从Excel文件中读取单元格(需要Compression lib)
由于我已经稍微扩展了代码以正确处理空列空文件,因此您也可以使用我的代码:
public class ExcelReader
{
    List<string> _sharedStrings;

    List<Dictionary<string, string>> _derivedData;

    public List<Dictionary<string, string>> DerivedData
    {
        get
        {
            return _derivedData;
        }
    }
    List<string> _header;

    public List<string> Headers { get { return _header; } }

    // e.g. cellID = H2 - only works with up to 26 cells
    private int GetColumnIndex(string cellID)
    {
        return cellID[0] - 'A';
    }

    public void StartReadFile(Stream input)
    {
        ZipArchive z = new ZipArchive(input, ZipArchiveMode.Read);
        var worksheet = z.GetEntry("xl/worksheets/sheet1.xml");
        var sharedString = z.GetEntry("xl/sharedStrings.xml");

        // get shared string
        _sharedStrings = new List<string>();
        // if there is no content the sharedStrings will be null
        if (sharedString != null)
        {
            using (var sr = sharedString.Open())
            {
                XDocument xdoc = XDocument.Load(sr);
                _sharedStrings =
                    (
                    from e in xdoc.Root.Elements()
                    select e.Elements().First().Value
                    ).ToList();
            }
        }

        // get header
        using (var sr = worksheet.Open())
        {
            XDocument xdoc = XDocument.Load(sr);
            // get element to first sheet data
            XNamespace xmlns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
            XElement sheetData = xdoc.Root.Element(xmlns + "sheetData");

            _header = new List<string>();
            _derivedData = new List<Dictionary<string, string>>();

            // worksheet empty?
            if (!sheetData.Elements().Any())
                return;
            // build header first
            var firstRow = sheetData.Elements().First();
            // full of c
            foreach (var c in firstRow.Elements())
            {
                // the c element, if have attribute t, will need to consult sharedStrings
                string val = c.Elements().First().Value;
                if (c.Attribute("t") != null)
                {
                    _header.Add(_sharedStrings[Convert.ToInt32(val)]);
                } else
                {
                    _header.Add(val);
                }

            }

            // build content now
            foreach (var row in sheetData.Elements())
            {
                // skip row 1
                if (row.Attribute("r").Value == "1")
                    continue;
                Dictionary<string, string> rowData = new Dictionary<string, string>();
                // the "c" elements each represent a column
                foreach (var c in row.Elements())
                {
                    var cellID = c.Attribute("r").Value; // e.g. H2

                    // each "c" element has a "v" element representing the value
                    string val = c.Elements().First().Value;
                    // a string? look up in shared string file
                    if (c.Attribute("t") != null)
                    {
                        rowData.Add(_header[GetColumnIndex(cellID)], _sharedStrings[Convert.ToInt32(val)]);
                    } else
                    {
                        // number
                        rowData.Add(_header[GetColumnIndex(cellID)], val);
                    }
                }
                _derivedData.Add(rowData);
            }
        }
    }
}

这适用于只有一个工作表和一些文本和数字单元格的简单Excel文件。它假设存在标题行。
使用方法如下:
var excelReader = new ExcelReader();
excelReader.StartReadFile(excelStream);

阅读后,excelReader.Headers中包含标题名称,excelReader.DerivedData中包含行。每一行都是一个Dictionary,其中标题为键,数据为值。空单元格不会出现在其中。
希望这可以帮助你入门。

1
谢谢 Heinrich。但是对我来说已经太晚了,我已经找到了解决方案。无论如何,我会点赞/接受的。谢谢! - Jaihind

1
很遗憾,无法使用微软官方的OpenXML SDK。原因就是您已经遇到的异常。WP8没有可用的System.IO.Packaging命名空间,这是提取/压缩基于zip的xlsx文件格式所必需的。添加WindowsBase.dll也不起作用,因为它未针对WP8编译。
在过去的两年中,通过谷歌搜索,我知道的仅有三个解决方案(除了自己从零开始开发Excel支持 :))。
  1. 使用Ag.OpenXML开源项目,你可以在http://agopenxml.codeplex.com/找到它。源代码库包含一个实现来写Excel文件(可下载的软件包仅包含Word导出)。我在我的WP8应用程序中使用了它相当长一段时间,尽管缺少很多功能,但它工作得很好。不幸的是,这个软件包自2011年以来就没有再维护过了。但是,这可能是一个很好的起点。

  2. 使用ComponentOne商业库https://www.componentone.com/SuperProducts/StudioWindowsPhone/

  3. 使用Syncfusion商业库http://www.syncfusion.com/products/windows-phone


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