4

我在我的 PL/SQL 过程中有以下代码,我utl_file.put在一个 while 循环中调用了 API_XXX.put(它调用)。l_xmldoc 是来自 getReportXML 函数的 CLOB,它返回 xml clob。

我编写的将 xml 写入文件的代码如下:

l_offset := 1;
    WHILE (l_offset <= l_length)
    LOOP
    l_char := dbms_lob.substr(l_xmldoc,1,l_offset);

    IF (l_char = to_char(10))  ---I also tried if (l_char=chr(10)) but it did not work 
    THEN
        API_XXXX.new_line(API_XXX.output, 1);
    ELSE
        API_XXXX.put(fnd_API_XXX.output, l_char);
    END IF;

    l_offset := l_offset + 1;
    END LOOP;

请注意,API_XXX 是我无法修改的现有包,并且此apifflushput.

API_XXX.put的部分如下(“WHICH”是第一个参数):

         elsif WHICH = API_XXX.OUTPUT then
           temp_file := OUT_FNAME;
           utl_file.put(F_OUT, BUFF);
           utl_file.fflush(F_OUT);

API_XXX.new_line就像(LINES 是要写入的行数):

         elsif WHICH = API_XXX.OUTPUT then
           temp_file := OUT_FNAME;
           utl_file.new_line(F_OUT, LINES);
           utl_file.fflush(F_OUT);

我注意到我客户的 put/new_line 过程有时会在我的客户的 UTL_FILE.WRITE_ERRORwhile 循环中因未知原因引发(可能是由于 l_length 太大(最多 167465))。

我阅读了Oracle PL/SQL UTL_FILE.PUT 缓冲 。我发现这是同样的原因,我的 l_xmldoc 非常大,当我循环它时,我发现它没有新的行终止符,所以即使我每次都 fflush,缓冲区也高达 32767。

那么,我应该如何将 l_xmldoc 转换为带有新行终止符的 varchar。

PS:我确认我的客户使用的是 Oralce 11g

4

2 回答 2

2
  1. 发布您正在使用的 Oracle 版本!或者我们可以随便猜测...

  2. fflush将无法按预期工作-来自文档

    FFLUSH 将挂起的数据物理写入由文件句柄标识的文件。通常,写入文件的数据会被缓冲。FFLUSH 过程强制将缓冲数据写入文件。数据必须以换行符结束。

  3. tbone 绝对正确, TO_CHAR(10) 行是错误的!只需尝试一下SELECT TO_CHAR(10) FROM DUAL;,您就会得到10然后将其与单个字符进行比较。单个字符永远不会是“10”,因为 10 有两个字符!

  4. 您的问题很可能是 XML 文件过大的缓冲区溢出,但请记住,目标系统上的其他问题也可能导致 write_errors,应予以处理。

解决方案

  • Quick&Dirty:由于您似乎并不关心性能,因此您可以每隔 X 字节关闭文件并使用 A 重新打开它以进行追加。所以只需添加到循环中:

    IF MOD( l_offset, 32000 ) = 0
    THEN
      UTL_FILE.FCLOSE( f_out );
      UTL_FILE.FOPEN( out_fpath, out_fname, f_out, 'a', 32767 );
    END IF;
    
  • 为正确的工作使用正确的工具:UTL_FILE不适合处理复杂的数据。UTL_FILE 的唯一用例是小换行符分隔的文本行。对于其他所有内容,您应该写入 RAW 字节!(这也将允许您对编码进行更好的控制,目前这只是小型的幸运猜测)

  • 使用 NIO-Filechannels 编写 Java 存储过程 - 快速、安全、美观……但请注意,您的程序运行速度可能快 10 倍!

于 2014-08-26T12:28:11.610 回答
1

只是一个猜测,但您可以尝试使用 chr(10) 来确定/写入换行符,而不是“to_char(10)”。不确定这是否能解决您的问题,但有时很长的行(没有换行符)可能会导致问题。

例如:

declare
    l_clob clob;
    l_char char;
begin
    l_clob := 'Line 1' || chr(10) || 'Line 2' || chr(10);

    for i in 1 .. DBMS_LOB.GETLENGTH(l_clob)
    loop
        l_char := dbms_lob.substr(l_clob, 1, i);

        if (l_char = chr(10)) then
        --if (l_char = to_char(10)) then
            dbms_output.put_line('Found a newline at position ' || i);
        end if;
    end loop;

end;

注意 chr(10) 和 to_char(10) 之间的区别。很容易测试这是否可以解决您的问题。

于 2014-08-13T18:12:59.223 回答