Чтение / импорт существующего файла Excel программно (ячейка за ячейкой) в Windows Phone 8


Я работаю над приложением 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.

2 3

2 ответа:

Я использовал следующий метод для чтения ячеек из файла xlsx Excel в Windows Phone 8:

  1. Добавьте библиотеку сжатия Microsoft в свой проект с помощью NuGet
  2. адаптируйте пример кода из developer network к вашим потребностям - он показывает, как читать ячейки из файла Excel (и для этого требуется сжатие 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, имеющая заголовок в качестве ключа и данные в качестве значения. Пустых камер там не будет.

Надеюсь, что это получает Вы начали.

К сожалению, невозможно использовать официальный OpenXML SDK от Microsoft. Причина именно в том исключении, с которым вы уже столкнулись. WP8 не имеет пространства имен System.IO.Packaging, которое требуется для извлечения / сжатия формата файлов xlsx на основе zip. Добавление WindowsBase.dll также не будет работать, потому что она не компилируется для WP8.

После гугла в течение довольно долгого времени в течение последних двух лет об этом единственные 3 решения, которые я знаю (несмотря на разработку Excel поддержка с нуля своими силами :)):

  1. Используйте Ag.OpenXML open source проект, который вы можете найти на 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