[SAP ABAP] Import and Export document Part 1

Client-side file processing

In a NetWeaver environment, we always need to remember the differences between the application server layer and the presentation layer. The application server layer is, as you may already know, a runtime environment for ABAP code. At a lower technical level, the application server is a remote server on which the NetWeaver platform is installed. The presentation layer instead can be understood as your local PC.
This difference is very important in the case of reading and writing files because SAP provides separate sets of tools in each case—one for processing files on the presentation layer and a second for processing files on the application server. Both are commonly used in SAP projects and will be fully covered in this chapter. 

Reading files from the local PC using gui_upload

Imagine a situation where a client asks you to develop an ABAP program that reads the content of files stored on the end user's local PC. This section will tell you exactly how to deal with such a situation.
The following steps show how to develop ABAP program that reads the content of files:
  1. Go to the ABAP Workbench (transaction SE80) and create a new report from the local class-based report template (look at Appendix AAssessments for help). You can give it any name, but I suggest sticking to the name given in this book (ZMSA_R_CHAPTER4_1). The code will look like this:
REPORT ZMSA_R_CHAPTER4_1.

CLASS lcl_demo DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS main.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.
  METHOD main.

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  lcl_demo=>main( ).
  1. We will put the entire code in the main method. Create two variables—one to store the filename and file path on our local system and one to store the contents of our file. The code will look as follows:
DATA: lv_filepath TYPE string VALUE 'C:\temp\testfile4_1.txt'.
DATA: lt_data TYPE TABLE OF string.
  1. We will assume just for now that our filename and file path will always be the same (C:\temp\testfile4_1.txt). Later, we will change it and allow the user to choose what he or she needs. Create a text file in C:\temp with the name testfile4_1.txt and insert the following content:
This is first line of testfile4_1.txt.
This is second line of testfile4_1.txt.
This is third line of testfile4_1.txt.
  1. The best way to read a file from the local PC is to use the gui_uploadstatic method from the standard SAP class cl_gui_frontend_services. Some people will use the old function module gui_upload, but a better approach is to use the gui_upload method. It's an object-oriented wrapper for gui_upload function which means the only purpose of this method is to call another function module. To save yourself a bit of time, you can always choose Pattern from the ABAP Workbench menu bar:

  1. In the popup that appears, choose ABAP Objects Patterns and click on the green checkmark:
  1. Another popup will appear. Fill it in as follows and click the green check mark again:
  1. Thanks to this, the method call pattern will be pasted into the source code of your program. You should see something similar to the following:
CALL METHOD cl_gui_frontend_services=>gui_upload
* EXPORTING
*     filename = SPACE
*     filetype = 'ASC'
*     has_field_separator = SPACE
*     header_length = 0
*     read_by_line = 'X'
*     dat_mode = SPACE
*     codepage = SPACE
*     ignore_cerr = ABAP_TRUE
*     replacement = '#'
*    virus_scan_profile =
* IMPORTING
    * filelength =
    * header =
CHANGING
    data_tab =
    * isscanperformed = SPACE
* EXCEPTIONS
    * [...]
We need to provide variables for the filename and data_tab parameters. It's important to notice that the filename parameter also includes a path. In our case, it's a full path so it's an absolute address. It can accept relative addressing and the default root directory is c:\Users\%USER%\Documents\SAP\SAP GUI\ (in a Windows environment). The parameter filename is commented out by default, so you have to remove the asterisk from the parameter name and from the EXPORTING section. 
If you look closely at the gui_upload method call pattern, you will see that there are a bunch of additional parameters that can help you archive specific business requirements. There is the filetype parameter, which can take one of three values: ASC (if data will be transferred as ASCII text), BIN (if data should be transferred unconverted in binary format), and DAT (if data should be transported unconverted as an ASCII text table, where the different columns are separated by a tabulator). You can also define code-page if you have different character encodingbycodepage parameters, the date format using dat_mode, or even run a virus scan by filling virus_scan_profile. For more information, you can read the class documentation. 
For displaying the results, we can use the display_data method from the cl_demo_outputclass. It's a very simple way to display something using just a single line of code. Please put the following method call at the end of the main method:
cl_demo_output=>display_data( lt_data ).
Now you can execute your program. Most likely, a SAP GUI security popup will appear. You need to click the Allow button to make this example work. This is standard SAP protection for unauthorized access to your local files. You can also mark the Remember My Decision checkbox to avoid being noticed next time you execute this program. You can always change these settings in the SAP GUI | Options Security Security Settings menu:
If everything went well, you should see a popup with the following content:
This code is far from perfect. First of all, the user has the possibility to choose a file he or she desires and not get a hardcoded one all the time. Let's be realistic; two user environments are never the same, so the hardcoded approach will never work in real life. To set up a dynamic file location, we need to use the method file_open_dialog from cl_gui_frontend_services. But first, we need to declare two additional variables—one to store the filename and file path and another to get user operation return code. Your new code should look like this:
DATA: lt_filetable TYPE filetable.
    DATA: lt_filetable TYPE file_table.
    DATA: lv_rc TYPE i.
Generate the method call pattern using the Pattern button for file_open_dialog, exactly like we did for the gui_upload method. This time it will produce the following code:
CALL METHOD cl_gui_frontend_services=>file_open_dialog
* EXPORTING
    * window_title =
    * default_extension =
    * default_filename =
    * file_filter =
    * with_encoding =
    * initial_directory =
    * multiselection =
  CHANGING
    file_table =
    rc =
    * user_action =
    * file_encoding =
    * EXCEPTIONS
    * file_open_dialog_failed = 1
    * cntl_error = 2
    * error_no_gui = 3
    * not_supported_by_gui = 4
    * others = 5
        .
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
Provide variables for file_table and rc parameters. It should be noted that the parameter file_table is of table type and can include more entries. This can be useful if you want to read multiple files, but can be also annoying if you have only one file in every scenario, because you have to implement additional logic to read the first (and only) file path in the table. The parameter rc gives you information on how many files were selected. It will be set to -1 if something went wrong. Use the READ TABLE keyword to read the first file path:
READ TABLE lt_filetable INTO lv_filepath INDEX 1.
Now if you run your program, you will get an additional popup where you can choose the desired file:
There are many additional useful parameters in the file_open_dialog method. You can block multiple file selection options (but you will still have to read the first entry from  lt_filetable). You can also make your dialog more business oriented and suitable by choosing the default directory path, default filetype, default extension, and additional filters. If you want to improve the user experience, you can make this popup a bit prettier by choosing the text for the title.
There is still one last part missing. We wrote down a nice piece of code but we didn't handle an expected situation we may come across. What will happen when the user does not choose any file at all? What will happen if the file can't be accessed? As a good programmer, you should always take care of such situations. Murphy's law is applicable in computer science more than anywhere else, so if something can go wrong, certainly sooner or later it will. The most obvious way is to tell the user what went wrong, put understandable information on the screen, and terminate processing. You can solve this in the following way (place it just after the file_open_dialog call):
IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty 
        NUMBER sy-msgno 
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
ELSEIF lv_rc < 1.
      MESSAGE 'No File choosen' TYPE 'W'.
      RETURN.
ENDIF.
Something similar can be also applied to the gui_upload call:
IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty 
        NUMBER sy-msgno 
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    RETURN.
ENDIF.
Make sure you have uncommented all the exceptions in the method call, otherwise catching an exception will not work and you will end up with a short dump.


Writing files to the local PC using gui_download

Now let's imagine the situation that the client needs a report which will generate a result in the form of a text file saved on the user's local computer. This chapter will expand your skills with this knowledge. It's very similar to the previous example; the only difference is that we write the file to the PC and not read from the PC. To save files and choose a suitable file path, we will be using new methods from the previously used class, cl_gui_frontend_services
First, create new report, ZMSA_R_CHAPTER4_2, and include a report template from Appendix AAssessments. We need to declare variables. We need three of them to make the method file_save_dialog work. lv_filename is the name of the file, lv_path is for the path-to-file directory where the file will be saved, and lv_fullpath is the path plus the filename. The code equivalent to this step looks like this: 
    DATA: lv_filename TYPE string.
    DATA: lv_path TYPE string.
    DATA: lv_fullpath TYPE string.
We will not hardcode the path in this example and will go straight into the method file_save_dialog. This is an analogous method to file_open_dialog but for choosing a path for where to store the file. Use the pattern option on the file_save_dialog method to produce a call (if you don't know how, please go back to the Reading files from the local PC using gui_upload section). If you did everything according to the instructions, you should see something like this:
CALL METHOD cl_gui_frontend_services=>file_save_dialog
* EXPORTING
    * window_title =
    * default_extension =
    * default_file_name =
    * with_encoding =
    * file_filter =
    * initial_directory =
    * prompt_on_overwrite = 'X'
  CHANGING
    filename =
    path =
    fullpath =
    * user_action =
    * file_encoding =
    * EXCEPTIONS
    * cntl_error = 1
    * error_no_gui = 2
    * not_supported_by_gui = 3
    * invalid_default_file_name = 4
    * others = 5
           .
IF sy-subrc <> 0.
    * Implement suitable error handling here
ENDIF.
Now, use the code pattern tool to insert the gui_download method call structure:
 CALL METHOD cl_gui_frontend_services=>gui_download
     EXPORTING
*       bin_filesize              =
       filename                  =
*       filetype                  = 'ASC'
*       append                    = SPACE
*       write_field_separator     = SPACE
*       header                    = '00'
*       trunc_trailing_blanks     = SPACE
*       write_lf                  = 'X'
*       col_select                = SPACE
*       col_select_mask           = SPACE
*       dat_mode                  = SPACE
*       confirm_overwrite         = SPACE
*       no_auth_check             = SPACE
*       codepage                  = SPACE
*       ignore_cerr               = ABAP_TRUE
*       replacement               = '#'
*       write_bom                 = SPACE
*       trunc_trailing_blanks_eol = 'X'
*       wk1_n_format              = SPACE
*       wk1_n_size                = SPACE
*       wk1_t_format              = SPACE
*       wk1_t_size                = SPACE
*       show_transfer_status      = 'X'
*       fieldnames                =
*       write_lf_after_last_line  = 'X'
*       virus_scan_profile        = '/SCET/GUI_DOWNLOAD'
*     IMPORTING
*       filelength                =
     changing
       data_tab                  =
*     EXCEPTIONS
*       file_write_error          = 1
*       no_batch                  = 2
*       gui_refuse_filetransfer   = 3
*       invalid_type              = 4
*       no_authority              = 5
*       unknown_error             = 6
*       header_not_allowed        = 7
*       separator_not_allowed     = 8
*       filesize_not_allowed      = 9
*       header_too_long           = 10
*       dp_error_create           = 11
*       dp_error_send             = 12
*       dp_error_write            = 13
*       unknown_dp_error          = 14
*       access_denied             = 15
*       dp_out_of_memory          = 16
*       disk_full                 = 17
*       dp_timeout                = 18
*       file_not_found            = 19
*       dataprovider_exception    = 20
*       control_flush_error       = 21
*       not_supported_by_gui      = 22
*       error_no_gui              = 23
*       others                    = 24
           .
   IF sy-subrc <> 0.
*    Implement suitable error handling here
   ENDIF.

Two parameters are obligatory—one to tell the method where to store the file and another that contains actual data to be stored. For the first parameter, we will use the lv_fullpath variable. For the second parameter, we need to declare a new variable: 
 DATA: lt_data_tab TYPE TABLE OF string.
In real life, some business data can be stored in a local file. In this example, we will just add a few dummy lines:
APPEND '1st dummy line' TO lt_data_tab.
APPEND '2nd dummy line' TO lt_data_tab.
APPEND '3rd dummy line' TO lt_data_tab.
If you execute your program, you will see save the file dialog:
You can choose whatever directory or filename you want, but you have to remember to be consistent in other parts of this example—we will refer to this value. If a file already exists, you will be asked to confirm overwriting:
After clicking Yes, go to the chosen path and open your file:

Note

Remember to use the mechanisms from the previous example to handle errors and inform the user what went wrong. 
I highly recommend playing around with all the other parameters of the gui_download method. It allows you to overwrite files without prompt popups and manipulate file content by using separators or date modifier options. You can also define the writing mode (data may be overwritten or appended at the end of the file).
Also, it's really worthwhile to check other methods from the cl_gui_frontend_services class as it can give you a variety of different possibilities. You can copy and delete a file or even read a file's attributes. This gives you a full spectrum of functionalities for working with directories. Apart from operations on files and folders, this class also offers a vast amount of other possibilities, such as the manipulation of registers and the reading of environment variables or other information about the user's system.


Server-side file processing

In this section, we will cover the basic transactions related to server-side files and writing and reading files to an application server. Those examples used in the loop and in the background job may be used for mass import and mass export.

Basic transactions related to server-side files

Before we start going into the ABAP code, we need to get familiar with a few useful transactions. In local environments and common operating systems, every user knows how to explore folders and view file contents. But in the case of server-side files, things are different. Of course, we talk here about a typical situation where the programmer does not have access to the server from the level of the operating system and can view files only by using the SAP GUI. The first transaction, AL11, is very important and useful. It's a SAP equivalent to Windows Explorer. Run AL11 from the Command Field in the SAP GUI. This will open the following:


In AL11, you can display server-side SAP directories, files, and file contents. We will use transaction AL11 to check if the files from the following example are really uploaded on the server. The full directory structure depends on the server operating system, but some of them are generic and should be quite similar in every SAP installation.
We will not discuss every single item in this list, but you should definitely know the most useful ones:
  • DIR_PROFILE is a central configuration directory of a SAP system. An instance is configured using a profile file stored in the DIR_PROFILE directory.
  • DIR_SAPUSERS is a default catalog for user files.
  • DIR_TRANS is a transport request directory. Basically, every released transport request is stored here as a file. You can copy such files and move into another system. It may be a good idea to back up your work for future use.
  • DIR_TEMP is a directory for temporary data.
Another two applications need to be mentioned before we jump into ABAP. The first one, CG3Z, is used to upload files to the server. The second, CG3Y, is to read files from the server. We will go through a simple example for each transaction, just for better visualization of how this really works. Run CG3Z first and fill everything in as follows:
Now you can verify the whole process by going to AL11 and exploring the used directory. If the path is not specified, the default folder will be DIR_SAPUSERS. For easy searching of the file, you can use a filter option on the menu bar:
Just put your filename in the popup:
This will remove all other files from the listing:
When you have located your file, you can open it by double-clicking it:
The second transaction, CG3Y, is used to download files from SAP server directories. Open CG3Y (it looks almost the same as CG3Z) and fill it in as follows: 
Write the source file path and filename into the Source file on application server field (analogously to the previous example in the CG3Z), and then choose to save your file anywhere you want by filling the Target file on front end field. Go to a temp directory to verify the new testfile4_2_from_server.txt file. It should have the same content as the original testfile4_2.txt:
In both transactions, we have two options we haven't covered yet. The Overwrite file option will overwrite the file if it exists in the destination directory and the Transfer format to data option that defines the method of file transfer as BIN for binary transfer and ASC for ASCII-like transfer. During both operations, a popup with an authorization permission question can appear. To make these examples work, you have to allow for read and write access. 

Writing files to the application server

Working with a file on a local PC gives you many capabilities; however, it has important limitations. For example, files are only available to us and if we close the current transaction, data will be lost. This means we can't use this data in a job or later in another transaction. The solution for these two problems can be storing files on the application server. We can't use cl_gui_frontend_services for that because it works only with the frontend layer. For application server-based file operations, we have a special keyword, OPEN DATASET.

Let's check how exactly this works. Please create a new report, ZMSA_R_CHAPTER4_3, from Appendix A, Assessments report template and declare the following variables in the main method:
DATA: lv_file TYPE string VALUE 'testfile4_3.txt'.
To open a file, you need to use the following syntax:
OPEN DATASET lv_file FOR OUTPUT IN TEXT MODE ENCODING DEFAULT. 
This actually opens something that may be considered stream to file. To write data into the file, you have to use the TRANSFER keyword:
TRANSFER '1st line on application server' TO lv_file.
TRANSFER '2nd line on application server' TO lv_file.
TRANSFER '3rd line on application server' TO lv_file.
After this operation, we have to close the file. To do so, we need to use the CLOSE DATASET statement:
CLOSE DATASET lv_file.
CLOSE DATASET will also save the current buffer to the file if there is some buffer on the operating system. An opened file that was not explicitly closed will be automatically closed when the program is exited. We can check our new file in an AL11 transaction. Keep in mind that we didn't provide a directory, so the file will be saved in the default root folder, DIR_SAPUSERS.

Reading files from the application server

Reading files from the application server is very easy; even easier than writing a file. But to be sure that this example works, we first need to store something in the application server. Copy a report pattern from Appendix A, Assessments into the newly created ZMSA_R_CHAPTER4_4. We need an additional variable to store file content lt_data and lv_line to temporarily store each line of a file. The variable lv_file is used to store the filename:
   DATA: lv_file TYPE string VALUE 'testfile4_3.txt'.
   DATA: lv_line TYPE string.
   DATA: lt_data TYPE TABLE OF string.

The first statement is almost the same as in the last exercise; we just need to change direction from OUTPUT to INPUT:
OPEN DATASET lv_file FOR INPUT IN TEXT MODE ENCODING DEFAULT.
Now, to read file content, we have to loop through every single line and put line content to our table variable  lt_data:
    DO.
      READ DATASET lv_file INTO lv_line.
      IF sy-subrc = 0.
        APPEND lv_line TO lt_data.
      ELSE.
        EXIT.
      ENDIF.
    ENDDO.
If a READ DATASET statement encounters the end of the file, sy-subrc will return a value of 4 and the DO loop will be stopped. Of course, you have to close the file:
 CLOSE DATASET lv_file.
To check the results, we will use the display_data method from the cl_demo_output class again:
cl_demo_output=>display_data( lt_data ).
If you did everything right after the execution of ZMSA_R_CHAPTER4_4, you should see the following:

Now you know how to do two basic operations with files on the application server. To learn more, you should check the SAP documentation for the OPEN DATASET statement. The last thing worth mentioning is two function modules, archivfile_client_to_server and eps2_get_directory_listing. The first function allows you to connect two operations—read a file from the client and upload it to the server. You can achieve this by mixing examples from this chapter, but this function can save you some time. The second function allows you to list all files and folders on the application server.

Comments

Popular posts from this blog

[SAP ABAP] Data declaration

[SAP ABAP] BAPI

[SAP HR] Payroll Schema