打算写个存储过程从数据库中抓取想要的SQL语句,然后通过邮件方式发出来。因为发送的邮件默认是文本格式,不太好看,因此想换成html格式。于是乎我要生成一个HTML字符串。本来是想直接放到附件中,但是因为生成的内容可能太大,放到附件不太合适,就需要改成写到文件中。
于是乎,就需要实现把CLOB写入文件的操作,不幸的是遇到不少麻烦。
1. UTL_FILE
写文件,第一反应就是调用UTL_FILE包。但是在调用UTL_FILE.PUT_LINE的时候,老是报如下错误...
ORA-29285: file write error
搞了半天才发现问题出在调用PUT_LINE的时候传入的字符串长度超过了32765个字符!
查看文档看看关于PUT_LINE的说明...
PUT_LINE Procedure
This procedure writes the text string stored in the buffer parameter to the open file identified by the file handle. The file must be open for write operations. PUT_LINE
terminates the line with the platform-specific line terminator character or characters.
See also "PUT_LINE_NCHAR Procedure".
UTL_FILE.PUT_LINE ( file IN FILE_TYPE, buffer IN VARCHAR2, autoflush IN BOOLEAN DEFAULT FALSE);
Table 168-20 PUT_LINE Procedure Parameters
Parameters | Description |
---|---|
|
Active file handle returned by an |
|
Text buffer that contains the lines to be written to the file. |
|
Flushes the buffer to disk after the |
没有看到任何关于buffer长度限制的说明,但是注意到UTL_FILE.FOPEN的说明就会发现问题所在了。
FOPEN Function
This function opens a file. You can specify the maximum line size and have a maximum of 50 files open simultaneously. See also FOPEN_NCHAR Function.
UTL_FILE.FOPEN (
location IN VARCHAR2,
filename IN VARCHAR2,
open_mode IN VARCHAR2,
max_linesize IN BINARY_INTEGER)
RETURN file_type;
Table 168-8 FOPEN Function Parameters
Parameter | Description |
---|---|
|
Directory location of file. This string is a directory object name and is case sensitive. The default is uppercase. Read privileges must be granted on this directory object for the |
|
File name, including extension (file type), without directory path. If a directory path is given as a part of the filename, it is ignored by |
|
Specifies how the file is opened. Modes include: r -- read text w -- write text a -- append text rb -- read byte mode wb -- write byte mode ab -- append byte mode If you try to open a file specifying ' |
|
Maximum number of characters for each line, including the newline character, for this file (minimum value 1, maximum value 32767). If unspecified, Oracle supplies a default value of 1024. |
注意到参数max_linesize最大值为32767个字符(默认为1024), 同时这个限制中包含了换行符(在windows下测试是两个字符长)的字符数。因此在调用put_line的时候传入的字符串长度不能超过32765!
可以进行简单测试...
DECLARE
l_fHandle UTL_FILE.FILE_TYPE;
l_linesize PLS_INTEGER := 32767; -- Change it to 32765
BEGIN
l_fHandle := UTL_FILE.FOPEN('SQL_REPORT_DIR', 'test_file2.txt', 'w', 32767);
UTL_FILE.PUT_LINE(l_fHandle, rpad('x', l_linesize, 'x'), true);
UTL_FILE.FCLOSE(l_fHandle);
EXCEPTION
WHEN OTHERS THEN
IF UTL_FILE.IS_OPEN(l_fHandle) THEN
UTL_FILE.FCLOSE(l_fHandle);
END IF;
RAISE;
END;
/
当把l_linesize改到32765以下的时候,上面的代码才可以正常执行。
这个问题虽然接解决了,但是因为我是想生成HTML文件,因此生成的CLOB是包含HTML标签的, 通过PUT_LINE这样写入文件的话,有可能会把标签拆成了两行,结果造成HTML文件不能正常显示。改咋办呢?
2. DBMS_XSLPROCESSOR.CLOB2FILE
无意中看到“Oracle-Developer.net"中有篇文章提到用DBMS_XSLPROCESSOR.CLOB2FILE一次把CLOB写入到文件中,试了下,相当容易!而且不会像put_line那样会截断CLOB一点点写入,所以最后生成的HTML文件可以正常显示出来。调用方式如下...
DBMS_XSLPROCESSOR.CLOB2FILE(p_clob_content, p_directory_name, TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS') || '_SBVR.html');