服务器端文件处理
如果只指定文件名而没有指定文件路径,则默认会使用系统属性参数DIR_HOME:
跨平台的文件路径
如果想要指定跨平台的文件名,则使用FILE_GET_NAME函数,该函数会将逻辑文件名与逻辑文件路径转换成服务器所运行的平台下的物理文件名与路径,但逻辑文件名与路径需要使用FILE事务码先来定义。
FILE_GET_NAME:能将SAP中通过FILE事务码定义的与操作系统无关(platform-independent)逻辑文件名转换成与平台相关的物理文件名。逻辑文件名通过下面的FILE事务码来配置。
列出服务器上的目录:al11
配置逻辑文件
第一步.建立操作系统的分类:如下面SAP系统已经建立了常用的操作系统分类,如DOS、UNIX、MAC、WIN几类操作系统。
第二步.创建操作系统名。此过程需要费用第一步所创建的操作系统分类
第三步.创建逻辑文件路径。在创建的过程中,引用了第一步创建的操作系统分类(Syntax group),而不是第二步创建的操作系统,这里有怪,而且到目前止第二步创建出来的操作系名用在什么地方。
这一步定义逻辑文件路径会间接(在运行时)使用到了第四步中定义的逻辑文件名(通过<FILENAME>参数在运行时动态的将第四步逻辑文件名转换为实际的物理文件名,<FILENAME>就是在运行时第四步转换过来的物理文件名)
在创建逻辑文件路径时,需要填写物理路径 Physical path,这个物理路径并不是我们平时讲的单纯文件路径,其实它除了前半部分单纯的文件路径外(这里为<P=DIR_GLOBAL>),还是后半部分的文件名(这里为<FILENAME>),所以逻辑文件路径并不只是定义了单纯的文件路径信息,而是某个文件的完整路径信息(路径+文件名)。
在这里Physical path字段可以使用一些预定义的占位符(如这里的<P=DIR_GLOBAL>、<FILENAME>),可以按F1查看所允许的预定符:
Reserved Word Replacement Text
<OPSYS> |
Operating system in call |
<INSTANCE> |
R/3 application instance |
<SYSID> |
R/3 application name in SY-SYSID |
<DBSYS> |
Database system in SY-DBSYS |
<SAPRL> |
R/3 release in SY-SAPRL |
<HOST> |
Host name in SY-HOST |
<CLIENT> |
Client in SY-MANDT |
<LANGUAGE> |
Log on language in SY-LANGU |
<DATE> |
Date in SY-DATUM |
<YEAR> |
Year in SY-DATUM, 4-character |
<SYEAR> |
Year in SY-DATUM, 2-character |
<MONTH> |
Month in SY-DATUM |
<DAY> |
Day in SY-DATUM |
<WEEKDAY> |
Day of the week in SY-FDAYW |
<TIME> |
Time in SY-UZEIT |
<STIME> |
Hour and minute in SY-UZEIT |
<HOUR> |
Hour in SY-UZEIT |
<MINUTE> |
Minute in SY-UZEIT |
<SECOND> |
Seconds in SY-UZEIT |
<PARAM_1> |
External parameter 1这个以及下面两个会使用FILE_GET_NAME函数的PARAMETER_1/2/3参数值来替换 |
<PARAM_2> |
External parameter 2 |
<PARAM_3> |
External parameter 3 |
<P=name> |
Name of a profile parameter这个使用的是RZ11事务码定义的全局参数名 |
(see Report RSPARAM for valid values) |
|
<V=name> |
|
(stored in variable table) |
|
<F=name> |
Return value of a function module这个会使用“FILENAME_EXIT_”+ name 所组成的函数的返回 |
Naming convention for this function module:值来替换这个占位符。以“FILENAME_EXIT_”打头的函数为 |
|
FILENAME_EXIT_name系统提供的,所以如果要使用自定义函数,则要使用以下两个占位 |
|
<Y=name> |
Return value of a function module以下两个占位符的用意是为了上述所预定义的占位不满我们要求 |
Naming convention for this function module:时,我们可以自定义这些占位符,并且这些占位符的取值来自于我 |
|
Y_FILENAME_EXIT_name们自定义的函数,这样可以满足根据自定义业务逻辑来生成文件名 |
|
<Z=name> |
Return value of a function module |
Naming convention for this function module:EXIT单词在SAP里表示出口的意义,出口在很多地方都是这样表 |
|
Z_FILENAME_EXIT_name示的 |
第四步.创建逻辑文件名。该步创建的逻辑文件名与上一将创建出来的逻辑文件路径关联起来
FILE_GET_NAME
使用上面第四步创建的逻辑文件名,服务器所在的操作环境为UNIX。
DATA: encoding TYPE filename-fileformat.
DATA: physical_filename TYPE string.
CALL FUNCTION 'FILE_GET_NAME'
EXPORTING
* CLIENT = SY-MANDT
logical_filename = 'ARCHIVE_BI_PROTOCOL_DATA_FILE'
* OPERATING_SYSTEM = SY-OPSYS
parameter_1 = 'PARAMETER_1'
parameter_2 = 'PARAMETER_2'
parameter_3 = 'PARAMETER_3'
* USE_PRESENTATION_SERVER = ' '
* WITH_FILE_EXTENSION = ' '
* USE_BUFFER = ' '
* ELEMINATE_BLANKS = 'X'
* INCLUDING_DIR = ' '
IMPORTING
* EMERGENCY_FLAG =
file_format = encoding
file_name = physical_filename
* EXCEPTIONS
* FILE_NOT_FOUND = 1
* OTHERS = 2
.
WRITE: / physical_filename, ' ', encoding.
/usr/sap/D06/SYS/global/PARAMETER_1_PARAMETER_3_20111116_145730_PARAMETER_2.ARCHIV
打开文件OPEN DATASET
OPEN DATASET dset FOR access IN mode [position]
[os_addition]
[error_handling].
Dest:目标文件名
sy-subrc |
Description |
0 |
File was opened. |
8 |
Operating system could not open file. |
每个Session最多可以打开100个文件,但具体要看OS。
打开方式access
INPUT
以读取方式打开文件,默认情况下打开时文件指针指向文件开始的地方,如果文件不存在,则sy-subrc为8。如果文件已经打开,文件指针复位到文件的起始位置。
OUTPUT
以写的方式打开文件(但也允许读),如果指定的文件已经存在,则内容会被删除。如果指定的文件不存在,则会创建一个新的文件。
APPENDING
以追加写的方式打开文件。如果文件已经存在,则文件指针会指向文件内容最后,如果文件不存在,则会创建。如果试着通过READ DATASET读取使用FOR APPENDING 方式打开的文件,则sy-subrc为4
UPDATE
以更新的方式打开文件,默认情况下打开时文件指针指向文件开始的地方。如果文件不存在,则sy-subrc为8
文件指针位置position
... AT POSITION pos ...
位置是按照字节来算的,文件的开始位置为0,如果置为-1,则会定位到文件末尾。
请注意以下特殊情况:
1、 在读取文件时,如果 pos 的值大于了文件的长度,将读取不到数据。
2、 在写文件时,如果文件指针指向了文件开始的后面的某个位置上,则从文件开始的地方到指定的 pos 止,都会使用0来填充。
3、 如果是在APPEND模式打开文件,则会忽略到 pos ,仍然从文件的最末开始附加。
4、 如果是修改文件,并且 pos 的值大于了文件的长度,则从文件末到 pos 位置都会设置成0,更新的的内容会从pos向后写。
注,该选项不能与FILTER选项同时使用。
由于文件可以大于2GB,所以 pos 要使用 P 类型来定义,而不能再使用 I 类型。
文件指定位置可以使用SET DATASET来修改。
在对文本文件进行指针定位时,要考虑到文件头部是否带有BOM,以及end-of-line marking。
打开模式mode
... {BINARY MODE}
| {TEXT MODE encoding [linefeed] }...
二进制模式BINARY MODE
If you read from or write to a file that is open in binary mode, the data is transferred byte by byte.When writing to a binary file, the binary content of a data object is transferred in unchanged form(使用未转换形式) into the file. When reading from a binary file, the binary content of the file is transferred in unchanged form into a data object.
字符模式TEXT MODE encoding [linefeed]
If the data type is character-type and flat(如果C类型), trailing blanks are cut off. In the data type string, trailing blanks are not cut off.
If you read from or write to a file that is open in text mode, the data is transferred line by line
如果没有指定行结束尾符linefeed,则默认使用当前服务器所在平台的行结尾符。
读取文件时,是以行为单位一行一行的读取。
行结尾符可以通过linefeed专门指定。
在Unicode 系统中,只有character-type的数据对象才能用来传输Text文件。
在Unicode 系统中,必须指定encoding。
字符编码encoding
... ENCODING { DEFAULT
| {UTF-8 [SKIPPING|WITH BYTE-ORDER MARK]} } ...
l DEFAULT
在Unicode 系统中,默认使用UTF-8编码
l UTF-8
可以使用CL_ABAP_FILE_UTILITIES的CHECK_UTF8方法来文件是否是UTF-8编码的文件
另外,CL_ABAP_FILE_UTILITIES的CHECK_FOR_BOM方法可以用来检测文件头部是否带有字节序,而CREATE_UTF8_FILE_WITH_BOM方法可以创建一个带有UTF-8字节序的文件。
注:在SAP中,A UTF-16 file can only be opened as a binary file.
byte order mark (BOM):字节序,UTF-8的BOM为EF BB BF。
l ... SKIPPING BYTE-ORDER MARK
只允许FOR INPUT or FOR UPDATE时使用,如果有BOM,则在读取或更新时会忽略掉BOM,即在读取时文件指针会设置在BOM的后面。如果省略掉该选项,则BOM会当作普通文件内容来处理。
l ... WITH BYTE-ORDER MARK
该选项只允许在FOR OUTPUT情况下使用,并且会向文件头部插入BOM,如果没有加上该选项,则不会插入。
注:BYTE-ORDER MARK 选项不能与AT POSITION pos同时使用。
当使用UTF-8读取一个文件时,推荐使用SKIPPING BYTE-ORDER MARK选项,以防BOM被当作普通文件内容读取出来;另外,为了使所有阅读器都可以读取SAP创建的UTF-8格式文件,推荐使用WITH BYTE-ORDER MARK选项。
换行符linefeed
... WITH { NATIVE
| UNIX
| WINDOWS } LINEFEED ...
line end marker:行结束标记
CRLF:Carriage-Return Line-Feed ,就是回车(CR, ASCII 13, \r) 换行(LF, ASCII 10, \n)。这两个ACSII字符不会在屏幕有任何输出,但在Windows中广泛使用来标识一行的结束。而在Linux/UNIX系统中只有换行符。许多网络协议,包括HTTP也使用CRLF来表示每一行的结束。CR和LF是在计算机终端还是电传打印机的时候遗留下来的东西。电传打字机就像普通打字机一样工作。在每一行的末端,CR命令让打印头回到左边。LF命令让纸前进一行。虽然使用卷纸的终端时代已经过去了,但是,CR和LF命令依然存在,许多应用程序和网络协议仍使用这些命令作为分隔符。
如果当指定了linefeed选项后,则全局参数abap/NTfmode(RZ11)会忽略,同时TYPE attr选项不能使用。
如果没有指定该选项,则line end marker依赖于平台:
1、The line end marker for Unix is "LF".
2、 The line end marker for MS Windows is "CRLF".然而,如果是在MS Windows操作系统下,则全局属性参数abap/NTfmode可以决定使用"LF"还是"CRLF",如果该参数的值为"b",则使用"LF";如果为"t"或者初始值,则使用"CRLF"。另外abap/NTfmode可以覆盖TYPE attr选项。如果在没有使用linefeed选项,又没有使用TYPE attr选项时,打开一个文件时会搜索第一行的line end marker ("LF" or "CRLF"),并用作整个文件中,如果没有找到,则会使用abap/NTfmode设置的值。
如果使用了WITH NATIVE|SMART|UNIX|WINDOWS LINEFEED选项,这些设置还可以使用SET DATASET语句来修改这些设置,如果没有使用,则line end marker不能使用SET DATASET语句来修改line end marker。
可以通过GET DATASET语句获取当前正在使用的line end marker。
l WITH NATIVE LINEFEED
根据当前服务器所在的操作系统来决定。i.e. "LF" for Unix OS390 or OS400, and "CRLF" for MS Windows.
l WITH UNIX LINEFEED
固定使用The line end marker is set to "LF",即文件的每行(一个TRANSFER ...TO ...语句就表示向文件写一行)都会以“0A”结尾。
l WITH WINDOWS LINEFEED
固定使用The line end marker is set to "CRLF",即文件的每行(一个TRANSFER ...TO ...语句就表示向文件写一行)都会以“0D0A”结尾。
操作系统选项os_addition
... [TYPE attr]
[FILTER opcom] ... .
TYPE
没有实质上的用处
FILTER
将输入输出流过滤。opcom为服务器相应的所在操作系统的命令串。
通常情况下,我们是从标准的STDOUT、STDIN管道读取或写入数据,如果我要对数据进行压缩之类的动作,则可以加上过滤器。
注:不能与AT POSITION 、 FOR UPDATE选项同时使用。
下面在Unix系统中,对数据输入时进行压缩,在输出时进行解压操作:
DATA file TYPE string VALUE `/usr/test.Z`.
OPEN DATASET file FOR OUTPUT IN BINARY MODE
FILTER 'compress'.
...
CLOSE DATASET file.
OPEN DATASET file FOR INPUT IN BINARY MODE
FILTER 'uncompress'.
...
CLOSE DATASET file.
出错处理error_handling
... [MESSAGE msg]
[IGNORING CONVERSION ERRORS]
[REPLACEMENT CHARACTER rc] ... .
该选项允许你接收操作系统的消息,压制异常信息,以及定义出错时未知字符的替换字符。不能转换的字符会默认会使用“#”替换,除非使用REPLACEMENT CHARACTER指定。
DATA mess TYPE string.
OPEN DATASET `` FOR INPUT IN BINARY MODE MESSAGE mess.
IF sy-subrc = 8.
WRITE: / mess.
ENDIF.
No such file or directory
写文件TRANSFER
TRANSFER dobj TO dset [LENGTH len]
[NO END OF LINE].
DATA: file TYPE string VALUE `flights.dat`,
wa TYPE spfli.
FIELD-SYMBOLS <fs_hex> TYPE x.
OPEN DATASET file FOR OUTPUT IN BINARY MODE.
SELECT *
FROM spfli
INTO wa.
ASSIGN wa TO <fs_hex> CASTING.
"写进去的是二进制,打开文件看到的会是乱码
TRANSFER <fs_hex> TO file.
ENDSELECT.
CLOSE DATASET file.
LENGTH选项:
决定了多少个字符或多少个字节将被写入到文件中。如果len的值大于了dobj数据对象所存储的字符或字节数时,则使用十六进制0或者空格来替换缺失的字节或字符(至于是字节还是字符则依赖于文件打开模式)
NO END OF LINE选项:
用来控制是否在以文本模式写入文件时,在每次传输完后是否加上换行符。
如果是使用文本模式打开并写入文件时,默认就会在每次传输完成后加上换行符。
读取READ DATASET
READ DATASET dset INTO dobj [MAXIMUMLENGTH mlen][[ACTUAL] LENGTH alen]
如果没有指定MAXIMUM LENGTH或者指定的为负数,则每次读取多少数据依赖于OPEN DATASET语句所采用的打开模式:如果是以文本模式打开,则每次读取一行数据,如果是以BIN模式打开,则尽可能多的数据并能填满dobj,如果指定了MAXIMUM LENGTH则每次读取mlen个字符(或字节)。
sy-subrc |
Meaning |
0 |
Data was read without reaching end of file.读到了数据并且没有达到文件尾 |
4 |
Data was read and the end of the file was reached or there was an attempt to read after the end of the file.读到了数据且到达了文件尾,或者达到文件尾后再试着读取 |
DATA: file TYPE string VALUE `flights.dat`,
wa TYPE spfli.
FIELD-SYMBOLS <hex_container> TYPE x.
OPEN DATASET file FOR INPUT IN BINARY MODE.
ASSIGN wa TO <hex_container> CASTING.
DO.
"由于没有使用MAXIMUM LENGTH选项,所以每次读取的最大字节数
"由<hex_container>所占字节数决定
READ DATASET file INTO <hex_container>.
IF sy-subrc = 0.
WRITE: / wa-carrid,
wa-connid,
wa-countryfr,
wa-cityfrom,
wa-cityto,
wa-fltime,
wa-distance.
ELSE.
EXIT.
ENDIF.
ENDDO.
CLOSE DATASET file.
修改上面程序,每次读取时指定所读取的最大字节数:
DATA: file TYPE string VALUE `flights.dat`,
"缓冲器,用来每次读取的码流
hex_container TYPE x LENGTH 1000,
len TYPE i.
FIELD-SYMBOLS <spfli> TYPE spfli.
"获取<spfli>所占内存的字节数,即为spfli结构类型所占内存大小
DESCRIBE FIELD <spfli> LENGTH len IN BYTE MODE.
OPEN DATASET file FOR INPUT IN BINARY MODE.
"以spfli类型的视图来看待(操作)缓冲器
ASSIGN hex_container TO <spfli> CASTING.
DO.
"每次读取指定的长度:len
READ DATASET file INTO hex_container MAXIMUM LENGTH len.
IF sy-subrc = 0.
"将读取的二进数据以spfli结构类型的视图展示
WRITE: / <spfli>-carrid,
<spfli>-connid,
<spfli>-countryfr,
<spfli>-cityfrom,
<spfli>-cityto,
<spfli>-fltime,
<spfli>-distance.
ELSE.
EXIT.
ENDIF.
ENDDO.
CLOSE DATASET file.
关闭文件 CLOSE DATASET
CLOSE DATASET dset.
删除文件 DELETE DATASET
DELETE DATASET dset.