You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle 19c中UTL_FILE写入docx文件后损坏问题求助

Oracle 19c中UTL_FILE导出BLOB生成docx文件损坏问题

环境

Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

问题描述

我们通过存储过程读取tab1表BLOB列中的docx文件数据,使用UTL_FILE写入指定目录。BLOB中的文件可正常下载打开,但写入目录后的文件却损坏,无法正常打开。以下是写入文件的代码片段:

DECLARE
  l_file      UTL_FILE.FILE_TYPE;
  l_buffer    RAW(32767);
  l_amount    BINARY_INTEGER := 32767;
  l_pos       INTEGER := 1;
  l_blob      BLOB;
  l_blob_len  INTEGER;
BEGIN
  
  SELECT blob_file
  INTO   l_blob
  FROM   tab1
  WHERE  id=1;

  l_blob_len := DBMS_LOB.getlength(l_blob);
  
  l_file := UTL_FILE.fopen('DB_DIR','file.docx','wb', 32767);

  
  WHILE l_pos < l_blob_len LOOP
    DBMS_LOB.read(l_blob, l_amount, l_pos, l_buffer);
    UTL_FILE.put_raw(file      => l_file      ,
                                buffer    => l_buffer,
                                autoflush => true);
    l_pos := l_pos + l_amount;
  END LOOP;

  UTL_FILE.fclose(l_file);
  
EXCEPTION
  WHEN OTHERS THEN
    IF UTL_FILE.is_open(l_file) THEN
      UTL_FILE.fclose(l_file);
    END IF;
    RAISE;
END;
/

问题原因与修复方案

文件损坏的核心问题有两个:

  • 循环条件错误:原代码使用l_pos < l_blob_len作为循环条件,当剩余数据长度不足32767字节时,最后一段数据会被跳过,导致文件末尾缺失字节。
  • 固定读取长度未动态调整:最后一次读取时,剩余BLOB数据长度可能小于32767,固定请求32767字节会导致缓冲区数据异常或写入多余空字节。

修复后的完整代码:

DECLARE
  l_file      UTL_FILE.FILE_TYPE;
  l_buffer    RAW(32767);
  l_amount    BINARY_INTEGER := 32767;
  l_pos       INTEGER := 1;
  l_blob      BLOB;
  l_blob_len  INTEGER;
BEGIN
  
  SELECT blob_file
  INTO   l_blob
  FROM   tab1
  WHERE  id=1;

  l_blob_len := DBMS_LOB.getlength(l_blob);
  
  l_file := UTL_FILE.fopen('DB_DIR','file.docx','wb', 32767);

  -- 修正循环条件,动态调整每次读取长度
  WHILE l_pos <= l_blob_len LOOP
    -- 取剩余长度和32767的较小值,避免读取越界
    l_amount := LEAST(32767, l_blob_len - l_pos + 1);
    DBMS_LOB.read(l_blob, l_amount, l_pos, l_buffer);
    UTL_FILE.put_raw(file      => l_file,
                    buffer    => l_buffer,
                    autoflush => true);
    l_pos := l_pos + l_amount;
  END LOOP;

  UTL_FILE.fclose(l_file);
  
EXCEPTION
  WHEN OTHERS THEN
    IF UTL_FILE.is_open(l_file) THEN
      UTL_FILE.fclose(l_file);
    END IF;
    RAISE;
END;
/

验证方式

修复后可通过以下步骤确认文件完整性:

  • 对比原BLOB长度(l_blob_len的值)与生成文件的字节数,两者必须完全一致。
  • 直接打开生成的docx文件,确认内容可正常读取。

内容的提问来源于stack exchange,提问作者RJD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 23:35:21