ExcelFormat Library

Эта заметка будет посвящена работе с библиотекой ExcelFormat, на которую я наткнулся некоторое время назад в поисках средств для работы с Эксель-файлами (XLS) под C++. Цель заметки – задокументировать работу с этой библиотекой и показать, насколько это легко и удобно. Например, в рамках Бюро переводов Old-Games.ru с помощью очень простых программок можно организовать workflow, который бы позволял преобразовывать xls-экспорт из СП в пачку текстовых файлов (обычно именно с ними работают утилиты для вставки текстов в игру) или же прямо в игровые файлы. В конце заметки будет приведен код, который позволяет делать первую задачу, вторая же – лишь дело техники.

Начну издалека. Поиск средства для работы с эксель-файлами был начат мной еще летом 2012-го, когда была создана система Переводчик для текстов Бюро. Первым делом на запрос “xls c++” в гугле выдается www.libxl.com, которым, естественно, и пришлось первым делом воспользоваться. С задачей составления XLS из текстовых файлов (то есть в противоположном направлении, чем в постановке вопроса выше), библиотека справилась, хоть и назойливо вставляла в получившийся эксель-файл рекламную строчку. Ее, правда, можно удалить. Так оно и продолжалось полгода, пока мне не понадобилось сделать текстовые файлы из экселя. Почему-то программа, которую я написал с помощью libxl могла обработать только порядка 100 строк – дальше вставлялись пустые строки. Пришлось промучиться час, пока я не догадался вывести сообщение об ошибке (в том, что ошибка на стороне libxl было совсем не очевидно), в котором сообщалось, что бесплатная версия ограничена по возможностям, покупайте дескать полную. Такого издевательства я не выдержал и стер libxl к чертям.

Далее последовал поиск бесплатных аналогов, которых на деле почти и не оказалось (несмотря на открытость формата!). С большим трудом был обнаружен проект на The Code Project – ExcelFormat Library. Надо сказать, что сам The Code Project меня сильно порадовал. В отличие от Google Code, на котором, за редким исключением, всё время какие-то заброшенные проекты, и неповоротливого Sourceforge с совершенно неудобной навигацией и организацией, подходящей для очень крупных проектов, здесь нас ждет, на мой взгляд, самый удобный формат – одна страница = один проект, сверху ссылки на последнюю версию и исходный код, в середине – описание и примеры использования, в конце – комментарии. Как оказывается, этого вполне достаточно для представления своего проекта и для пользования им другими. На том же Code Project была найдена библиотека для работы с sqlite (в других местах – опять пусто, либо не работает под MSVC6) – об этом я, возможно, еще расскажу в другой раз. Так что мое мнение о сайте сугубо положительно.

Но перейдем к коду. Не знаю как сейчас, но на момент моей работы с ним, документация ограничивалась тем, что написано на страничке проекта. Примеры использования, какие-то тонкости по форматированию (которые мне совершенно ни к чему), но реально нужные вещи, вроде того, как получить строчку из ячейки – отсутствуют. Немногим лучше обстоит дело с примерами внутри архива исходников, но там тоже маловато. Поэтому приведу здесь код вышеупомянутой программы, которая разбивает XLS лист на текстовые файлы. Список файлов хранится в list.txt: имя_файла номер_начальной_строки номер_конечной_строки

Кроме того, стоит отметить неочевидный момент с работой с широкими чарами, в которых Эксель хранит русские символы (английские – в обычных), именно поэтому в листинге происходит выбор типа ячейки – 3 или 4. Если 4 (широкий чар), то мы его конвертируем в обычную строку (не забудьте подключить comdef.h).

BasicExcel xls;
if(!xls.Load(name)){ cout<<“No such XLS file!”<<endl; return 0;}
XLSFormatManager fmt_mgr(xls);
BasicExcelWorksheet* sheet = xls.GetWorksheet(0);
CellFormat fmt_general(fmt_mgr);
fmt_general.set_format_string(“0.000”);
fstream fin, fout;
fin.open(“list.txt”, ios::in);
if(!fin){ cout<<“No LIST.TXT file!”<<endl; return 0;}

char fname[255];
int i1,i2;

while(!fin.eof()){

fin>>fname>>i1>>i2;
cout<<“File: “<<fname<<” “<<i1<<” “<<i2<<endl;
fout.open(fname, ios::out);

if(i2 > sheet->GetTotalRows()) i2 = sheet->GetTotalRows();

for(int row = i1; row < i2; row++){
BasicExcelCell* cell = sheet->Cell(row, 1);
const char *str=0;
const WCHAR *wstr;
_bstr_t *b;

cout<<row<<” “<<cell->Type()<<endl;

if(cell->Type()==4){ //WSTRING
wstr=cell->GetWString();
b = new _bstr_t(wstr);
str = *b;
}

else if (cell->Type()==3){ //STRING
str = cell->GetString();
}

if(str!=NULL){
fout<<str<<endl;
}

else fout<<endl;
}

fout.close();
}

fin.close();

This entry was posted in Переводы, Программирование. Bookmark the permalink.

Leave a Reply