Pull to refresh

Comments 32

Данный выбор обусловлен «традициями компании» — у других сотрудников был опыт работ OpenXML и, когда я разрабатывал данное решение, то знал, что в случае возникновения вопросов могу обратиться к старшим товарищам. Да и в целом, мне показалось логичным использовать нативное решение от Microsoft.

Что это? Сборка xml через string builder?


А если у вас в строке будет кавычка или символ >, что будет в итоге?

Да, все верно, именно через StringBuilder собирается xml. Если нам необходимо вставить угольные скобки, то вставляем их как любой другой символ, если нам нужно вставить кавычки, то просто экранируем их.
Однако, как таковой проблемы нет, так как мы заведомо знаем где и какие теги будут вставлены (мы же их сами в коде и расставляем).
Если есть сомнения, можете попробовать скачать код с репозитория и попробовать потестить у себя. Если вдруг заметите неадекватное поведение программы, буду рад комментариям.

sb.Append($"<sheet name=\"{sheetName}\">");


Вот здесь например, если имя листа будет что-то типа "My parent's accounting", то ваша xml будет невалидна


Я почему-то думал, xml правильно собирать через XmlDocument, XDocument или сериализуя класс (я предпочитаю использовать 1 и 3 варианты, зависит от задачи)

Сейчас перепроверил — все успешно собирается. Прилагаю скрин:


На счет предложенных Вами вариантов сборки xml я ничего возразить не могу. Они вполне могли бы использоваться. Просто в данном случае, мне показалось ограничиться StringBuilder'ом логичным решением в силу его компактности и полного удовлетворения имеющихся потребностей в рамках решения конкретной задачи. Конечно, если бы использовались более разнообразные теги с большим количеством атрибутов, логичным было бы подключение дополнительных библиотек.

Собирается-собирается, но потом ни один парсер такое не откроет

Почему? Аналогичное решение, в настоящий момент, используется на внутреннем продукте компании (как раз парсер) и пока, тьфу-тьфу-тьфу, все работает.
Если подскажете, с каким парсером можно поиграться и проверить работоспособность приведенного решения, то буду искренне очень признателен.

Ок. перепроверил. Условия чуть изменились — попробуйте назвать лист как "Procter&Gamble"


Вот правила:


" is replaced with &quot;
& is replaced with &amp;
< is replaced with &lt;
> is replaced with &gt;

А саму валидацию можно провести:


  • в notepad++ плагином xml tools
  • гугля "xml validate online"
  • попытавшись загрузив эту xml в c# XmlDocument.
  • в браузере открыть XML.

Вот например вполне валидный XML.


<test test1=" '>' " test2=' " '> > </test>
Вот здесь например, если имя листа будет что-то типа "My parent's accounting", то ваша xml будет невалидна

Чего это вдруг? Одинарные кавычки валидны внутри двойных и наоборот. Двойные внутри двойных или одинарные внутри одинарных нужно заменять мнемониками.

Спасибо! Это решение тоже было рассмотрено, но было найден бесплатный вариант для всех перечисленных форматов. В течении сегодняшнего дня планирую выложить пост о конвертации rtf в xml. Потом расскажу про doc и xls, а дальше про odt и ods (но с ними все довольно тривиально).

UFO just landed and posted this here

Шикарная и простая библиотека!
Но, к сожалению, у нее ограничения(
Соберусь с силами и выложу пост про конвертацию xls и doc — вот там вообще жара, конечно!
И, самое паршивое, ну очень сложно было найти решение под .Net, зато под линухом на питончике делается одной командной строкой в терминале)

Автор молодец! Технических ограничений по объему обрабатываемых документов нет? 5-7 ГБ Экселя потянет?

Спасибо, если это не сарказм) Посмотрел темы Ваших статей — видно, что вы уже давно и плотно в it! Мне вот эта статья понравилась — даже повторить захотелось)
Если по теме вопроса, то на самом деле размер файла Excel с большой долей вероятности может быть ограничен спецификацией. Так, для 32-битных систем он не может быть больше 500-700Мб, а для online-версии предельный размер файла и вовсе составляет 250Мб. То что касается 64 разрядных систем, фактически ограничения накладываются только железом. Со спецификацией можно ознакомиться здесь
Отсюда можно сделать следующие выводы:


  1. Вероятность того, что кто-то создаст файла такого огромного размера крайне мала.
  2. Есть очень высокая вероятность упереться в технические ограничения (банальная нехватка памяти). Поясню. Вся информация в документе xlsx хранится в zip-архиве, что означает, что закрытый файл размером 5-7 Гб занимает ощутимо меньше памяти на дисковом пространстве, нежели этот же файл, но загруженный и открытый в программе, особенно, если осуществляется какая-то обработка хранимой в нем информации. Думаю, тот кто в студенчестве писал какой-нибудь архиватор типа Хафмана, сейчас прекрасно может представить примерную разницу между двумя этими состояниями файлов.

В общем, я хочу сказать, что, если речь идет о таких огромных файлах, то для работы с ними необходимо иметь как минимум соответствующее железо, а программа, которая будет использовать предложенное решение должна быть скомпилирована под 64-х разрядную систему и тогда, скорее всего, файл будет обработан и сконвертирован.
Однако, не стоит упускать из виду высокую вероятность неожиданного поведения GB при работе с такими объемами файлов, а также непредсказуемого поведения операционной системы, которая может принудительно кильнуть разожравшийся процесс.
Вот принимая во внимание все перечисленное, можно сказать, что ограничений на объемы обработки документов нет, и, при наличии соответствующего железа, файл объемом 5-7 Гб (а это около 16-20 Гб оперативы на хосте) должен будет быть обработан.
Но, скажу честно, такие кейсы я сам не тестил.

Ну так о том и вопрос. Умеет ли программа обрабатывать файл по частям или надо полностью в память грузить?
Судя по методу string Convert(Stream stream) как минимум результат будет в памяти.

Функционал обработки файла по частям не реализован. Честно говоря, я, на данный момент, очень слабо себе представляю, как можно разбить xlsx на части. Если с отдельной обработкой листов еще можно что-то придумать, то с разбивкой листов по строкам — все нет так однозначно. Тем более, если задача стоит разбить документ без предварительной его загрузки в оперативную память.

В этой задаче две проблемы, связанные с чрезмерным потреблением памяти.
1. Чтение исходного файла
2. Запись результата
Что касается второй проблемы, то у вас уже в определении интерфейса IConvertable (а именно метода string Convert(Stream stream)) заложена невозможность работы с большими файлами. Разумнее возращать Stream и не пользоваться StringBuilder`ом, а писать напрямую в поток. Также данная проблема проявится не только при работе с большими файлами, но а еще и с большим количеством средних по размеру. Результат работы будет возвращен в виде большой строки, а отсюда все проблемы с LOH. Другими словами при парсинге большого количества сравнительно небольших файлов (>4KB тескта в нем), память будет стремительно утекать.
Что касается 1го пункта, то тут я с вами не соглашусь. OpenXml умеет работать с большими файлами без чрезмерного потребления памяти (как с xslx, так и c docx):
OpenXmlReader reader = OpenXmlReader.Create(doc.MainDocumentPart);
while (reader.Read())
{
if (reader.ElementType == typeof(Document))
{
}
}
Да сложнее с таким подходом работать, но зато не жрет память.

Спасибо!
Нужно будет внимательно ее изучить.

Спасибо! Я, честно говоря, о таком подходе даже не задумывался.

Спасибо за ответ. Да, это не сарказм, это реалии 2009-2010 года.
Как вы видите в процитированной вами моей статье, сидим мы тут на Music XML 2.0 и плотно занимаемся и другими XML, не связанными с музыкальной промышленностью.
Опять же, процитированную вами спецификацию Excel для Office 365, Excel 2019, Excel 2016, Excel 2013 писали люди далекие от реалии наших IT.
Excel — самая что ни на есть отечественная база данных, которую сейчас используют минимум 50 миллионов пользователей по всей стране. Более того, о чем не пишут,
но надо упомянуть из уважения к ресурсу, есть верхний предел числа ошибок в формулах,
после которого его открыть фактически нельзя никакими стандартными средствами.
Более того, это число — степень двойки — 2^12 = 4096 ошибок. )

Вот поэтому мой вопрос немного глубже. Есть ли гарантия, что все используемые вами
библиотеки под Windows 7 или 10 потянут промышленные объемы данных, нет
ли импортов библиотек из серии .Net for MS Office 2010-2013 или С# для этих же целей,
версии патчей MS XML Parser 6 или 4.

Я понимаю, что для ваших целей может быть ограничения не достигнуты, но широким массам будет приятно осознавать, что купленные мощности есть куда девать.

128GB на рабочей станции — это уже реалии нашего дня, может быть 2-3 следующих лет.
Почему это так — тоже есть в моей статье. Жду ответа.

Очень интересная информация на счет предела в количестве ошибок — я, честно говоря, даже не знал, что такие есть. И то, что такое количество пользователей у Excel я как-то тоже не задумывался)
На счет дополнительно установленных пакетов — их нет. Использую только OpenXML и все.
Мне вот тоже сейчас стало интересно, а какой максимальный размер файла удастся обработать, но у меня сейчас под рукой только ноут с 16 Гб оперативы.
Кстати, на счет обработки огромных файлов xlsx со сложным содержимым, возможно, имеет смысл как раз использовать Interop, так как файл в таком случае будет открываться и обрабатываться непосредственно в среде Excel, что, теоретически, поможет избежать каких-нибудь не очевидных ошибок.

Статья правильная. 2 года назад решал похожую задачу через OpenXml.

Вероятность того, что кто-то создаст файла такого огромного размера крайне мала.


Увы, вывод неправильный. Мой сценарий был очень простой. Многостраничный опросник по степени удовлетворенности сотрудников в компании численностью 32 000 человек, под 100 вопросов. Вывод в эксельку.

Есть очень высокая вероятность упереться в технические ограничения


Так и было. Погуглил и нашел, как стримить zip. Все ограничения пропали.

Не очень удачные названия методов.


  1. XxxxProcess() — должен быть ProcessXxxxx()
  2. XxxParagraph(), Table() — это названия классов/конструкторов, а не методов. Где глагол?
По работе часто приходится обрабатывать файлы XLSX.
В последнее время довелось работать с огромными таблицами (порядка 200 столбцов на несколько тысяч строк), и если открывать их только на чтение, то все нормально, но вот запись файла могла происходить несколько минут.
Начал пилить свой велосипед на Python, но к сожалению (или к счастью), дело не зашло далеко (обошелся другими хаками вроде уменьшения таблиц, где это возможно):
github.com/ChronoMonochrome/xlsxutil
С doc, docx, xls, xlsx умеет работать эта библиотека. Зависимостей не требует. Кросплатформенна с некоторыми ограничениями.

Как раз про опыт ее использования планирую рассказать в следующей статье. Действительно, хорошая, еще и кросплатформенная, библиотека, но со своими приколами)

Sign up to leave a comment.

Articles