Oracle UTL_文件使用附加模式创建重复的头

Oracle UTL_文件使用附加模式创建重复的头,oracle,plsql,utl-file,Oracle,Plsql,Utl File,如何在UTL_文件包中使用“A”ppend模式,但只创建一个头(不重复)?可能吗?我正在追加数据,但每次追加数据时,都会创建重复的标题 我的代码: CREATE OR REPLACE PROCEDURE p_test AS CURSOR c_test IS select blah, blah from dual; v_file UTL_FILE.FILE_TYPE; v_header varchar2(25); BEGIN v_file := UTL_FILE.FOPEN(loc

如何在UTL_文件包中使用“A”ppend模式,但只创建一个头(不重复)?可能吗?我正在追加数据,但每次追加数据时,都会创建重复的标题

我的代码:

CREATE OR REPLACE PROCEDURE p_test AS
CURSOR c_test IS
select blah, blah from dual;

 v_file  UTL_FILE.FILE_TYPE;
 v_header   varchar2(25);

BEGIN
 v_file := UTL_FILE.FOPEN(location  => 'my_dir',
                       filename     => 'filetest09102019.csv',
                       open_mode    => 'A',
                       max_linesize => 32767);
 If file exists = 0 then        --using fgetattr; if I use 1, repeating headers will print
     v_header := 'col1, col2, col3';
     utl_file.put_line (v_file, v_header); 
 Else null; end if;     --unfortunately headers did not print at all when false/0                  
 FOR cur_rec IN c_test LOOP
UTL_FILE.PUT_LINE(v_file, data from c_test );
END LOOP;
UTL_FILE.FCLOSE(v_file);

EXCEPTION
WHEN OTHERS THEN
UTL_FILE.FCLOSE(v_file);
END;

如果多次调用此过程,则每次调用该过程时都会将头追加到文件中

您可以先检查文件是否存在,然后再追加标头,例如,使用fgetattr检测是否要追加文件


或者,修改您的代码,使其只调用一次过程并一次性写入所有数据,而不附加任何内容。

您可以通过一些设计来解决这个问题。目前,您有一个过程,它以追加模式打开文件,将头写入其中,然后将数据写入其中。您需要的是打开文件的子程序。这一程序将是有效的 实现以下逻辑:

  • 测试文件是否存在()
  • 如果该文件不存在,请在写入模式下创建该文件,写入标题,然后关闭该文件
  • 以附加模式打开文件
  • 您现有的过程现在只调用上面描述的例程,并将数据写入打开的文件。以下内容(使用借用和未测试的代码):


    严格来说,
    open\u file()
    在本例中不需要私有过程。但一般来说,我认为在单独的过程中隐藏底层内容是一种好的做法,因为这样可以使代码的主体更易于阅读。此外,我们通常希望在多个位置(针对多种类型的文件)执行此操作,因此便于封装。

    谢谢,Jeffrey。不幸的是,“文件存在”对我不起作用。该文件每天生成一次,带有时间戳——如果该文件已经存在,而不是文件生成本身的第一次运行,它可能会工作(对不起,我在最初的帖子中没有提到它)。除非我的逻辑是错误的(参见上面修改的代码)。我不能使用“write”选项,因为软件正在调用它,需要append选项,否则它将无法工作:(这没有意义-您是否在使用fopen创建文件后立即检查该文件是否存在?在打开该文件进行附加之前,您应该检查该文件是否存在。如果您的文件有多个标题,您必须以某种方式为同一文件名多次调用此过程。我看不到任何其他可能发生的情况,除非还有其他的代码你没有给我们看。我的天,你说得对!!谢谢,它现在可以工作了!谢谢,还没有试过,但这也有道理:D
    CREATE OR REPLACE PROCEDURE p_test AS
    CURSOR c_test IS
    select blah, blah from dual;
    
     v_file  UTL_FILE.FILE_TYPE;
     v_header   varchar2(25)  := 'col1, col2, col3';
    
     function open_file (p_filename in varchar2
                         , p_dirname in varchar2
                         , p_header in varchar2
                          )
       return UTL_FILE.FILE_TYPE
     is
        fh UTL_FILE.FILE_TYPE;
        l_fexists boolean;
        l_flen   number;
        l_bsize  number;
        l_res    number(1);   
      begin
        utl_file.fgetattr(upper(p_DirName), p_FileName, l_fexists, l_flen, l_bsize);
        if not l_fexists  then
          fh := UTL_FILE.FOPEN(location    => p_DirName,
                               filename     => p_FileName,
                               open_mode    => 'W',
                               max_linesize => 32767);     
          utl_file.put_line (fh, p_header); 
          utl_file.fclose(fh);
        end if;
        fh := UTL_FILE.FOPEN(location    => p_DirName,
                             filename     => p_FileName,
                             open_mode    => 'A',
                             max_linesize => 32767);     
        return fh;
      end open_file;
    
    BEGIN
     v_file := open_file 'my_dir', 'filetest09102019.csv', v_header);                  
    
      FOR cur_rec IN c_test LOOP
        UTL_FILE.PUT_LINE(v_file, data from c_test );
      END LOOP;
    UTL_FILE.FCLOSE(v_file);
    
    EXCEPTION
    WHEN OTHERS THEN
    UTL_FILE.FCLOSE(v_file);
    END;