ABAP读取Excel方法大全

前言

ABAP读取Excel文件是比较常见的开发,可以使用多种方式实现,OLE是较为古老的技术,速度慢,且对主机有要求(系统,office版本等);最新的方案则是通过将Excel文件转换为XML进行解析,采用最新的面向对象编程,容易理解,且兼容性较好。

方法

标准函数

函数名 说明
TEXT_CONVERT_XLS_TO_SAP 直接将Excel数据解析为ABAP内表,但是需要内表结构与Excel结构一致
ALSM_EXCEL_TO_INTERNAL_TABL 将数据以单元格的维度读取出来,但最长只有50个字符

自定义方法
通过自定义功能,实现读取更大长度的内容,以及多个sheet
结构定义
在这里插入图片描述

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
* +--------------------------------------------------------------------------------------</SIGNATURE>
  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
* +--------------------------------------------------------------------------------------</SIGNATURE>
  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
* +--------------------------------------------------------------------------------------</SIGNATURE>
  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
* +--------------------------------------------------------------------------------------</SIGNATURE>
  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 基于cl_ixml,可通过sheet名称读取
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/

猜你喜欢

转载自blog.csdn.net/u012232542/article/details/109752588