Обработка xlsx файлов на C++

Добрый день! Господа буду признателен вам за пассивную помощь.
В чём суть вопроса: изучаю я С++, читаю книги, смотрю видео уроки. Накопилось достаточно теоретических знаний (как мне кажется), но с практикой всё очень плохо.
Суть моего вопроса в следующем: у меня есть задание которое я хочу выполнить сам с минимальной помощью со стороны, но не знаю с какой стороны к нему подойти

Задача заключается в следующем: нужно написать консольное windows приложение которое будет получать на вход два параметра пути к входному(.xlsx) и выходному файлу(выдавать ошибку если значения не верны) и обрабатывать файл.

Как я думаю реализовывать:
0. подключаю <fstream>-для работы с файлами; <ifstream>-для входного файла <оfstream> для выходного;
1. Две строки для параметров входного файла и выходного файлов; (обработка ошибок для входного файла)
2. два объекта по одному для каждого класса ifstream /объект/ (/путь в переменной/) оfstream /объект/ (/путь в переменной/)
...

#include "stdafx.h"
#include <fstream>

using namespace std;

void checkDir (string dirIN)
    {
        //проверяем входной файл
    }

void checkOUTdir (string dirOUT)
    {
            //проверяем/создаём выходной файл
    }

 main (){
     string dirIN, dirOUT;

     cout "Входной файл:";
     getline (cin, dirIN)

     cout "Выходной файл";
     getline(cin, dirOUT);

     //Наверное дальше строки не верны, я хотел сказать что ниже по моей задумке должны идти функции работы с самими файлами
     ifstream INdir (dirIN)
     {
         //работаем с файлом
     };
     ofstream OUTdir (dirOUT)
     {
         //пишем в файл
     };
 }

Ошибка №1: кроме fstream необходимо включать заголовки iostream и string.

Ошибка №2: отсутствует тип возвращаемого значения функции main. Должно быть int main() { ... }.

Ошибка №3: cout "Входной файл:"; — отсутствует оператор вывода в поток. Должно быть так: cout << "Входной файл:";.

Ошибка №4: не хватает точки с запятой после getline (cin, dirIN).

Далее, фрагмент

     ifstream INdir (dirIN)
     {
         //работаем с файлом
     };

компилятор будет считать некорректным определением функции. (С ofstream OUTdir всё аналогично.)

Должно быть:

    ifstream INdir(dirIN);

    if (INdir)
    {
        //работаем с файлом
    };

Выражение ifstream INdir (dirIN); — это определение переменной типа входного файлового потока с инициализацией (т.е. при исполнении этого выражения будет попытка открыть файл с именем, указанным в dirIN). Затем в if проверяем был ли корректно открыт поток. Здесь используется неявное преобразование переменной типа входной файловый поток к типу bool (определено для классов потоков в STL). Если всё нормально, внутри блока работаем с потоком INdir также, как со стандартным cin.

Для полноты ощущений, в код хорошо бы добавить обработку ситуаций, когда с открытием файла что-то пошло не так. Тем более, что ты используешь два файла: входной и выходной, и при ошибке открытия входного файла, скорее всего, выходной файл открывать/создавать не имеет смысла. Обработку ошибочных ситуаций можно сделать разными способами (if-else, возбуждение и обработка исключений) и с различной логикой работы. Это уже зависит от того, как ты планируешь построить логику работы программы.

Ещё один момент. По умолчанию конструктор файлового потока открывает файл в текстовом режиме. Ты планируешь работать с бинарным файлом из Excel (или я ошибаюсь?). Следовательно нужно использовать второй параметр конструктора:

    ifstream INdir(dirIN, ios_base::in | ios_base::binary);

Для чего нужны

void checkDir (string dirIN)
    {
        //проверяем входной файл
    }

void checkOUTdir (string dirOUT)
    {
            //проверяем/создаём выходной файл
    }

на данном этапе мне не понятно. Поэтому без комментариев.

Добрый день. По факту я смог наворотить вот такой код. Он мне полностью понятен и я знаю как и что в нём работает.

    #include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <locale>

using namespace std;
void error (int);

int main(int argc, char *argv[])
{
    setlocale(LC_ALL,"Russian");
    error (argc);
    return 0;
}

void error (int i){
    if (i==1){
        cout << "Вы не ввели аргументов\n" << "Для коректной работы программы введите два аргумента\n" << "Входной и выходные файлы\n";
             } else if(i==2){
                    cout << "Вы не ввели параметры выходного файла\n ";
    }
}

Честно говоря дальше я затупил из-за переизбытка разнообразной информации. Входной файл у меня .xlsx Нагуглил что в начале этот файл нужно распаковать используя библиотеку zlib. А потом работать с распакованными данными.

Если вам будет проще понять для чего всё это опишу что в итоге программа должна на вход получать таблицу .xlsx парсить её и записывать в файл.

Отличная программа. Придраться можно только к форматированию исходного кода и включению лишних заголовков.

А вот парсить Экселовские таблицы и записывать в файл тебе, наверное, лучше на VBA из под того же Excel. Мне кажется, что с С++ ты времени потратишь гораздо больше.

Обязательно xlsx? С CSV намного проще будет работать.

selevit, CSV — это не спортивно! ))

Настоящий программист не будет связываться с текстовым форматом электронных таблиц. Тем более, что разделитель полей и десятичная точка в нём зависит от настроек локали операционной системы. Только xlsx, только хардкор!

Череп, не смог отделить сарказм от серьезных утверждений в твоем посте :)

разделитель полей и десятичная точка в нём зависит от настроек локали операционной системы

Это, кстати, автоматически детектируется большинством редакторов.

Это, кстати, автоматически детектируется большинством редакторов.

Редакторы — это хорошо. Но если парсить CSV самописной программой... Причём сгенерирован CSV может быть на компе с одними настройками локали, а парситься будет — на компе с другими настройками. Ещё, помнится, там с ограничителями строк какая-то байда была... Так что тут тоже не всё так шоколадно.

В итоге получается задача текстового парсинга с плавающими условиями. При прочих равных, лично я бы реализовывал её НЕ на С/С++. А учитывая близость Эксела и примерно одинаковый уровень владения топикмейкером С++ и VBA, логичный совет: использовать VBA и не искать себе лишнего геморроя.

CSV часто используют для импорта и экспорта данных, наряду с XML. Обычно в этом случае формат файла детерминирован.

В CSV строки экранируются специфическим образом (кавычки экранируются кавычками) и это нужно учитывать. Уверен, что уже есть много готовых реализаций парсеров.

Могу с ходу выдать пример, когда необходимо использовать парсинг CSV в C++. Например, если нам нужно быстро делать импорт 50 миллионов записей из файла в БД. Обычно такие парсеры пишутся на скриптовых языках (PHP, Perl, Python), но при большом количестве данных иногда есть смысл написать это на плюсах.

XLSX-формат в этом случае будет огромным оверхедом. Да и не видел, чтобы VBA всерьез использовался где-то кроме макросов к продуктам MS Office.

Угу... Ради интереса, почитай в статью Википедии. И не могу не процитировать:

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

О чём я и говорил.

Не думаю, что перед топикмейкером стоит задача переноса 50 млн. записей из Excel в БД )) А для десятка тысяч записей скрипт на VBA под Excel — вполне потянет.

Обычно такие парсеры пишутся на скриптовых языках (PHP, Perl, Python)

Собственно говоря, я это и имел ввиду, когда писал

При прочих равных, лично я бы реализовывал её НЕ на С/С++.

Я так понимаю, перед ТС вообще никакой конкретной задачи не стоит. Задачка-то учебная, наверно.

Я так понимаю, что ТС уже давно забил на этот топик.

Для учебной задачи парсинг xlsx, imho, солжновато.

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.