Считывание EXCEL во внутреннюю таблицу является задачей распространенной. Так же существует много способов ее решить, некоторые решения требуют много лишнего кода, некоторые не всегда удовлетворяют нужным требованиям. Как — то раз я наткнулся на статью посвященную этой задаче. Идея мне понравилась, я ее доработал с упором на простоту использования.
Если Вам не интересна реализация, то можно проскролить в конец статьи к исходникам и примерам использования.
Реализация
Набор методов у меня получился такой.

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 |
class ZCL_EXCEL_READER definition public create public . public section. methods CONSTRUCTOR importing value(EXCEL_BIN) type XSTRING optional . methods READ_EXCEL exporting value(E_FILE_NAME_PATH) type STRING returning value(R_STATUS) type CHAR1 . methods SET_EXCEL_BIN importing value(I_EXCEL_BIN) type XSTRING . methods PREPARE importing value(I_SHEET_NUMBER) type I default 1 . methods GET_TABLE importing value(I_HANDLE_ROWS) type I default 1 exporting value(E_TABLE) type STANDARD TABLE . methods GET_EXCEL_BIN returning value(R_EXCEL_BIN) type XSTRING . methods GET_SHEETS exporting value(E_SHEETS) type STANDARD TABLE . class-methods ITAB_TO_XLSX importing !IT_FIELDCAT type LVC_T_FCAT optional !IT_SORT type LVC_T_SORT optional !IT_FILT type LVC_T_FILT optional !IS_LAYOUT type LVC_S_LAYO optional !IT_HYPERLINKS type LVC_T_HYPE optional value(IT_DATA) type STANDARD TABLE returning value(R_XSTRING) type XSTRING . protected section. private section. types: T_WORKSHEET_NAMES type standard table of string . types: begin of CONVERT_MAPPING, index type int4, name type string, type_kind type char1, end of CONVERT_MAPPING . data EXCEL_BIN type XSTRING . data SHEETS type T_WORKSHEET_NAMES . data RAW_ITAB type ref to DATA . ENDCLASS. |
Для получения данных EXCEL файла нам необходимо его считать, либо каким-то образом передать его содержимое в оболочку.
Первый способ, при создании экземпляра класса в конструктор передать готовый бинарник.
1 2 3 4 5 |
method CONSTRUCTOR. me->excel_bin = excel_bin. endmethod. |
Либо после создания объекта воспользоваться методом SET_EXCEL_BIN
1 2 3 4 5 |
method SET_EXCEL_BIN. me->excel_bin = i_excel_bin. endmethod. |
Второй способ, считать файл непосредственно с компьютера. Для этого существует метод READ_EXCEL
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 |
method READ_EXCEL. data: file_name type filetable, answer type i. types : block type x LENGTH 1024. data : data_tab type standard table of block, length type i. cl_gui_frontend_services=>file_open_dialog( exporting window_title = 'Выберите файл' multiselection = abap_false changing file_table = file_name rc = answer exceptions file_open_dialog_failed = 1 cntl_error = 2 error_no_gui = 3 not_supported_by_gui = 4 others = 5 ). if sy-subrc <> 0 or lines( file_name ) = 0. R_STATUS = 'E'. return. endif. e_file_name_path = file_name[ 1 ]. cl_gui_frontend_services=>gui_upload( exporting filename = e_file_name_path filetype = 'BIN' importing filelength = length changing data_tab = data_tab exceptions file_open_error = 1 file_read_error = 2 no_batch = 3 gui_refuse_filetransfer = 4 invalid_type = 5 no_authority = 6 unknown_error = 7 bad_data_format = 8 header_not_allowed = 9 separator_not_allowed = 10 header_too_long = 11 unknown_dp_error = 12 access_denied = 13 dp_out_of_memory = 14 disk_full = 15 dp_timeout = 16 not_supported_by_gui = 17 error_no_gui = 18 others = 19 ). if sy-subrc <> 0. R_STATUS = 'E'. return. else. concatenate lines of data_tab[] into me->excel_bin in BYTE mode. me->excel_bin = me->excel_bin+0(length). R_STATUS = 'S'. endif. endmethod. |
После того как мы получили наш файл, следующим шагом обязательно должен быть вызов метода PREPARE. В качестве входящего параметра он имеет I_SHEET_NUMBER. Это значение отвечает за то, какую страницу в EXCEL файле нам нужно считать. Параметре имеет тип integer. Соответственно нам нужно указать порядковый номер страницы — первая, вторая… и т.д.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
method PREPARE. check me->excel_bin is not initial. data: mo_excel type ref to cl_fdt_xl_spreadsheet, sheets type standard table of string. mo_excel = new #( document_name = '' xdocument = me->excel_bin ). mo_excel->if_fdt_doc_spreadsheet~get_worksheet_names( importing worksheet_names = me->sheets ). if lines( me->sheets ) >= i_sheet_number . data(iv_name) = me->sheets[ i_sheet_number ]. me->raw_itab = mo_excel->if_fdt_doc_spreadsheet~get_itab_from_worksheet( iv_name ). endif. endmethod. |
Далее просто нужно получить содержимое страницы во внутреннюю таблицу при помощи метода GET_TABLE. Данный метод имеет входящий параметр i_handle_rows. Обычно в EXCEL файлах есть заголовки, этим параметром мы говорим сколько строк у нас выделено под заголовок, после считывания эти строки будут удалены. Если у нас нет заголовка, то ставим параметр как «0».
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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
method GET_TABLE. check me->raw_itab is not initial. field-symbols: <tab> type standard table. assign me->raw_itab->* to <tab>. if i_handle_rows > 0. delete <tab> from 1 to i_handle_rows. " обрезаем заголовок endif. ***************************************************** try . data: output_tabledescr type ref to cl_abap_tabledescr. output_tabledescr ?= cl_abap_tabledescr=>describe_by_data( E_TABLE ). data: output_structdescr type ref to cl_abap_structdescr. output_structdescr ?= output_tabledescr->get_table_line_type( ). DATA(output_components) = output_structdescr->get_components( ). data: excel_structdescr type ref to cl_abap_structdescr. excel_structdescr ?= cl_abap_structdescr=>describe_by_data( <tab>[ 1 ] ). data(excel_components) = excel_structdescr->get_components( ). data: mapping_table type standard table of convert_mapping. * генерируем строку соотвествующую названию полей нашей структуры insert initial line into <tab> index 1. assign <tab>[ 1 ] to field-symbol(<row>). if <row> is assigned. loop at excel_components into data(src_comp). data(my_index) = sy-tabix. if line_exists( output_components[ my_index ] ). " тут же обрезаются лишние столбцы в EXCEL data(output_comp) = output_components[ my_index ]. assign component src_comp-name of structure <row> to field-symbol(<row_header_field>). <row_header_field> = output_comp-name. **************************** создаем мапинг строки для последующей конвертации append initial line to mapping_table assigning field-symbol(<mapping>). <mapping>-index = my_index. <mapping>-name = output_comp-name. <mapping>-type_kind = output_comp-type->type_kind. endif. endloop. endif. delete <tab> index 1. loop at <tab> assigning field-symbol(<excel_row>). data(tabix) = sy-tabix. append initial line to e_table assigning field-symbol(<output_row>). loop at mapping_table into data(mapping). assign component mapping-index of structure <excel_row> to field-symbol(<excel_cell>). assign component mapping-index of structure <output_row> to field-symbol(<output_column_fld>). ******** обработка полей try . if mapping-type_kind = 'D'. replace all occurrences of '-' in <excel_cell> with ''. endif. if mapping-type_kind = 'N'. replace all occurrences of '.' in <excel_cell> with ''. endif. catch cx_root. clear <excel_cell>. endtry. ******** присваивание try. <output_column_fld> = <excel_cell>. catch cx_root. clear: <output_column_fld>. endtry. endloop. endloop. catch cx_root. endtry. endmethod. |
На этом процесс завершен, данные считанны.
Так же среди методов можно заметить статический метод ITAB_TO_XLSX. Этот метод делает обратный процесс. Превращает внутреннюю таблицу в excel файл. Более подробно об этом я писал в этой статье.
Способ использования
Код вызова представлен ниже. Соответственно структура внутренней таблицы должна совпадать со структурой файла.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
* любая Ваша структура types: begin of load_str, field1 type string, field2 type int4, field3 type f, field4 type n length 10, field5 type dats, end of load_str. data: reader type ref to zcl_excel_reader, load type table of load_str. reader = new #( ). * откроется окошко с выбором файла reader->read_excel( ). * считываем первую страницу reader->prepare( 1 ). * указываем, что под заголовок у нас зарезервирована одна строка reader->get_table( exporting i_handle_rows = 1 importing e_table = load ). |
Либо
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
types: begin of load_str, field1 type string, field2 type int4, field3 type f, field4 type n length 10, field5 type dats, end of load_str. data: reader type ref to zcl_excel_reader, load type table of load_str, excel_bin type xstring. ***** * инициализация excel_bin ***** reader = new #( excel_bin ). reader->prepare( 1 ). * нет заголовка, значение 0 reader->get_table( exporting i_handle_rows = 0 importing e_table = load ). |
На этом этапе, у Вас во внутренней таблице load будет содержимое страницы EXCEL файла. Для считывания нужно всего несколько строк, довольно удобно.
Исходный код класса-оболочки для считывания EXCEL файлов можно найти по ссылке.