Форум программистов, компьютерный форум, киберфорум
C++/CLI Windows Forms
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/8: Рейтинг темы: голосов - 8, средняя оценка - 4.75
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
1

Распаковка zip архива на примере файла формата OpenXML

11.12.2015, 17:46. Показов 1492. Ответов 1
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте.

Пытаюсь распаковать файл .xlsx для дальнейшей работы с содержимым. Но не понимаю, как обратиться к конкретным файлам внутри этого архива.

Вначале подключаю файлы директивами:
C++
1
2
3
#using "System.dll"
#using "WindowsBase.dll"
#using "System.xml.dll"
Адресное пространство подключаем:
C++
1
2
3
4
5
    using namespace System::IO;
    using namespace System::Text;
    using namespace System::Xml;
    using namespace System::Xml::XPath;
    using namespace System::IO::Packaging;
Ну и сам код:
C++
1
2
3
4
5
6
            Package ^pkg = Package::Open(file.xlsx, FileMode::Open, FileAccess::Read);
            PackagePartCollection ^packagePartCol = pkg->GetParts();
            PackageRelationshipCollection ^packageRelCol = pkg->GetRelationships();
 
            pkg->Close();
            delete pkg;
Я так понимаю, 1 команда распаковывает архив и все содержимое хранится по ссылке pkg?
Коллекцию частей и отношений я благополучно получаю, компилируется без проблем, а вот как получить доступ к конкретной части - не понимаю. Или как получить массив частей?
Как мне открыть, например, как текстовый файл xl\workbook.xml?

Есть примеры для шарпа и в основном по сборке архива, а как считывать из zip-файла в С++ совсем ничего не нашел.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.12.2015, 17:46
Ответы с готовыми решениями:

Распаковка .zip (DotNetZip)
Не могу программно распаковать архив, вылетают 2 разных исключения. Пользуюсь библиотекой DotNetZip...

Распаковка архива (.zip)
Нужно программно распаковать zip архив. Какие библиотеки могут это сделать ? Можно ли распаковать...

Распаковка ZIP-архива
Как с помощью bat, распаковать ZIP архив ? На одном форуме нашел for %i in (*.zip) do @(md...

Программная распаковка zip-архива
Собственно вопрос простой - КАК это реализовать?

1
0 / 0 / 0
Регистрация: 05.11.2015
Сообщений: 33
14.12.2015, 19:57  [ТС] 2
Удалось разобраться как читать файлы xlsx, распаковывая их и считывая текстовые данные. Код приведу тут, наверняка пригодится. В моем примере меня интересовали лишь текстовые строки из ячеек и числа, так что все остальные типы данных ячеек (дата, булев тип, формула) просто игнорируются. И все данные запихиваются в массив строк. Для парсинга строк использовались регулярные выражения (using namespace System::Text::RegularExpressions).

C++
1
2
3
4
5
6
7
8
9
#using "System.dll"
#using "WindowsBase.dll"
#using "System.xml.dll"
 
    using namespace System::Text;
    using namespace System::Text::RegularExpressions;
    using namespace System::Xml;
    using namespace System::Xml::XPath;
    using namespace System::IO::Packaging;
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
            Package ^pkg = Package::Open(xlsx_file_name, FileMode::Open, FileAccess::Read); //  распаковываем архив
            PackagePartCollection ^packagePartCol = pkg->GetParts();                    //  получаем ссылки на все части архива
            array<String ^> ^sharedstrings = gcnew array<String ^>(1000);               //  массив для хранения набора текстовых строк из файла /xl/sharedStrings.xml
            array<String ^> ^sheets = gcnew array<String ^>(5) {"/xl/worksheets/sheet1.xml", 
                "/xl/worksheets/sheet2.xml", "/xl/worksheets/sheet3.xml", 
                "/xl/worksheets/sheet4.xml", "/xl/worksheets/sheet5.xml"};                                 // обрабатываем 5 вкладок файла xlsx
            array <System::String ^, 3> ^xls_data = gcnew array <System::String ^, 3>(5, 30, 50);  //     сохраняем содержимое xlsx файла в 3-мерный массив
                        for each (PackagePart ^pp in packagePartCol)                                //  ищем среди распакованных файлов нужный (со строками)
                if (pp->Uri->OriginalString == L"/xl/sharedStrings.xml")
                {
                    Stream ^fs = pp->GetStream();
                    array<Byte> ^by = gcnew array<Byte>(fs->Length);
                    fs->Read(by, 0, fs->Length);
                    String ^str_by = UTF8Encoding::UTF8->GetString(by);
                    int i = 0;
                    Regex ^reg = gcnew Regex("<t.*?>(?<capture>.*?)</t>");
                    for (Match ^m = reg->Match(str_by); m->Success; m = m->NextMatch())
                    {
                        sharedstrings[i] = m->Groups["capture"]->Value;
                        ++i;
                    }
                    delete(IDisposable ^) fs;
                }
            for (int sh = 0; sh<5; ++sh)                                                             //  перебор по пяти вкладкам
                for each (PackagePart ^pp in packagePartCol)
                    if (pp->Uri->OriginalString == sheets[sh])
                    {
                        Stream ^fs = pp->GetStream();
                        array<Byte> ^by = gcnew array<Byte>(fs->Length);
                        fs->Read(by, 0, fs->Length);
                        String ^str_by = UTF8Encoding::UTF8->GetString(by);
                        Regex ^reg = gcnew Regex("<row.+?r="(?<row>[0-9]+?)".*?>(?<cells>.*?)</row>");
                        for (Match ^m = reg->Match(str_by); m->Success && Int32::Parse(m->Groups["row"]->Value)<30; m = m->NextMatch())                                      //   находим строки
                        {
                            int row = Int32::Parse(m->Groups["row"]->Value);
                            int col = 0;
                            String ^cells = m->Groups["cells"]->Value;
                            String ^cell_pattern =  "<c.+?r="(?<index>[A-Z]+?[0-9]+?)".*?";     //  ищем индекс ячейки |<c r="D3" ...|
                            cell_pattern +=         "(((t="(?<type>[a-zA-z]+?)")?>";                //  ищем тип ячейки, если он есть  |t="s">| (см. Open Xml Standart, часть 1, глава 18.18.11)
                            cell_pattern +=         "((<v.*?>(?<digit>[0-9]+?)</v>)|";              //  ищем номер значения из sharedstrings, если оно есть |<v>30</v>| или
                            cell_pattern +=         "(<is.*?><t.*?>(?<inlinestr>.*?)</t></is>))";   //  или считываем его отсюда |<is><t>inline_string</t></is>|
                            cell_pattern +=         "</c>)|(/>))";                                  //  проверяем, а было ли что-то в ячейке <c ...>...</c> или она пустая <c .../>
                            Regex ^reg_c = gcnew Regex(cell_pattern);
                            for (Match ^mm = reg_c->Match(cells); mm->Success && col<50; mm = mm->NextMatch())                                     //      обрабатываем все ячейки из строки
                            {
                                String ^cell_index = mm->Groups["index"]->Value;
                                if (mm->Groups["type"]->Value == "s")
                                    xls_data[sh, row-1, col] = sharedstrings[Int32::Parse(mm->Groups["digit"]->Value)];                    //     записываем значение в 3-мерный массив строк: sh - номер вкладки, row - номер строки, col - номер столбца
                                else if (mm->Groups["type"]->Value == "b")
                                    xls_data[sh, row-1, col] = "Boolean type of cell in XLSX file";
                                else if (mm->Groups["type"]->Value == "d")
                                    xls_data[sh, row-1, col] = "Date format of cell";
                                else if (mm->Groups["type"]->Value == "e")
                                    xls_data[sh, row-1, col] = "Error cell in XLSX file";
                                else if (mm->Groups["type"]->Value == "n")
                                    xls_data[sh, row-1, col] = mm->Groups["digit"]->Value;
                                else if (mm->Groups["type"]->Value == "str")
                                    xls_data[sh, row-1, col] = "Cell contain formula string";
                                else if (mm->Groups["type"]->Value == "inlineStr")
                                    xls_data[sh, row-1, col] = mm->Groups["inlinestr"]->Value;
                                else if (mm->Groups["type"]->Value == "" && mm->Groups["digit"]->Value != "")
                                    xls_data[sh, row-1, col] = mm->Groups["digit"]->Value;
                                else xls_data[sh, row-1, col] = "Undefined value (out of table)";
                                ++col;
                            }
                        }
                    delete(IDisposable ^) fs;
                    }
            pkg->Close();
            delete pkg;
0
14.12.2015, 19:57
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.12.2015, 19:57
Помогаю со студенческими работами здесь

Распаковка zip-архива средствами С++
Помогите считать из zip-архива файлы в кодировке Unicode (UTF-8). Долго копался в ресурсах на эту...

Распаковка архива посредством 7-Zip
Снова здарова всем. Но у меня есть вопрос: нужно что бы при запуске батника, он распаковал архив....

Распаковка запароленного ZIP-архива
Всем привет,недавно появилась нужда распаковать запароленный .zip архив ,скажем,на рабочий стол...

Распаковка многотомного zip архива
Приветствую всех! Появилась задача распаковки многотомного архива средствами Delphi. Использую...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru