ABAP Class to Import CSV Files
I had to write a few SAP ABAP programs which required the uploading of a CSV file in order to import data into SAP. Instead of writing and then copying a FORM into multiple programs (or calling the FORM from another program, or creating a function module, etc.) I developed an ABAP class that would handle the file upload and conversion of the CSV into an internal table. Below is the code for my class, the first part is automatically generated from the data entered in the class edit screen. You can tell the automatically generated code because it is formatted the opposite of code which has been formatted with the "pretty printer," the reserved words are in lower case and the variables are in upper case.
class Z_BC_USER_FILEIO definition
public
final
create public .
public section.
type-pools ABAP .
methods UPLOAD
importing
!I_SHOW_DIALOG type ABAP_BOOL default ' '
!I_WINDOW_TITLE type STRING default ''
!I_INITIAL_DIRECTORY type STRING default ''
!I_DEFAULT_FILE type STRING default '*.*'
!I_DEFAULT_EXTENSION type STRING default '*.*'
!I_FILE_FILTER type STRING default '*.*'
!I_UPLOAD_PATH type STRING default ''
!I_CSV_PARSE type ABAP_BOOL default ' '
!I_CSV_DATA_SEP type CHAR1 default ','
!I_CSV_ESC_CHAR type CHAR1 default '"'
!I_CSV_NUM_COLS type I default 9999
!I_CSV_SKIPHEAD type ABAP_BOOL default ' '
exporting
!E_FILE_RAWDATA type TEXTLINE_T
changing
!E_FILE_CSV_STRUCT type ANY optional
!E_FILE_CSV_TABLE type STANDARD TABLE optional
exceptions
UPLOAD_ERROR
PARSE_ERROR
PATH_ERROR
PROGRAM_ERROR .
private section.
data P_UPLOAD_PATH type STRING .
type-pools ABAP .
class-methods PARSE_CSV
importing
!I_CSV_DATA_SEP type CHAR1 default ','
!I_CSV_ESC_CHAR type CHAR1 default '"'
!I_CSV_NUM_COLS type I default 9999
!I_CSV_SKIPHEAD type ABAP_BOOL default ' '
!I_FILE_RAWDATA type TEXTLINE_T
exporting
!E_FILE_CSV_STRUCT type ANY
!E_FILE_CSV_TABLE type STANDARD TABLE
exceptions
PARSE_ERROR
TABLE_ERROR .
METHOD upload.
DATA: lf_error TYPE i VALUE 0,
lf_upload_path TYPE char1024,
lf_window_title TYPE string.
p_upload_path = i_upload_path.
lf_upload_path = p_upload_path.
" let user select file if needed
IF i_show_dialog = 'X'.
IF I_WINDOW_TITLE IS INITIAL.
lf_window_title = text-002.
ELSE.
lf_window_title = I_WINDOW_TITLE.
ENDIF.
CALL FUNCTION '/SAPSLL/BROWSE_LOCAL_FILE_SYST'
EXPORTING
iv_window_title = lf_window_title
iv_default_extension = i_default_extension
iv_default_filename = i_default_file
iv_file_filter = i_file_filter
iv_initial_directory = i_initial_directory
iv_multiselection = ' '
IMPORTING
ev_rcode = lf_error
CHANGING
iv_path = lf_upload_path
.
ELSE.
" Must have the path if not using the dialog
IF p_upload_path IS INITIAL.
lf_error = 1.
ENDIF.
ENDIF.
" upload the file if we have a path
IF lf_error = 0.
CALL METHOD cl_gui_frontend_services =>gui_upload
EXPORTING
filename = p_upload_path
CHANGING
data_tab = e_file_rawdata
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.
IF i_csv_parse = 'X'.
"IF ( e_file_csv_struct IS NOT INITIAL ) AND ( e_file_csv_table IS NOT INITIAL ).
CALL METHOD parse_csv
EXPORTING
i_csv_data_sep = i_csv_data_sep
i_csv_esc_char = i_csv_esc_char
i_file_rawdata = e_file_rawdata
i_csv_num_cols = i_csv_num_cols
i_csv_skiphead = i_csv_skiphead
IMPORTING
e_file_csv_struct = e_file_csv_struct
e_file_csv_table = e_file_csv_table
EXCEPTIONS
parse_error = 1
table_error = 2
OTHERS = 3
.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
RAISING parse_error.
ENDIF.
"ELSE. " I_CSV_PARSE set without other CSV parameters
" MESSAGE s000(Z_gts) DISPLAY LIKE 'E'
" WITH text-001 space space space
" RAISING program_error.
"ENDIF.
ENDIF.
ELSE. " GUI_UPLOAD error
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
RAISING upload_error.
ENDIF.
ELSE. " Path not set or error with user dialog
MESSAGE s000(Z_gts) DISPLAY LIKE 'E'
WITH text-000 p_upload_path space space
RAISING path_error.
ENDIF.
ENDMETHOD.
METHOD parse_csv.
DATA: lt_csv_table_struct TYPE REF TO data,
lt_csv_table_desc TYPE REF TO cl_abap_tabledescr,
ls_csv_table_desc TYPE REF TO cl_abap_structdescr,
lt_csv_table_flds TYPE abap_compdescr_tab,
ls_csv_table_flds TYPE abap_compdescr,
ls_file_rawline TYPE LINE OF textline_t,
lt_file_columns TYPE table_of_strings,
ls_file_columns TYPE LINE OF table_of_strings,
lf_skip_line TYPE abap_bool VALUE ' ',
ls_fieldcatalog TYPE lvc_s_fcat,
lt_fieldcatalog TYPE lvc_t_fcat,
lt_dynamictable TYPE REF TO data,
ls_dynamicline TYPE REF TO data,
lf_loop_count TYPE i,
lf_line_count TYPE i,
lf_fieldname TYPE char30.
FIELD-SYMBOLS: <fs_csv_table_struct> TYPE STANDARD TABLE,
<fs_dynamic_table> TYPE STANDARD TABLE,
<fs_dynamic_lines> TYPE ANY,
<fs_dynamic_field> TYPE ANY.
" determine the structure of the destination table
GET REFERENCE OF e_file_csv_table INTO lt_csv_table_struct.
ASSIGN lt_csv_table_struct->* TO <fs_csv_table_struct>.
lt_csv_table_desc ? =
cl_abap_structdescr =>describe_by_data_ref( lt_csv_table_struct ).
ls_csv_table_desc ? = lt_csv_table_desc->get_table_line_type( ).
lt_csv_table_flds = ls_csv_table_desc->components.
" use destination table structure for results table
LOOP AT lt_csv_table_flds INTO ls_csv_table_flds.
ls_fieldcatalog-fieldname = ls_csv_table_flds-name.
ls_fieldcatalog-inttype = ls_csv_table_flds-type_kind.
ls_fieldcatalog-intlen = ls_csv_table_flds-length.
ls_fieldcatalog-decimals = ls_csv_table_flds-decimals.
APPEND ls_fieldcatalog TO lt_fieldcatalog.
ENDLOOP.
" build a dynamic table to put the CSV contents into
CALL METHOD cl_alv_table_create =>create_dynamic_table
EXPORTING
it_fieldcatalog = lt_fieldcatalog
IMPORTING
ep_table = lt_dynamictable
EXCEPTIONS
generate_subpool_dir_full = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
RAISING table_error.
ENDIF.
" finish dynamic table, create dynamic table lines
ASSIGN lt_dynamictable->* TO <fs_dynamic_table>.
CREATE DATA ls_dynamicline LIKE LINE OF <fs_dynamic_table>.
ASSIGN ls_dynamicline->* TO <fs_dynamic_lines>.
" delete header line if needed
IF i_csv_skiphead = 'X'.
lf_skip_line = 'X'.
ENDIF.
" process the CSV file raw data
LOOP AT i_file_rawdata INTO ls_file_rawline.
CALL FUNCTION 'RSDS_CONVERT_CSV'
EXPORTING
i_data_sep = i_csv_data_sep
i_esc_char = i_csv_esc_char
i_record = ls_file_rawline
i_field_count = i_csv_num_cols
IMPORTING
e_t_data = lt_file_columns
EXCEPTIONS
escape_no_close = 1
escape_improper = 2
conversion_error = 3
OTHERS = 4.
IF sy-subrc <> 0. " RSDS_CONVERT_CSV error
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
RAISING parse_error.
ENDIF.
" store CSV fields into dynamic table
lf_loop_count = 1.
DESCRIBE TABLE lt_file_columns LINES lf_line_count.
LOOP AT lt_csv_table_flds INTO ls_csv_table_flds.
MOVE ls_csv_table_flds-name TO lf_fieldname.
ASSIGN COMPONENT lf_fieldname
OF STRUCTURE <fs_dynamic_lines>
TO <fs_dynamic_field>.
READ TABLE lt_file_columns INDEX lf_loop_count INTO ls_file_columns.
IF lf_loop_count < = lf_line_count.
<fs_dynamic_field> = ls_file_columns.
ELSE.
<fs_dynamic_field> = ''.
ENDIF.
lf_loop_count = lf_loop_count + 1.
ENDLOOP.
" move dynamic table line to resultant table, unless we are skipping
IF lf_skip_line = ' '.
MOVE-CORRESPONDING <fs_dynamic_lines> TO e_file_csv_struct.
APPEND e_file_csv_struct TO e_file_csv_table.
ELSE.
lf_skip_line = ' '.
ENDIF.
ENDLOOP.
ENDMETHOD.
Comments (newest first)
Thanks!