Variante 1 (cl_gui_frontend_services, freier Separator)
* Beispiel für die CSV-Eingabedaten:
* Mandant;Fluggesellschaft;Flugnummer;Land;Abflugstadt;Startflugh.;Land;Ankunftstadt;Zielflugh.;Flugdauer;Abflug;Ankunftszeit;Entfernung;Entfernung in;Charter;n Tag(e) später;
* 900;AA;0017;US;NEW YORK;JFK;US;SAN FRANCISCO;SFO; 6:01;11:00:00;14:01:00;2572;MI;;0;
* 900;AA;0064;US;SAN FRANCISCO;SFO;US;NEW YORK;JFK; 5:21;09:00:00;17:21:00;2572;MI;;0;
* Ausgabestruktur (Spalten) für die eingelesenen und gesplitteten CSV-Daten
* der Einfachheit halber hier alles erstmal als Strings abbilden
TYPES : BEGIN OF ty_s_csv,
mandant TYPE string,
fluggesellschaft TYPE string,
flugnummer TYPE string,
land_ab TYPE string,
abflugstadt TYPE string,
startflughafen TYPE string,
land_an TYPE string,
ankunftstadt TYPE string,
zielflughafen TYPE string,
flugdauer TYPE string,
abflug TYPE string,
ankunftszeit TYPE string,
entfernung TYPE string,
einheit TYPE string,
charter TYPE string,
tage TYPE string,
END OF ty_s_csv.
* Tabellentypen
TYPES: ty_it_csv TYPE STANDARD TABLE OF ty_s_csv WITH DEFAULT KEY.
* Überschriften vorhanden
PARAMETERS: p_head AS CHECKBOX DEFAULT 'X'.
* Separator / Trennzeichen
PARAMETERS: p_sep TYPE char1 DEFAULT ';'.
TRY.
DATA: lv_rc TYPE i.
DATA: it_files TYPE filetable.
DATA: lv_action TYPE i.
* FileOpen-Dialog aufrufen
cl_gui_frontend_services=>file_open_dialog( EXPORTING
file_filter = |csv (*.csv)\|*.csv\|{ cl_gui_frontend_services=>filetype_all }|
multiselection = abap_false
CHANGING
file_table = it_files
rc = lv_rc
user_action = lv_action ).
IF lv_action = cl_gui_frontend_services=>action_ok.
* wenn mind. eine Dateie ausgewählt worden ist
IF lines( it_files ) = 1.
* Tabelle für Einlesedaten
DATA(it_strings) = VALUE string_table( ).
* eingelesene Datei zeilenweise als Stringdaten einlesen
cl_gui_frontend_services=>gui_upload( EXPORTING
filename = CONV #( it_files[ 1 ]-filename )
filetype = 'ASC' " Dateityp BIN, ASC, DAT
CHANGING
data_tab = it_strings ). " Übergabetabelle für Datei-Inhalt
cl_demo_output=>write_data( it_strings ).
* Wenn mit Header, dann ab Zeile 2, sonst gleich ab Zeile 1
DATA(lv_startzeile) = COND i( WHEN p_head = abap_true THEN 2 ELSE 1 ).
* Je nach Vorhandensein des Headers prüfen, ob genug Zeilen in der Tabelle
IF ( lines( it_strings ) > lv_startzeile - 1 ).
* Ausgabetabelle mit ausgesplitteten CSV-Daten
DATA(it_csv) = VALUE ty_it_csv( ).
* Eingelesene Strings durchlaufen, Start bei Zeile 1 (mit Header) oder 2 (mit Header)
LOOP AT it_strings ASSIGNING FIELD-SYMBOL(<z>) FROM lv_startzeile.
* neue Ausgabezeile
DATA(lv_csv_line) = VALUE ty_s_csv( ).
* String anhand des Separators aufsplitten
SPLIT <z> AT p_sep INTO TABLE DATA(it_columns).
* Wenn anzahl der Splitelemente == Anzahl Felder in der CSV-Struktur
IF lines( it_columns ) = 16.
* gesplittete Daten in die neue CSV-Zeile übernehmen
lv_csv_line-mandant = it_columns[ 1 ].
lv_csv_line-fluggesellschaft = it_columns[ 2 ].
lv_csv_line-flugnummer = it_columns[ 3 ].
lv_csv_line-land_ab = it_columns[ 4 ].
lv_csv_line-abflugstadt = it_columns[ 5 ].
lv_csv_line-startflughafen = it_columns[ 6 ].
lv_csv_line-land_an = it_columns[ 7 ].
lv_csv_line-ankunftstadt = it_columns[ 8 ].
lv_csv_line-zielflughafen = it_columns[ 9 ].
lv_csv_line-flugdauer = it_columns[ 10 ].
lv_csv_line-abflug = it_columns[ 11 ].
lv_csv_line-ankunftszeit = it_columns[ 12 ].
lv_csv_line-entfernung = it_columns[ 13 ].
lv_csv_line-einheit = it_columns[ 14 ].
lv_csv_line-charter = it_columns[ 15 ].
lv_csv_line-tage = it_columns[ 16 ].
ENDIF.
* neue CSV-Zeile an Ausgabetabelle anfügen
APPEND lv_csv_line TO it_csv.
ENDLOOP.
cl_demo_output=>write_data( it_csv ).
* HTML-Code vom Demo-Output holen
DATA(lv_html) = cl_demo_output=>get( ).
* Daten im Inline-Browser im SAP-Fenster anzeigen
cl_abap_browser=>show_html( EXPORTING
title = 'Daten aus CSV'
html_string = lv_html
container = cl_gui_container=>default_screen ).
* cl_gui_container=>default_screen erzwingen
WRITE: space.
ENDIF.
ENDIF.
ENDIF.
CATCH cx_root INTO DATA(e_text).
MESSAGE e_text->get_text( ) TYPE 'I'.
ENDTRY.
Variante 2 (cl_gui_frontend_services, freier Separator, dynamisches Einlesen von CSV-Daten)
* Überschriften vorhanden
PARAMETERS: p_head AS CHECKBOX DEFAULT 'X'.
* Separator / Trennzeichen
PARAMETERS: p_sep TYPE char1 DEFAULT ';'.
TRY.
DATA: lv_rc TYPE i.
DATA: it_files TYPE filetable.
DATA: lv_action TYPE i.
* FileOpen-Dialog aufrufen
cl_gui_frontend_services=>file_open_dialog( EXPORTING
file_filter = |csv (*.csv)\|*.csv\|{ cl_gui_frontend_services=>filetype_all }|
multiselection = abap_false
CHANGING
file_table = it_files
rc = lv_rc
user_action = lv_action ).
IF lv_action = cl_gui_frontend_services=>action_ok.
* wenn mind. eine Dateie ausgewählt worden ist
IF lines( it_files ) = 1.
* Tabelle für Einlesedaten
DATA(it_strings) = VALUE string_table( ).
* eingelesene Datei zeilenweise als Stringdaten einlesen
cl_gui_frontend_services=>gui_upload( EXPORTING
filename = CONV #( it_files[ 1 ]-filename )
filetype = 'ASC' " Dateityp BIN, ASC, DAT
CHANGING
data_tab = it_strings ). " Übergabetabelle für Datei-Inhalt
cl_demo_output=>write_data( it_strings ).
DATA(it_errors) = VALUE string_table( ).
* Wenn mit Header, dann ab Zeile 2, sonst gleich ab Zeile 1
DATA(lv_startzeile) = COND i( WHEN p_head = abap_true THEN 2 ELSE 1 ).
* Je nach Vorhandensein des Headers prüfen, ob genug Zeilen (für Erstellung des Headers) in der Tabelle
IF ( lines( it_strings ) > lv_startzeile - 1 ).
* 1. verfügbaren String aus der eingelesenen Tabelle anhand des Separators aufsplitten
SPLIT it_strings[ 1 ] AT p_sep INTO TABLE DATA(it_cnt_col).
* Komponenten (Spalten) der Tabelle
DATA(it_components) = VALUE cl_abap_structdescr=>component_table( ).
* Komponententabelle füllen
LOOP AT it_cnt_col ASSIGNING FIELD-SYMBOL(<c>).
* Standard-Spaltenbezeichner vorbelegen (COL1...COLn)
DATA(lv_name) = |COL{ sy-tabix }|.
* Wenn Header vorhanden, dann Header übernehmen
IF p_head = abap_true.
lv_name = <c>.
* alle Vorkommen, die nicht [a-zA-Z0-9_] entsprechen, durch '_' ersetzen
REPLACE ALL OCCURRENCES OF REGEX '([^\w]|[äöüÄÖÜß])+' IN lv_name WITH '_'.
ENDIF.
* Spalte vom Typ String zur Komponententabelle hinzufügen
APPEND VALUE #( name = lv_name
type = cl_abap_elemdescr=>get_string( )
) TO it_components.
ENDLOOP.
* Strukturdeskriptor für Komponententabelle
DATA(o_struct_desc) = cl_abap_structdescr=>create( it_components ).
* Tabellendeskriptor erzeugen
DATA(o_table_desc) = cl_abap_tabledescr=>create(
p_line_type = o_struct_desc " Spalten
p_table_kind = cl_abap_tabledescr=>tablekind_std " Tabellentyp STANDARD TABLE
p_unique = abap_false " NON-UNIQUE KEY
p_key_kind = cl_abap_tabledescr=>keydefkind_default " Benutzerdefinierter Schlüssel
).
* Tabellenobjekt anhand des Tabellendeskriptors erstellen
DATA: o_table TYPE REF TO data.
CREATE DATA o_table TYPE HANDLE o_table_desc.
* Feldsymbol auf das Tabellenobjekt
FIELD-SYMBOLS <csv_table> TYPE STANDARD TABLE.
ASSIGN o_table->* TO <csv_table>.
* Eingelesene Strings durchlaufen, Start bei Zeile 1 (ohne Header) oder 2 (mit Header)
LOOP AT it_strings ASSIGNING FIELD-SYMBOL(<z>) FROM lv_startzeile.
* neue Ausgabezeile anfügen
APPEND INITIAL LINE TO <csv_table>.
* neue Ausgabezeile holen
DATA(lv_lc) = lines( <csv_table> ).
ASSIGN <csv_table>[ lv_lc ] TO FIELD-SYMBOL(<row>).
* String anhand des Separators aufsplitten
SPLIT <z> AT p_sep INTO TABLE DATA(it_column_data).
* Wenn anzahl der Splitelemente == Anzahl Felder in der CSV-Struktur
IF lines( it_column_data ) = lines( it_components ).
* gesplittete Daten in die neue CSV-Zeile übernehmen
LOOP AT it_components ASSIGNING FIELD-SYMBOL(<comp>).
* n-te Spalte <col> der akt. Tabellenzeile <row> ermitteln
ASSIGN COMPONENT sy-tabix OF STRUCTURE <row> TO FIELD-SYMBOL(<col>).
* den n-ten gesplitteten Wert der n-ten Spalte <col> der akt. Tabellenzeile <row> zuordnen
<col> = it_column_data[ sy-tabix ].
ENDLOOP.
ELSE.
* Wenn abweichende Spaltenanzahl vom Header
APPEND |Zeile { sy-tabix }: Spaltenanzahl ({ lines( it_column_data ) }) weicht vom Header ({ lines( it_components ) }) ab.| TO it_errors.
ENDIF.
ENDLOOP.
cl_demo_output=>write_data( it_errors ).
cl_demo_output=>write_data( <csv_table> ).
* HTML-Code vom Demo-Output holen
DATA(lv_html) = cl_demo_output=>get( ).
* Daten im Inline-Browser im SAP-Fenster anzeigen
cl_abap_browser=>show_html( EXPORTING
title = 'Daten aus CSV'
html_string = lv_html
container = cl_gui_container=>default_screen ).
* cl_gui_container=>default_screen erzwingen
WRITE: space.
ENDIF.
ENDIF.
ENDIF.
CATCH cx_root INTO DATA(e_text).
MESSAGE e_text->get_text( ) TYPE 'I'.
ENDTRY.
Variante 3 (cl_gui_frontend_services, TAB-Zeichen als Separator)
* CSV-Datei mit drei Spalten
TYPES: BEGIN OF ty_s_type,
col1 TYPE string,
col2 TYPE string,
col3 TYPE string,
END OF ty_s_type.
TYPES: ty_it_csv TYPE STANDARD TABLE OF ty_s_type WITH DEFAULT KEY.
DATA: it_csv TYPE ty_it_csv.
TRY.
* Setzt voraus, dass die CSV-Daten TAB-getrennt sind!
cl_gui_frontend_services=>gui_upload( EXPORTING
filename = 'c:\temp\test.csv' " Eingabedatei
filetype = 'ASC' " Dateityp BIN, ASC, DAT
has_field_separator = abap_true " Spalten durch TAB getrennt bei ASCII Upload?
CHANGING
data_tab = it_csv ). " Übergabetabelle für Datei-Inhalt
cl_demo_output=>write_data( it_csv ).
CATCH cx_root INTO DATA(e_text).
MESSAGE e_text->get_text( ) TYPE 'I'.
ENDTRY.
Variante 4 (Funktionbaustein, obsolet)
* CSV-Datei mit drei Spalten
TYPES: BEGIN OF ty_s_type,
col1 TYPE string,
col2 TYPE string,
col3 TYPE string,
END OF ty_s_type.
TYPES: ty_it_csv TYPE STANDARD TABLE OF ty_s_type WITH DEFAULT KEY.
DATA: it_csv TYPE ty_it_csv.
* Funktion ruft eigenen File-Open-Dialog auf
* FuBa UPLOAD ist obsolet
CALL FUNCTION 'UPLOAD'
EXPORTING
filename = 'c:\temp\data.txt' " Dateinamen vorbelegen
filetype = 'DAT' " Eingabedatei-Typ: Datentabelle ASCII mit Spaltentabulator
TABLES
data_tab = it_csv
EXCEPTIONS
conversion_error = 1
file_open_error = 2
file_read_error = 3
invalid_table_width = 4
invalid_type = 5
no_batch = 6
unknown_error = 7
gui_refuse_filetransfer = 8
OTHERS = 9.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.