SAP R/3 форум ABAP консультантов
Russian ABAP Developer's Club

Home - FAQ - Search - Memberlist - Usergroups - Profile - Log in to check your private messages - Register - Log in - English
Blogs - Weblogs News

Read and Write DIF Files



 
Post new topic   Reply to topic    Russian ABAP Developer's Club Forum Index -> Programming Techniques | Приемы программирования
View previous topic :: View next topic  
Author Message
admin
Администратор
Администратор



Joined: 01 Sep 2007
Posts: 1636

PostPosted: Sun Nov 04, 2007 4:45 pm    Post subject: Read and Write DIF Files Reply with quote

Read and Write DIF Files
This program contains the code to read/write DIF files from ABAP.

The DIF File Structure

DIF (Data Interchange Format) is a program-independent method of storing data. DIF files are ASCll text files. The format uses a brief line length to make the files as universally compatible as possible with application software, languages, operating systems and computer hardware.

A DIF file is oriented towards row-and-column data, such as a spreadsheet or data-base manager might produce. Because individual programs may "rotate" the rows and columns, DIF uses the terms vector and tuple. You may generally interpret vector as column and tuple as row. DIF files contain two sections: a file header and a data section.

The DIF Header

There are four required entries in the DIF header, and a number of optional entries. The format of all header entries is

<topic>

<vector> , <numerical>

" <string> "

where

<topic> is a "token," generally 32 characters or fewer.

<vector> is O if specifying the entire file.

<numerical> is O unless a value is specified.

<string> is "" (double quotations with no space between) if it is not used.

The first required item in a DIF file is the title. For a typical spreadsheet, this would look like:

TABLE

0, <version>

" <title> "

where

<version> is 1.

<title> is the title of the table.

The next required item is the vector count. This specifies the number of vectors (columns). Its format is

VECTORS

0, <count>

where

<count> is the number of vectors. This entry may appear anywhere in the header, but must appear before any entries that specify vector numbers.

The third required item is the tuple count. This specifies the length of the vectors (the number of rows). Its format is

of the vectors (the number of rows). Its format is

TUPLES

0, <count>

where

<count> is the number of tuples.

The final required header item is DATA, which specifies the division of the header information from the data proper. DATA must be the last header item. Its format is:

DATA

0,0

Optional Header Items

Other header entries are optional. DIF Clearinghouse has included optional entries. Some are "standard" as a result of their being used in particular software products. The optional header entry items are: label, comment, field size, time series, significant values, and measure.

- Permits enhanced description of a vector

COMMENT

- Labels a specific <vector> , <line>

" <comment> "

LABEL

<vector> , <line>

" <label> "" <comment> "

where

<vector> is the label <vector> is the commented vector.

<line>'allows for labeling more than one <line> may refer to more than one line.

<label> is the label string.<comment> is the comment string.

- Allocates fixed field sizes for each vector

SIZE

<vector> , <bytes>

where

<vector> is the vector being sized.

<bytes> is the size.

- Specifies the period in a time series:

PERIODICITY

<vector> , <period>

where

<vector> is the specified vector.

<period> is the time period.

- Indicates first year of a time series:- Indicates first period of a time series:

MINORSTART

< VeCtOr # ) , < Start )<vector> , <start>

where

<vector> is the specified vector.

<start> is the start of the time series.

- Indicates the portion of a vector that contains significant values:

TRUELENGTH

<vector> , <length>

where

<vector> is the specified vector.

<length> is the length of that vector that contains significant values.

- Units of measure for a given vectoc

UNITS

<vector> ,0

" <name> "

where

<vector> is the specified vector.

<name> is the name string of the units to be applied.

- Units in which a given vector should be displayed:

DISPLAYUNITS

<vector>,0

" <name> "

where

<vector> is the specified vector.

<name> is the name string of the units used to display the vector. (This may be different from the units used to measure the vector.)

DIF Data Section

The data section is organized in a series of tuples. Data within each tuple is organized in vector sequence. Essentially, using a spreadsheet as a data model, this means one data entry to a cell, in ascending column position, then by ascending row position.

There are two "special data values," BOT (Beginning of Tuple) and EOD (End of Data). BOT marks the start of each tuple. EOD terminates the DIF file.

Each data entry is organized in the following manner

<type>, <numerical>

<string>

where

<type> is one of three different indicators:

special data value

<numeric> is O

<string> is BOT, EOD

O numeric data (signed decimal number)

<numeric> is numeric data

<string> is one of the Value Indicators

(see below)

1 string data

<numeric> is O

<string> is string data

Value Indicator

There are five value indicators to use as the <string> when the <type> = 0:

V value

NA not available

<numeric> must be O

ERROR error condition

<numeric> must be O

TRUE <numeric> is 1

FALSE <numeric> is O

Code:
REPORT ZKBTST30.
*-----------------------------------------------------------------------
* A small program that will convert an internal table to/from DIF
* format (as used in Excel, and many other spreadsheets/databases)
*-----------------------------------------------------------------------
* See program documentation for more details on the DIF format
*-----------------------------------------------------------------------
TABLES:
  PA0002.
DATA: MC_TRUNCATED(1) TYPE C.
DATA: BEGIN OF MSTR_FIELD,
        TYPE(1) TYPE C,
        LENGTH TYPE I,
      END OF MSTR_FIELD.
DATA: BEGIN OF MTAB_DIF OCCURS 0,
        LINE(132) TYPE C, " Make longer if any data element > 132 chars
      END OF MTAB_DIF.
*-- Make sure your internal table is set up properly for the data
*-- that you want to read in from a DIF file.  ie the DIF file and the
*-- internal table have the same number of columns.
DATA: BEGIN OF MTAB_DATA OCCURS 0,
        PERNR LIKE PA0002-PERNR,
        NACHN LIKE PA0002-NACHN,
        VORNA LIKE PA0002-VORNA,
      END OF MTAB_DATA.
START-OF-SELECTION.
*-- Put some data into an internal table
  SELECT PERNR NACHN VORNA UP TO 30 ROWS FROM PA0002
    INTO CORRESPONDING FIELDS OF TABLE MTAB_DATA.
END-OF-SELECTION.
*-- This is how to translate the internal table to DIF format
  PERFORM TRANSLATE_ITAB_TO_DIF
              TABLES
                 MTAB_DATA
                 MTAB_DIF
              USING
                 'SAP'.
*-- Save the internal table so that you can prove it worked by opening
*-- it in Excel or whatever tool you use
  CALL FUNCTION 'WS_DOWNLOAD'
       EXPORTING
            FILENAME            = 'c:\sample.dif'
            FILETYPE            = 'ASC'
       TABLES
            DATA_TAB            = MTAB_DIF
       EXCEPTIONS
            FILE_OPEN_ERROR     = 1
            FILE_WRITE_ERROR    = 2
            INVALID_FILESIZE    = 3
            INVALID_TABLE_WIDTH = 4
            INVALID_TYPE        = 5
            NO_BATCH            = 6
            UNKNOWN_ERROR       = 7
            OTHERS              = 8.
*-- Really should do some error checking here, but that can wait
*-- Show how to convert a DIF file to an internal table.
*-- Got lazy here, and just reused the DIF file created earlier
  PERFORM TRANSLATE_DIF_TO_TABLE
              TABLES
                 MTAB_DIF
                 MTAB_DATA
              USING 'X'
           CHANGING MC_TRUNCATED.
*---------------------------------------------------------------------*
*       FORM TRANSLATE_ITAB_TO_DIF                *
*---------------------------------------------------------------------*
*       Convert an internal table into a DIF file *
*---------------------------------------------------------------------*
*  -->  LTAB_INPUT      - table of values to be converted             *
*  -->  LTAB_OUTPUT_DIF - table to hold DIF file after conversion     *
*  -->  LS_TABLE_NAME   - application that created the file           *
*---------------------------------------------------------------------*
FORM TRANSLATE_ITAB_TO_DIF
     TABLES   LTAB_INPUT
              LTAB_OUTPUT_DIF
     USING    LS_TABLE_NAME LIKE SY-REPID.
  DATA:
    LI_TABLE_ROWS TYPE I,
    LI_TABLE_COLUMNS TYPE I.
  FIELD-SYMBOLS:
    <TABLE_LINE>.
*-- Default application will be the program name if none is provided
  IF LS_TABLE_NAME = SPACE.
    LS_TABLE_NAME = SY-REPID.
  ENDIF.
*-- Make sure that we start with a clean table
  CLEAR LTAB_OUTPUT_DIF.
  REFRESH LTAB_OUTPUT_DIF.
*-- Write the DIF header
  PERFORM WRITE_DIF_HEADER
     TABLES   LTAB_INPUT
              LTAB_OUTPUT_DIF
     USING    LS_TABLE_NAME
     CHANGING LI_TABLE_ROWS
              LI_TABLE_COLUMNS.
  LOOP AT LTAB_INPUT.
    ASSIGN COMPONENT 0 OF STRUCTURE LTAB_INPUT TO <TABLE_LINE>.
    PERFORM WRITE_DIF_DETAILS TABLES LTAB_OUTPUT_DIF
          USING <TABLE_LINE>
                LI_TABLE_COLUMNS.
  ENDLOOP.
  APPEND: '-1,0' TO LTAB_OUTPUT_DIF,   " End of Data
          'EOD'  TO LTAB_OUTPUT_DIF.
ENDFORM.           " TRANSLATE_ITAB_TO_DIF
*---------------------------------------------------------------------*
*       FORM WRITE_DIF_HEADER *
*---------------------------------------------------------------------*
*       Add the DIF header lines to the output table                  *
*---------------------------------------------------------------------*
*  -->  PTAB_INPUT            *
*  -->  PTAB_OUTPUT           *
*  -->  PS_TABLE_NAME         *
*  -->  PI_TABLE_ROWS    - number of rows of data *
*  -->  PI_TABLE_COLUMNS - number of columns of data                  *
*---------------------------------------------------------------------*
FORM WRITE_DIF_HEADER TABLES PTAB_INPUT
         PTAB_OUTPUT
   USING PS_TABLE_NAME
CHANGING PI_TABLE_ROWS
         PI_TABLE_COLUMNS.
  DATA:
    LS_TUPLES(5)         TYPE C,       " Number of columns
    LS_VECTORS(5)        TYPE C,       " Number of rows
    LS_TUPLE_VALUES(11)  TYPE C,
    LS_VECTOR_VALUES(11) TYPE C.
  FIELD-SYMBOLS:
    <L_FS>.
* Get the number of rows in the table
  DESCRIBE TABLE PTAB_INPUT LINES LS_VECTORS.
  PI_TABLE_ROWS = LS_VECTORS.
* Find the number of columns in the table
  WHILE SY-SUBRC = 0.
    ASSIGN COMPONENT SY-INDEX OF STRUCTURE PTAB_INPUT TO <L_FS>.
    CHECK SY-SUBRC = 0.                " Continue only if column found
    LS_TUPLES = SY-INDEX.
  ENDWHILE.
  PI_TABLE_COLUMNS = LS_TUPLES.
* Set up fields for DIF header
  CONCATENATE '"' PS_TABLE_NAME '"' into PS_TABLE_NAME.
  CONCATENATE
    '0,'
    LS_VECTORS
    INTO LS_VECTOR_VALUES.
  CONDENSE LS_VECTOR_VALUES NO-GAPS.
  CONCATENATE
    '0,'
    LS_TUPLES
    INTO LS_TUPLE_VALUES.
  CONDENSE LS_TUPLE_VALUES NO-GAPS.
* Write the DIF file header
  APPEND:
    'TABLE'             TO PTAB_OUTPUT,
    '0,1'               TO PTAB_OUTPUT,
    PS_TABLE_NAME TO PTAB_OUTPUT,
    'VECTORS'           TO PTAB_OUTPUT,
    LS_VECTOR_VALUES    TO PTAB_OUTPUT,
    '""'                to PTAB_OUTPUT,
    'TUPLES'            TO PTAB_OUTPUT,
    LS_TUPLE_VALUES     TO PTAB_OUTPUT,
    '""'                to PTAB_OUTPUT,
    'DATA'              TO PTAB_OUTPUT,
    '0,0'               TO PTAB_OUTPUT,
    '""'                to PTAB_OUTPUT.
ENDFORM.           " WRITE_DIF_HEADER
*---------------------------------------------------------------------*
*       FORM WRITE_DIF_DETAILS*
*---------------------------------------------------------------------*
*       Format each piece of data and append to output table          *
*---------------------------------------------------------------------*
*  -->  PTAB_OUTPUT           *
*  -->  PSTR_TABLE_LINE       *
*  -->  PI_TABLE_COLUMNS      *
*---------------------------------------------------------------------*
FORM WRITE_DIF_DETAILS TABLES PTAB_OUTPUT
   USING PSTR_TABLE_LINE
         PI_TABLE_COLUMNS.
  DATA: LS_FIELD_TYPE(1)   TYPE C,
        LS_OUTPUT_LINE(132) TYPE C.
  FIELD-SYMBOLS:
    <FIELD_NAME>.
  APPEND: '-1,0' TO PTAB_OUTPUT, " Codes to indicate begin of tuple
          'BOT'  TO PTAB_OUTPUT.
  DO PI_TABLE_COLUMNS TIMES.
    ASSIGN COMPONENT SY-INDEX OF STRUCTURE PSTR_TABLE_LINE
          TO <FIELD_NAME>.
    DESCRIBE FIELD <FIELD_NAME> TYPE LS_FIELD_TYPE.
* Different processing for numbers and text
    IF LS_FIELD_TYPE = 'I' OR          " Integer
       LS_FIELD_TYPE = 'P' OR          " Packed
       LS_FIELD_TYPE = 'F' OR          " Floating Point
       LS_FIELD_TYPE = 'S' OR          " 1 byte integer
       LS_FIELD_TYPE = 'B'.            " 2 byte integer
      LS_OUTPUT_LINE = <FIELD_NAME>.
      CONDENSE LS_OUTPUT_LINE.
      CONCATENATE
        '0,'
*       <field_name>
        LS_OUTPUT_LINE
        INTO LS_OUTPUT_LINE.
      APPEND: LS_OUTPUT_LINE TO PTAB_OUTPUT,
              'V'            TO PTAB_OUTPUT.
* If it is not a number format that we recognize, treat it as text
    ELSE.
      APPEND: '1,0'        TO PTAB_OUTPUT,
              <FIELD_NAME> TO PTAB_OUTPUT.
    ENDIF.
  ENDDO.
ENDFORM.           " WRITE_DIF_DETAILS
*---------------------------------------------------------------------*
*       FORM TRANSLATE_DIF_TO_TABLE               *
*---------------------------------------------------------------------*
*       Convert a DIF file to an internal table   *
*---------------------------------------------------------------------*
*  -->  LTAB_DIF              *
*  -->  LTAB_OUTPUT           *
*  -->  SWAP_MEANING_TUPLE_VECTOR - some implementations of the DIF   *
*               file format have the meaning of   *
*               tuple and vector swapped.  Place  *
*               an X in this field if you are     *
*               having problems.                  *
*  -->  LC_DATA_TRUNCATED        - indicates if some data had to be   *
*              truncated when it was put in the   *
*              table.         *
*---------------------------------------------------------------------*
FORM TRANSLATE_DIF_TO_TABLE TABLES LTAB_DIF
               LTAB_OUTPUT
         USING SWAP_MEANING_TUPLE_VECTOR
      CHANGING LC_DATA_TRUNCATED.
  CLEAR LTAB_OUTPUT.
  REFRESH LTAB_OUTPUT.
  FIELD-SYMBOLS:
    <L_FS>.
  DATA:
    LI_ROW                TYPE I,
    LI_COLUMNS            TYPE I,
    LI_INDEX              TYPE I,
    LI_ITAB_COLUMN        TYPE I,
    LI_ITAB_FIELD_LENGTH  TYPE I,
    LI_DIF_DATA_LENGTH    TYPE I,
    LN_DIF_ROWS(1000)     TYPE N,
    LN_DIF_COLUMNS(1000)  TYPE N,
    LN_DUMMY(10)          TYPE N,
    LN_TYPE_IND(2)        TYPE N,      " Type Indicator
    LN_VALUE_IND(32)      TYPE N,      " Value Indicator
    LC_ROW_NAME(7)        TYPE C,      " Name to use for rows/columns
    LC_COL_NAME(7)        TYPE C.      " (Vector/Tuple)
  IF SWAP_MEANING_TUPLE_VECTOR NE SPACE.
    LC_COL_NAME = 'TUPLES'.
    LC_ROW_NAME = 'VECTORS'.
  ELSE.
    LC_COL_NAME = 'VECTORS'.
    LC_ROW_NAME = 'TUPLES'.
  ENDIF.
* Determine how many columns in the dif file
  SEARCH LTAB_DIF FOR LC_COL_NAME.
  IF SY-SUBRC = 0. " Value found
    LI_ROW = SY-TABIX + 1.
    READ TABLE LTAB_DIF INDEX LI_ROW.
    SPLIT LTAB_DIF AT ',' INTO LN_DUMMY LN_DIF_COLUMNS.
  ELSE.
* No tuples Statement found in the DIF file.
    MESSAGE ID 'ZZ' TYPE 'E' NUMBER '0000'
      WITH 'raise no_columns_found'.
  ENDIF.
* Find the number of columns in the table
  WHILE SY-SUBRC = 0.
    ASSIGN COMPONENT SY-INDEX OF STRUCTURE LTAB_OUTPUT TO <L_FS>.
    CHECK SY-SUBRC = 0.                " Continue only if column found
    LI_COLUMNS = SY-INDEX.
  ENDWHILE.
  IF LI_COLUMNS NE LN_DIF_COLUMNS.
*  This exception was probably raised because the program that exported
*  the DIF file swaps the meaning of the TUPLES and VECTORS statements
*  (Excel 5.0 is an example of this).  To correct this problem, simply
*  set the swap_meaning_tuple_vector parameter to 'X'.
*  The other common reason for this exception is that the internal table
*  defined to receive the file has a different number of columns that
*  the DIF file has.
    MESSAGE ID 'ZZ' TYPE 'E' NUMBER '0000'
     WITH 'raise itab_columns_ne_dif_columns'.
  ENDIF.
* Determine how many rows in the dif file
  SEARCH LTAB_DIF FOR LC_ROW_NAME.
  IF SY-SUBRC = 0. " Value found
    LI_ROW = SY-TABIX + 1.
    READ TABLE LTAB_DIF INDEX LI_ROW.
    SPLIT LTAB_DIF AT ',' INTO LN_DUMMY LN_DIF_ROWS.
  ELSE.
* No vectors Statement found in the DIF file.
    message id 'ZZ' type 'E' number '0000'
    WITH 'raise no_rows_found'.
  ENDIF.
* Search for Begin of TUPLES (BOT)
  SEARCH LTAB_DIF FOR 'BOT'.
  IF SY-SUBRC = 0. " BOT found
    LI_INDEX = SY-TABIX - 1.           " Set starting point
  ELSE.
* No BOT found in the DIF file.
    message id 'ZZ' type 'E' number '0000'
      WITH 'raise no_bot_found'.
  ENDIF.
* Add one to LN_DIF_COLUMNS to account for the BOT entries in DIF File
  LN_DIF_COLUMNS = LN_DIF_COLUMNS + 1.
  DO LN_DIF_ROWS TIMES.
    DO LN_DIF_COLUMNS TIMES.
      LI_ITAB_COLUMN = SY-INDEX - 1.   " First entry is BOT, skip it
      READ TABLE LTAB_DIF INDEX LI_INDEX.
      SPLIT LTAB_DIF AT ',' INTO LN_TYPE_IND LN_VALUE_IND.
      CASE LN_TYPE_IND.
      WHEN -1.     " Skip all special commands (BOT)
          LI_INDEX = LI_INDEX + 2.
        WHEN 0. " Numeric Data, 2nd element is actual number
          ASSIGN COMPONENT LI_ITAB_COLUMN
              OF STRUCTURE LTAB_OUTPUT TO <L_FS>.
          <L_FS> = LN_VALUE_IND.
          LI_INDEX = LI_INDEX + 2.
        WHEN 1.    " Text Data
          LI_INDEX = LI_INDEX + 1.
          READ TABLE LTAB_DIF INDEX LI_INDEX.
*         Remove all double quotes
          WHILE SY-SUBRC = 0.
            REPLACE '"' with space into ltab_dif.
            CONDENSE LTAB_DIF.
          ENDWHILE.
          ASSIGN COMPONENT LI_ITAB_COLUMN
              OF STRUCTURE LTAB_OUTPUT TO <L_FS>.
          <L_FS> = LTAB_DIF.
          DESCRIBE FIELD <L_FS> LENGTH LI_ITAB_FIELD_LENGTH.
          LI_DIF_DATA_LENGTH = STRLEN( LTAB_DIF ).
          IF LI_DIF_DATA_LENGTH > LI_ITAB_FIELD_LENGTH.
            LC_DATA_TRUNCATED = 'X'.
          ENDIF.
          LI_INDEX = LI_INDEX + 1.
        WHEN OTHERS.
          .....
      ENDCASE.
    ENDDO.
    APPEND LTAB_OUTPUT.
    CLEAR LTAB_OUTPUT.
  ENDDO.
ENDFORM.           " TRANSLATE_DIF_TO_TABLE
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Russian ABAP Developer's Club Forum Index -> Programming Techniques | Приемы программирования All times are GMT + 4 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


All product names are trademarks of their respective companies. SAPNET.RU websites are in no way affiliated with SAP AG.
SAP, SAP R/3, R/3 software, mySAP, ABAP, BAPI, xApps, SAP NetWeaver and any other are registered trademarks of SAP AG.
Every effort is made to ensure content integrity. Use information on this site at your own risk.