ABAP读取Excel文件可以使用多种方式实现,OLE是最常用的技术,但速度及兼容性较差;也可以使用DOI接口读取,最新的技术则通过XML技术进行解析,采用最新的面向对象编程,容易理解,且兼容性较好。
标准函数
class ZCL_MDG_IF_TOOLS definition
public
final
create public .
public section.
type-pools OLE2 .
types:
types TY_D_ITABVALUE type ZSMDG_ALSMEX_TABLINE-VALUE .
types TY_ITAB type ZSMDG_ALSMEX_TABLINE .
types:
ty_t_itab type table of zsmdg_alsmex_tabline .
types:
begin of ty_s_senderline,
line(4096) type c,
end of ty_s_senderline .
types TY_SENDER type TY_S_SENDERLINE .
types:
ty_t_sender type table of ty_s_senderline .
constants GC_ESC type C value '"' ##NO_TEXT.
class-methods READ_EXCEL_MULTIPLE_SHEETS
importing
!FILENAME type RLGRAP-FILENAME
!I_BEGIN_COL type I default 1
!I_BEGIN_ROW type I default 2
!I_END_COL type I default 99
!I_END_ROW type I default 100000
!SHEET_INDEX type I optional
!SHEET_NAME type ALSMEX_TABLINE-VALUE optional
exporting
!INTERN type ZMDG_ALSMEX_TABLINE_T
exceptions
INCONSISTENT_PARAMETERS
UPLOAD_OLE .
protected section.
class-methods line_to_cell_esc_sep
changing
!i_string type any
!i_sic_int type i
!i_separator type c
!i_intern_value type ty_d_itabvalue .
class-methods line_to_cell_separat
changing
!i_line type any
!i_row type sy-tabix
!ch_cell_col type kcd_ex_col
!i_separator type c
!i_fdpos type sy-fdpos
!i_intern type ty_t_itab .
class-methods separated_to_intern_convert
changing
!i_tab type ty_t_sender
!i_separator type c
!i_intern type ty_t_itab .
private section.
ENDCLASS.
CLASS ZCL_MDG_IF_TOOLS IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Protected Method ZCL_MDG_IF_TOOLS=>LINE_TO_CELL_ESC_SEP
* +-------------------------------------------------------------------------------------------------+
* | [<-->] I_STRING TYPE ANY
* | [<-->] I_SIC_INT TYPE I
* | [<-->] I_SEPARATOR TYPE C
* | [<-->] I_INTERN_VALUE TYPE TY_D_ITABVALUE
* +--------------------------------------------------------------------------------------
method line_to_cell_esc_sep.
data: l_int type i,
l_cell_end(2).
field-symbols: <l_cell> type any.
l_cell_end = gc_esc.
l_cell_end+1 = i_separator .
if i_string cs gc_esc.
i_string = i_string+1.
if i_string cs l_cell_end.
l_int = sy-fdpos.
assign i_string(l_int) to <l_cell>.
i_intern_value = <l_cell>.
l_int = l_int + 2.
i_sic_int = l_int.
i_string = i_string+l_int.
elseif i_string cs gc_esc.
* letzte Celle
l_int = sy-fdpos.
assign i_string(l_int) to <l_cell>.
i_intern_value = <l_cell>.
l_int = l_int + 1.
i_sic_int = l_int.
i_string = i_string+l_int.
l_int = strlen( i_string ).
if l_int > 0 . message x001(kx) . endif.
else.
message x001(kx) .
endif.
endif.
endmethod.
*<SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Protected Method ZCL_MDG_IF_TOOLS=>LINE_TO_CELL_SEPARAT
* +-------------------------------------------------------------------------------------------------+
* | [<-->] I_LINE TYPE ANY
* | [<-->] I_ROW TYPE SY-TABIX
* | [<-->] CH_CELL_COL TYPE KCD_EX_COL
* | [<-->] I_SEPARATOR TYPE C
* | [<-->] I_FDPOS TYPE SY-FDPOS
* | [<-->] I_INTERN TYPE TY_T_ITAB
* +--------------------------------------------------------------------------------------
method line_to_cell_separat.
data: l_string type ty_s_senderline.
data l_sic_int type i.
data:ls_intern type zsmdg_alsmex_tabline.
clear ls_intern.
l_sic_int = i_fdpos.
ls_intern-row = i_row.
l_string = i_line.
ls_intern-col = ch_cell_col.
* csv Dateien mit separator in Zelle: --> ;"abc;cd";
if ( i_separator = ';' or i_separator = ',' ) and
l_string(1) = gc_esc.
line_to_cell_esc_sep(
changing
i_string = l_string
i_sic_int = l_sic_int
i_separator = i_separator
i_intern_value = ls_intern-value
).
else.
if l_sic_int > 0.
ls_intern-value = i_line(l_sic_int).
endif.
endif.
if l_sic_int > 0.
append ls_intern to i_intern.
endif.
l_sic_int = l_sic_int + 1.
i_line = i_line+l_sic_int.
endmethod.
*<SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_MDG_IF_TOOLS=>READ_EXCEL_MULTIPLE_SHEETS
* +-------------------------------------------------------------------------------------------------+
* | [--->] FILENAME TYPE RLGRAP-FILENAME
* | [--->] I_BEGIN_COL TYPE I (default =1)
* | [--->] I_BEGIN_ROW TYPE I (default =2)
* | [--->] I_END_COL TYPE I (default =99)
* | [--->] I_END_ROW TYPE I (default =100000)
* | [--->] SHEET_INDEX TYPE I(optional)
* | [--->] SHEET_NAME TYPE ALSMEX_TABLINE-VALUE(optional)
* | [<---] INTERN TYPE ZMDG_ALSMEX_TABLINE_T
* | [EXC!] INCONSISTENT_PARAMETERS
* | [EXC!] UPLOAD_OLE
* +--------------------------------------------------------------------------------------
method read_excel_multiple_sheets.
data: excel_tab type ty_t_sender.
data: ld_separator type c.
data: application type ole2_object,
workbook type ole2_object,
range type ole2_object,
worksheet type ole2_object.
data: h_cell type ole2_object,
h_cell1 type ole2_object.
data:
ld_rc type i.
* Rückgabewert der Methode "clipboard_export "
* Makro für Fehlerbehandlung der Methods
define m_message.
CASE sy-subrc.
WHEN 0.
WHEN 1.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
WHEN OTHERS. RAISE upload_ole.
ENDCASE.
end-of-definition.
* check parameters
if i_begin_row > i_end_row.
raise inconsistent_parameters.
endif.
if i_begin_col > i_end_col.
raise inconsistent_parameters.
endif.
* Get TAB-sign for separation of fields
class cl_abap_char_utilities definition load.
ld_separator = cl_abap_char_utilities=>horizontal_tab.
* open file in Excel
if application-header = space or application-handle = -1.
create object application 'Excel.Application'.
m_message.
endif.
call method of application 'Workbooks' = workbook.
m_message.
call method of workbook 'Open' exporting #1 = filename.
m_message.
* set property of application 'Visible' = 1.
* m_message.
*-------ADD START---------
if sheet_name is not initial.
call method of application 'WORKSHEETS' = worksheet
exporting
#1 = sheet_name.
if sy-subrc ne 0.
return.
endif.
call method of worksheet 'Activate'.
m_message.
elseif sheet_index is not initial.
call method of application 'WORKSHEETS' = worksheet
exporting
#1 = sheet_index.
if sy-subrc ne 0.
return.
endif.
call method of worksheet 'Activate'.
m_message.
else."默认模式
get property of application 'ACTIVESHEET' = worksheet.
m_message.
endif.
*-------ADD END---------
* mark whole spread sheet
call method of worksheet 'Cells' = h_cell
exporting #1 = i_begin_row #2 = i_begin_col.
m_message.
call method of worksheet 'Cells' = h_cell1
exporting #1 = i_end_row #2 = i_end_col.
m_message.
call method of worksheet 'RANGE' = range
exporting #1 = h_cell #2 = h_cell1.
m_message.
call method of range 'SELECT'.
m_message.
* copy marked area (whole spread sheet) into Clippboard
call method of range 'COPY'.
m_message.
* read clipboard into ABAP
call method cl_gui_frontend_services=>clipboard_import
importing
data = excel_tab
exceptions
cntl_error = 1
* ERROR_NO_GUI = 2
* NOT_SUPPORTED_BY_GUI = 3
others = 4.
if sy-subrc <> 0.
message a037(alsmex).
endif.
separated_to_intern_convert(
changing
i_tab = excel_tab
i_intern = intern
i_separator = ld_separator
).
* clear clipboard
refresh excel_tab.
call method cl_gui_frontend_services=>clipboard_export
importing
data = excel_tab
changing
rc = ld_rc
exceptions
cntl_error = 1
* ERROR_NO_GUI = 2
* NOT_SUPPORTED_BY_GUI = 3
others = 4.
* quit Excel and free ABAP Object - unfortunately, this does not kill
* the Excel process
call method of application 'QUIT'.
m_message.
* >>>>> Begin of change note 575877
* to kill the Excel process it's necessary to free all used objects
free object h_cell. m_message.
free object h_cell1. m_message.
free object range. m_message.
free object worksheet. m_message.
free object workbook. m_message.
free object application. m_message.
* <<<<< End of change note 575877
endmethod.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Protected Method ZCL_MDG_IF_TOOLS=>SEPARATED_TO_INTERN_CONVERT
* +-------------------------------------------------------------------------------------------------+
* | [<-->] I_TAB TYPE TY_T_SENDER
* | [<-->] I_SEPARATOR TYPE C
* | [<-->] I_INTERN TYPE TY_T_ITAB
* +--------------------------------------------------------------------------------------
method separated_to_intern_convert.
data: l_sic_tabix type sy-tabix,
l_sic_col type kcd_ex_col.
data: l_fdpos type sy-fdpos.
data:ls_intern type zsmdg_alsmex_tabline.
refresh i_intern.
loop at i_tab assigning field-symbol(<fs_tab>).
l_sic_tabix = sy-tabix.
l_sic_col = 0.
while <fs_tab> ca i_separator.
l_fdpos = sy-fdpos.
l_sic_col = l_sic_col + 1.
line_to_cell_separat(
changing
i_line = <fs_tab>
i_intern = i_intern
i_row = l_sic_tabix
ch_cell_col = l_sic_col
i_separator = i_separator
i_fdpos = l_fdpos
).
endwhile.
if <fs_tab> <> space.
clear ls_intern.
ls_intern-row = l_sic_tabix.
ls_intern-col = l_sic_col + 1.
ls_intern-value = <fs_tab>.
append ls_intern to i_intern.
endif.
endloop.
endmethod.
ENDCLASS.
面向对象实现
类名 | 说明 |
---|---|
cl_fdt_xl_spreadsheet | 限制使用,参考评论区 |
abap2xlsx | 开源仓库,推荐使用,,可通过abapgit获取 |
参考代码 |
"首先获取文件流xstring
data(lo_excel) = new cl_fdt_xl_spreadsheet( document_name = ms_upload-file_name xdocument = ms_upload-file ).
lo_excel->if_fdt_doc_spreadsheet~get_worksheet_names(
importing
worksheet_names = data(lt_worksheets)
).
data:lr_sheet_data type ref to data.
field-symbols:<ft_sheet_data> type index table.
loop at lt_worksheets reference into data(lr_worksheet).
data(lv_sheet_index) = sy-tabix.
lr_sheet_data = lo_excel->if_fdt_doc_spreadsheet~get_itab_from_worksheet(
worksheet_name = lr_worksheet->*
).
if <ft_sheet_data> is assigned.
unassign <ft_sheet_data>.
endif.
assign lr_sheet_data->* to <ft_sheet_data>.
endloop.
对于Excel文件的写入,常用的有OLE或DOI等技术,我个人比较喜欢用开源库abap2xlsx,也可考虑xlsx workbench实现,参考如下
https://github.com/sapmentors/abap2xlsx
https://blogs.sap.com/2014/04/22/xlsx-workbench/
https://blogs.sap.com/2020/05/22/best-way-to-generate-microsoft-excel-xlsx-from-template-in-abap/
https://blogs.sap.com/2021/12/30/xlsc-upload-unified-approach-for-older-abap-version/