Posted: Sun Nov 04, 2007 4:45 pm Post subject: Read and Write DIF Files
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
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.