Работа с большими файлами экселяИсточник: habrahabr
Что такое большой файл? Ну так чтобы реально большой? В бытность свою я думал, что это файлик на 50-60 тыс строк записей. И оставался я бы в таком неведении до сих пор, но пришлось выполнять один проект, в котором надо было работать с файлами на 600-800 тыс строк. Что сначала А сначала, друзья мои, ринулись мы в самое простое, что можно придумать. Interop.Excell, и все дела. Казалось. Ага, щаз. Как показали тестовые испытания, данный способ открытия приводил к тому, что за час было прочитано 200 тыс строк экселя, приложение активно потребляло оперативку, и раздвигало плечами остальные процессы на машине. Кончилось все ожидаемо, но следственный эксперимент надо было довести до конца - на 260 тысячах приложение свалилось в OutOfMemory на машине с 4 Гб. Стало понятно, что в лоб решить проблему не получится Google it Сколько нам открытий чудных… Гугль привел, как ни странно, в msdn, где я познакомился с двумя методами открытия очень больших файлов: DOM и SAX. Уж за давностью времен не вспомню, но какой то из них отвалился по причине опостылевшей уже на тот момент OutOfMemory, а второй был совершенно неюзабелен в плане доступа к данным. Почему - читаем ниже. Из чего же, из чего же Сделаны наши эксельки. Ни для кого, кто решил копнуть формат чуть глубже, не станет секретом, что в отличие от бинарным xls, xlsx - по сути zip архив с данными. Достаточно поменять расширение ручками и распаковать архив в папку - и мы получим всю внутреннюю структуру документа, что есть не что иное, как набор xml файлов и сопутствующей информации. Как оказалось, в корневом xml нет текстовых данных. Вместо этого мы имеем набор индексов, которые ссылаются на вспомогательный файл, в котором представлены пары "ключ/значение" Одним из вышеприведенных способов открыть то файл можно, но при этом нужно копаться в сопутствующих файлах и вытаскивать из них текстовые значения. Мрак. И отступила тьма После долгих мытарств и стенаний родилось следующее: Наши любимые юзинги, которые некоторые личности забывают указывать: using System.Collections.Generic; using System.Data; using System.Data.OleDb; using System.IO; using System.Linq; using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; * This source code was highlighted with Source Code Highlighter. Собственно, сам код: public delegate void _DataLoaded(List<string> data); public delegate void _NewProcent(int col); public static _DataLoaded DataLoaded; public static _NewProcent NewProcent; public static MessageHave MessageHave_Event; public static void ReadData(object data) { //Приводим объект с переданной парой "имя файла"-"выбранный лист экселя" var keyValuePair = (KeyValuePair<string, string>)data; using (var cnn = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + keyValuePair.Key + @";Extended Properties=""Excel 12.0;HDR=No;IMEX=1""") ) { int calc = 1000; MessageHave_Event("Открытие соединения провайдера"); cnn.Open(); try { var cmd = new OleDbCommand(String.Format("select * from [{0}]", keyValuePair.Value), cnn); using (OleDbDataReader dr = cmd.ExecuteReader()) { var lines = new List<string>(); int id = 0; if (dr != null) while (dr.Read()) { string text = ""; for (int i = 0; i < dr.FieldCount; ++i) { if (dr[i] != null) text += dr[i] + "^";//добавляем разделитель между ячейками else text += "^"; } lines.Add(text); id++; if (id == calc) { NewProcent(id); calc += 1000; } } DataLoaded(lines); } cnn.Close(); } catch (Exception ex) { MessageHave_Event("Exception: " + ex.Message); cnn.Close(); } } } * This source code was highlighted with Source Code Highlighter. Код показал производительность порядка 15-20 минут на файлах в 600-800 тыс строк записей. |