1

我正在编写一个数据库过程来归档包含 BLOB 的 Oracle 9i 表中的数据。由于数据库变得太大,我们的策略是将 BLOB 导出到文件系统(Windows 2000 服务器),在那里可以将它们备份到磁带上,然后截断数据库表。

这是我将 BLOB 保存到磁盘的过程:

      程序 blob_to_file
      (
          -- 要写入文件的 BLOB
          pi_blob 在 BLOB 中,

          -- Oracle 目录对象的名称
          pi_oracle_directory_name IN VARCHAR2,

          -- 目标文件名
          pi_file_name IN VARCHAR2
      )
      是

        v_out_file UTL_FILE.FILE_TYPE;
        v_blob_len 整数;

        v_buffer RAW(32767);
        v_amount BINARY_INTEGER := 32767;
        v_pos 整数:= 1;

      开始

      v_out_file := utl_file.fopen(
          位置 => pi_oracle_directory_name,
          文件名 => pi_file_name,
          open_mode => 'W',
          max_linesize => 32767);

      v_blob_len := dbms_lob.getlength(pi_blob);

      WHILE (v_pos < v_blob_len) 循环

        -- 确保读取的数量不小于剩余的 BLOB 数量
        如果 (v_pos + v_amount) > (v_blob_len + 1) 那么
          v_amount := v_blob_len - v_pos;
        万一;

        -- 将 BLOB 块读入缓冲区
        DBMS_LOB.read(
          lob_loc => pi_blob,
          金额 => v_amount,
          偏移量 => v_pos,
          缓冲区 => v_buffer);

        -- 将缓冲区作为原始数据输出到文件流中
        utl_file.put_raw(
          文件 => v_out_file,
          缓冲区 => v_buffer,
          自动刷新 => 真);

        v_pos := v_pos + v_amount;

      结束循环;

      -- 关闭文件
      UTL_FILE.FCLOSE(v_out_file);

      例外

        其他时候
          -- 如果出现问题,请关闭文件。
          如果 UTL_FILE.is_open(v_out_file) 那么
            UTL_FILE.fclose(v_out_file);
          万一;
          增加;

    结束blob_to_file;

这是我的过程,它遍历表中的 BLOB 并将它们归档:

    程序 archive_letter_table
      (
              -- Oracle 目录对象的名称
              pi_oracle_directory_name IN VARCHAR2
      )
      是

        v_out_filename NVARCHAR2(100);
        v_blob BLOB;

        CURSOR letter_cursor IS
          选择
            letter_id
            ,template_ref
            ,rtf
            ,xml_data
            ,row_version
            ,文件名
            ,document_type
            ,文档
            ,business_entity_id
            ,实体类型
            ,创建日期
            ,sec_function_ref
            ,user_account_ref
            ,热休克蛋白
          从
            fusion.lms_letter;

      开始

        FOR letter_cursor_row in letter_cursor 循环

          如果 letter_cursor_row.document 不是 NULL THEN

            -- 检索 BLOB 并确定其大小
            v_blob := letter_cursor_row.document;
            v_out_filename := CAST(letter_cursor_row.letter_id AS VARCHAR2) || '_' || letter_cursor_row.file_name;

            -- 调用程序将 BLOB 写入文件        
            FILE_UTILS.blob_to_file(v_blob, pi_oracle_directory_name, v_out_filename);

          万一;

        结束循环;

        截断 fusion.lms_letter;

      结束存档_lms_letter_table;

我的两个问题是:

1) 运行“archive_letter_table”过程后,保存到磁盘的文件包含 CR 和 LF 字符,而不仅仅是 LF 字符。我可以手动进行全局搜索/替换来修复它们,但需要一个自动化的 PL/SQL 解决方案。显然有一个 Oracle 错误 #2546782,由于插入 CR 和 LF,“utl_file.put_raw()”的输出不正确。这几乎可以肯定似乎是导致我的问题。它在本页底部提到: http ://www.oracle.com/technology/sample_code/tech/pl_sql/htdocs/x/Utl_File/start.htm

有谁知道我可以在我的 PL/SQL 过程中去掉这些 CRLF 的方法吗?

2) 文件可以是 PDF 或 RTF。保存 PDF 效果很好(CRLF 问题除外),但 RTF 失败并出现以下错误:

从命令的第 5 行开始出错:
开始
fusion.FUSION_ARCHIVE.archive_lms_letter_table('LMS_Letter_Archive_Dir');
结尾;
错误报告:
ORA-29285: 文件写入错误
ORA-06512:在“FUSION.FILE_UTILS”,第 73 行
ORA-06512:在“FUSION.FUSION_ARCHIVE”,第 59 行
ORA-06512: 在第 2 行
29285. 00000 - “文件写入错误”
*原因:无法写入、刷新或关闭文件。
*操作:验证文件是否存在,是否可访问,并且
           它以写入或附加模式打开。

PDF 文件的大小在 69KB 到 219KB 之间,而 RTF应该是633KB。然而,由于上面的错误,它最终在磁盘上是 7KB 并且显然无法读取。通过将原始 RTF 与我的程序尝试保存到磁盘的 RTF 进行比较,我可以看到我的程序未能保存文档的最后一行(这显然很长​​...... 626KB)。我怀疑这与 put_raw 没有处理这么长时间的行有关。

有没有人知道如何解决这个问题?

如果您只有其中一个问题的解决方案,请随时回复。非常感谢任何帮助。

4

3 回答 3

1

至于您的 CR/LF 问题,您似乎已经被预言了(显然是坏事……):

在撰写本文时,还没有变通方法,Oracle 也没有考虑向后移植 Oracle9i 的修复程序。

通过深入研究这些Ask Tom 答案,您可以获得更多见解。在您的情况下,我想开发一个 Java 包将是一个值得考虑的选择。

于 2009-07-29T09:07:27.503 回答
1

我们有一个奇怪的尝试处理 MAC 输出,它只使用 CR。

我们将一个只有 CR 的文件作为 BLOB 加载到数据库中,这没关系。

当我们试图从 BLOB 中写出它时,它会出现与您得到的相同代码的错误!

解决方案是在插入 blob 之前将所有 CR 替换为 CR LF。

然后有趣的是,当 Oracle 将其写出时(DB 在 UNIX 上),它只写出 LF。

然后,在交付用户之前,我们将实际输出文件中的 LF 替换为 CR!

于 2010-02-04T12:35:43.897 回答
0

鉴于您正在处理数据(即尝试将其从数据库中删除),将表(作为 BLOB)复制到更高的数据库版本(或 linux 或其他非 Windows 版本)的可行性是什么。然后你可以从那里运行提取。

于 2009-07-29T22:40:44.457 回答