Sql 在循环中调用UTL_FILE.put时发生UTL_FILE.WRITE_错误

Sql 在循环中调用UTL_FILE.put时发生UTL_FILE.WRITE_错误,sql,oracle,plsql,utl-file,Sql,Oracle,Plsql,Utl File,我的PL/SQL过程中有以下代码,我在while循环中的API_XXX.put(它调用utl_file.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_

我的PL/SQL过程中有以下代码,我在while循环中的API_XXX.put(它调用
utl_file.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\u XXX.new\u line
类似于(line是要写入的行数):

我注意到,客户端的put/new_行过程有时会在客户的while循环中引发
UTL_文件。由于未知原因(可能是因为l_长度太大(高达167465)),写入错误

我读 . 我发现这是同样的原因,我的l_xmldoc非常大,当我循环它时,我发现它没有一个新的行终止符,所以缓冲区高达32767,即使我每次都刷新

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


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

只是一个猜测,但是您可以尝试使用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)之间的区别。很容易测试这是否解决了您的问题

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

  • 您的
    fflush
    将无法按预期工作-从:


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

  • t一行是对的,到_CHAR(10)的那行是错的!只需尝试从DUAL中选择字符(10)
  • 您将得到
    10
    ,然后将其与单个字符进行比较。单个字符永远不会是“10”,因为10有两个字符

  • 您的问题很可能是由于XML文件太大而导致缓冲区溢出,但请记住,目标系统上的其他问题也可能导致写入错误,这应该得到处理

  • 解决
    • Quick&Dirty:由于您似乎并不关心性能,因此只需每隔X字节关闭一个文件,然后使用for append重新打开它。因此,只需添加到循环中:

      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\u文件
      不适合处理复杂数据。UTL_文件的唯一用例是以换行符分隔的小文本行。对于其他所有内容,您应该写入原始字节!(这也将允许您对编码进行porper控制,目前这只是小型vanilly幸运猜测)

    • 使用NIO FileChannel编写Java存储过程-快速、安全、美观。。。但是要小心,你的程序可能会运行快10倍


    我建议检查文件内容和编码,或者最好使用UTL\u file.PUT\u RAW。过去我遇到过一些问题,我试图导入excel文件,但导入失败了,没有任何原因,然后我发现问题出在未知符号的情况下。错误的编码也会损坏文件。您好@DARK\u A,您的问题是UTL\u文件。写入错误?我也是
    UTL\u文件。将\u raw
    放入以写入我的文件。一般来说,我先将clob转换为blob,然后再将其写入文件。@user272735,您是否遇到过我的问题?你知道为什么吗?你确定你的解决方案有效吗?请在回答中分享你的代码。我还没有测试过这个问题,但我怀疑在调用UTL_FILE.PUT或PUT_LINE时,输入长度不能超过PL/SQL(32767)中VARCHAR2允许的最大值。你能分享一个代码示例吗?另外,我的api在每次输入一个字符后都会调用fflush。所以我们现在没有写一行,我看到有人对这个答案投了更高的票,你的意思是我把字符(10)替换成chr(10)会有帮助吗?有什么区别?请你解释一下好吗?to_CHAR(10)将10(数字)转换为10(字符)。CHR(10)将十进制转换为字符,在本例中为新行符号。CHR(10)是一个换行符。它与to_char(10)不同,后者将数字10转换为字符串“10”。因此,您的代码永远不会找到新行,也永远不会编写新行(调用utl_file.newline的API代码永远不会被调用)。我相信,这部电影需要新线终结者。修复代码并进行测试非常简单。@t谢谢!因为我无法轻松测试这个问题,所以我将等待客户的反馈。我对你的回答感到惊讶,因为这已经有效多年了……但我仍然会尝试。那么,如果FFLUSH工作正常,如果我只放一个短的varchar,而不放一个新的行终止符?虽然我同意,但你的解决方案对我来说并不适用。1.我不知道打开了哪个文件,因为我的api为这个文件创建了一个随机名称并为我打开了它,所以我无法重新打开该文件。2.我不能把_raw放进去,因为API没有给我这个(同样,我必须使用API来打开文件)。3.Java过程不是选择,我必须在plsql中写入。“通常,写入文件的数据是缓冲的。FFLUSH过程强制将缓冲的数据写入文件。数据必须以换行符终止。”此外,Oracle文档中的这句话让我很困惑。它说,当我刷新时,它会强制将数据写入文件。但是我对每一个字符都进行了填充,并且这个字符没有新的行终止符。为什么在过去的几十年里不存在任何问题?@Jaskey请理解这句话:如果没有换行符,FFLUSH什么都做不了当且仅当存在换行符终止符时,fflush将刷新缓冲区中的所有内容,直到并包括此换行符使用Short varchar不会有问题,因为FCLOSE最终会刷新所有内容!但是,对于长文本,缓冲区将
    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;
    
    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;