FUNCTION Z_WRITE_TO_FILE.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(ITAB) TYPE  ANY TABLE
*"     REFERENCE(FLD_DELI) TYPE  CHAR1 DEFAULT ','
*"     REFERENCE(REC_DELI) TYPE  CHAR2
*"     REFERENCE(ENCLOSE_CHAR) TYPE  CHAR1 DEFAULT '"'
*"     REFERENCE(FILENAME) TYPE  RLGRAP-FILENAME
*"     REFERENCE(ACCESSMODE) TYPE  CHAR1 DEFAULT 'O'
*"     REFERENCE(CODEPAGE) TYPE  TCP00-CPCODEPAGE DEFAULT 1160
*"     REFERENCE(DISP_LABEL) TYPE  CHAR1 DEFAULT ''
*"     REFERENCE(STRUT_NAME) TYPE  DD03T-TABNAME DEFAULT ''
*"  EXPORTING
*"     REFERENCE(MSG) TYPE  STRING
*"  EXCEPTIONS
*"      FILE_CANNOT_OPEN
*"      FILE_CLOSE_ERROR
*"      FILE_DOWNLOAD_ERROR
*"      STRUT_NAME_ERROR
*"----------------------------------------------------------------------
* This function is used to download a passed itab with any type to UNIX
* server or client PC with specified field & record delimiter, access mode,
* codepage and path.
*-----------------------------------------------------------------------
  TYPE-POOLS: ABAP.
* the following code should be in global data.-begin
   CONSTANTS: C_QOUTATION_MARK TYPE C VALUE '"',
           C_UNIX VALUE 'U',
           C_PC   VALUE 'P',
           C_DASH VALUE '-',
           C_DOWNLOAD_SUCCESS VALUE 'Successfully downloaded file:',
           C_DOWNLOAD_FAILURE VALUE 'Error downloading file:'.

FORM GET_PATH_OS_TYPE USING P_PATH CHANGING P_TYPE.
  SEARCH P_PATH FOR '/'.            "Unix directory
  IF SY-SUBRC = 0.
    P_TYPE = C_UNIX.
  ELSE.
    SEARCH P_PATH FOR '\'.           "PC directory
    IF SY-SUBRC = 0.
      P_TYPE = C_PC.
    ENDIF.
  ENDIF.
ENDFORM. 
* Global data .-end.

   DATA: LT_COMPS  TYPE ABAP_COMPDESCR_TAB,
        WA_COMP   LIKE  LINE  OF LT_COMPS,
        LR_STRUCTDESR  TYPE  REF  TO CL_ABAP_STRUCTDESCR,  "CL_ABAP_TABLEDESCR,
        LT_FLD_DESP  TYPE  TABLE  OF DFIES,
        WA_FLD_DESP  TYPE DFIES.
* lv_line used to keep a formated record temporarily.
   DATA: LV_LINE  TYPE STRING,
        LT_LINES  TYPE  TABLE  OF STRING,
        LV_FILENAME  TYPE STRING,
        LV_FLD_TEMP( 255),
        LV_CODEPAGE  TYPE ABAP_ENCODING.
   DATA: LV_UNIX_OR_PC  TYPE  C,
        LV_APPEND_FLAG  TYPE  C  VALUE  ''.
   FIELD-SYMBOLS: <FS_RECORD>  TYPE  ANY,
                 <FS_FIELD>  TYPE  ANY.

* if itab is empty, do nothing
   CHECK  NOT ITAB  IS  INITIAL.

* get itab definition info
   LOOP  AT ITAB  ASSIGNING <FS_RECORD>.  EXITENDLOOP.
  LR_STRUCTDESR ?=
      CL_ABAP_TYPEDESCR=>DESCRIBE_BY_DATA( <FS_RECORD> ).
  LT_COMPS[] = LR_STRUCTDESR->COMPONENTS[].

* display field discription
   IF DISP_LABEL =  'X'.
* if pass struture name to the FM, get fields description from DDIC
     IF  NOT STRUT_NAME  IS  INITIAL.
       CALL  FUNCTION  'DDIF_FIELDINFO_GET'
         EXPORTING
          TABNAME              = STRUT_NAME
          LANGU                = SY-LANGU
         TABLES
          DFIES_TAB            = LT_FLD_DESP
         EXCEPTIONS
          NOT_FOUND            =  1
          INTERNAL_ERROR       =  2
           OTHERS               =  3.
       IF SY-SUBRC =  0.
         LOOP  AT LT_FLD_DESP  INTO WA_FLD_DESP.
           CONCATENATE LV_LINE FLD_DELI
            C_QOUTATION_MARK WA_FLD_DESP-FIELDTEXT C_QOUTATION_MARK
             INTO LV_LINE.
         ENDLOOP.
       ELSE.
         RAISE STRUT_NAME_ERROR.
       ENDIF.
     ELSE.
* if don't pass structure name to the FM, get fields description from runtime environment
       LOOP  AT LT_COMPS  INTO WA_COMP.
         CONCATENATE LV_LINE FLD_DELI
          C_QOUTATION_MARK WA_COMP-NAME C_QOUTATION_MARK
           INTO LV_LINE.
       ENDLOOP.
     ENDIF.
     IF  NOT LV_LINE  IS  INITIAL.
       SHIFT LV_LINE  LEFT DELETING  LEADING FLD_DELI.
       APPEND LV_LINE  TO LT_LINES.
     ENDIF.
   ENDIF.

* convert itab to flat
* Get each record of ITAB
   LOOP  AT ITAB  ASSIGNING <FS_RECORD>.
     CLEAR LV_LINE.
* Get each field of each record
     LOOP  AT LT_COMPS  INTO WA_COMP.
       CLEAR LV_FLD_TEMP.
       ASSIGN  COMPONENT WA_COMP-NAME
           OF  STRUCTURE <FS_RECORD>
           TO <FS_FIELD>.
* connect the field determine by their filed type.
       IF  NOT <FS_FIELD>  IS  INITIAL.
*       format field to character type
         WRITE <FS_FIELD>  TO LV_FLD_TEMP  LEFT-JUSTIFIED.
*        SHIFT LV_FLD_TEMP LEFT DELETING LEADING SPACE.
         CASE WA_COMP-TYPE_KIND.
           WHEN  'C'  or  'D'  or  'T'.
*           if the type of field equals D/T/C, enclose the value of field with quotation mark
*           if need formatting Date/Time field, place formatting code at here
             CONCATENATE C_QOUTATION_MARK LV_FLD_TEMP C_QOUTATION_MARK  INTO LV_FLD_TEMP.
           WHEN  'I'  or  'N'  or  'P'.
*           if need remove the leading zero of field of type I/N/P/F, place shift code at here
           WHEN  'F'.
             CALL  FUNCTION  'FLTP_CHAR_CONVERSION'
             EXPORTING
              DECIM =  2
               INPUT = <FS_FIELD>
             IMPORTING
              FLSTR = LV_FLD_TEMP.
             CONDENSE LV_FLD_TEMP.
           WHEN  OTHERS.
         ENDCASE.
       ENDIF.
       CONCATENATE LV_LINE FLD_DELI LV_FLD_TEMP  INTO LV_LINE.
     ENDLOOP.
     SHIFT LV_LINE  LEFT DELETING  LEADING FLD_DELI.
     APPEND LV_LINE  TO LT_LINES.
   ENDLOOP.

* determine if downloading to Unix or PC
   PERFORM GET_PATH_OS_TYPE  USING FILENAME
                            CHANGING LV_UNIX_OR_PC.
* download itab to unix server
   IF LV_UNIX_OR_PC = C_UNIX.

     IF ACCESSMODE =  'O'.
       OPEN  DATASET FILENAME  FOR  OUTPUT
                 IN LEGACY  TEXT  MODE  CODE  PAGE CODEPAGE
                 MESSAGE MSG
                IGNORING CONVERSION ERRORS REPLACEMENT CHARACTER  '~'.
     ELSE.
       OPEN  DATASET FILENAME  FOR  APPENDING
                 IN LEGACY  TEXT  MODE  CODE  PAGE CODEPAGE
                 MESSAGE MSG
                IGNORING CONVERSION ERRORS REPLACEMENT CHARACTER  '~'.
     ENDIF.
     IF SY-SUBRC <>  0.
       CONCATENATE MSG C_DASH FILENAME  INTO MSG  SEPARATED  BY SPACE.
       RAISE FILE_CANNOT_OPEN.
     ENDIF.

     LOOP  AT LT_LINES  INTO LV_LINE.
       TRANSFER LV_LINE  TO FILENAME  NO  END  OF  LINE.
       TRANSFER REC_DELI  TO FILENAME  NO  END  OF  LINE.
     ENDLOOP.

     CLOSE  DATASET FILENAME.
     IF SY-SUBRC =  0.
       CONCATENATE C_DOWNLOAD_SUCCESS FILENAME  INTO MSG  SEPARATED  BY SPACE.
     ELSE.
       CONCATENATE C_DOWNLOAD_FAILURE FILENAME  INTO MSG  SEPARATED  BY SPACE.
       RAISE FILE_CLOSE_ERROR.
     ENDIF.

   ELSEIF LV_UNIX_OR_PC = C_PC.
* download itab to pc client
    LV_FILENAME = FILENAME.
    LV_CODEPAGE = CODEPAGE.
     IF ACCESSMODE =  'A'.
      LV_APPEND_FLAG =  'X'.
     ENDIF.
     CALL  METHOD CL_GUI_FRONTEND_SERVICES=>GUI_DOWNLOAD
       EXPORTING
*        BIN_FILESIZE              =
        FILENAME                  = LV_FILENAME
        FILETYPE                  =  'ASC'
         APPEND                    = LV_APPEND_FLAG
        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                  = LV_CODEPAGE
*        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
*      IMPORTING
*        FILELENGTH                =
       CHANGING
        DATA_TAB                  = LT_LINES[]
       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.
       CONCATENATE C_DOWNLOAD_SUCCESS FILENAME  INTO MSG  SEPARATED  BY SPACE.
     ELSE.
       CONCATENATE C_DOWNLOAD_FAILURE
                  FILENAME C_DASH
                  SY-MSGNO C_DASH
                  SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4
                   INTO MSG  SEPARATED  BY SPACE.
       RAISE FILE_DOWNLOAD_ERROR.
     ENDIF.
   ENDIF.
ENDFUNCTION.