CLOB数据类型:
CREATE DIRECTORY MY_FILES AS ‘/home/dmdba/temp’;
CREATE TABLE t1(id NUMBER,file_content CLOB,FILE_BLOB BLOB);
CREATE TABLE t1_blob_temp (ID INT PRIMARY KEY, FILE_BLOB BLOB);
CREATE OR REPLACE PROCEDURE SP_INSERT_FILE_TO_CLOB(
p_id INT,
p_dir_name VARCHAR(100),
p_file_name VARCHAR(255),
p_src_csid INT
)
AS
v_clob CLOB;
v_blob BLOB;
v_bfile BFILE;
v_dest_offset INT := 1;
v_src_offset INT := 1;
v_lang_context INT := 0;
v_warning INT;
BEGIN
INSERT INTO t1 (ID, FILE_CONTENT)
VALUES (p_id, EMPTY_CLOB())
RETURNING FILE_CONTENT INTO v_clob;
INSERT INTO t1_blob_temp (ID, FILE_BLOB)
VALUES (p_id, EMPTY_BLOB())
RETURNING FILE_BLOB INTO v_blob;
v_bfile := BFILENAME(p_dir_name, p_file_name);
DBMS_LOB.FILEOPEN(v_bfile, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LOADFROMFILE(
dest_lob => v_blob,
src_file => v_bfile,
amount => DBMS_LOB.GETLENGTH(v_bfile)
);
DBMS_LOB.CONVERTTOCLOB(
dest_lob => v_clob,
src_blob => v_blob,
amount => DBMS_LOB.GETLENGTH(v_blob),
dest_offset => v_dest_offset,
src_offset => v_src_offset,
blob_csid => p_src_csid,
lang_context => v_lang_context,
warning => v_warning
);
DBMS_LOB.FILECLOSE(v_bfile);
COMMIT;
DBMS_OUTPUT.PUT_LINE('文件 ’ || p_file_name || ’ (字符集ID: ’ || p_src_csid || ') 已成功插入到 ID ’ || p_id);
END;
/
CALL SP_INSERT_FILE_TO_CLOB(1, ‘MY_FILES’, ‘f1.txt’, 1);
select * from t1;
导入数据:
– 1. 创建目录对象(目录需先在数据库服务器上存在)
CREATE OR REPLACE DIRECTORY EXPORT_DIR AS ‘/home/dmdba/export/’;
– 2. 授予当前用户读写目录的权限(替换“YOUR_USER”为实际用户名)
GRANT READ, WRITE ON DIRECTORY EXPORT_DIR TO YOUR_USER;
CREATE TABLE t2 (ID INT, FILE_BLOB BFILE);
CREATE OR REPLACE PROCEDURE SP_EXPORT_CLOB_TO_FILE(
p_id INT, – 需导出的CLOB对应的ID(t1表的ID)
p_dir_name VARCHAR(100), – 目录对象名(如 ‘MY_FILES’)
p_output_file VARCHAR(255) – 输出文件名(如 ‘clob_1_export.txt’)
)
AS
– 定义游标:用于读取CLOB(旧版本兼容)
CURSOR c_clob IS
– 关键:加表的所有者前缀(替换 USER_A 为步骤1查询到的 OWNER)
SELECT FILE_CONTENT
FROM SYSDBA.T1 – 这里必须替换为你的 t1 表实际所有者,如 SYS.T1、DMUSER.T1
WHERE ID = p_id;
v_clob CLOB; – 存储读取的CLOB数据
v_file_handle UTL_FILE.FILE_TYPE; – 文件句柄
v_clob_len INT; – CLOB总长度
v_read_offset INT := 1; – CLOB读取起始位置
v_read_size INT := 32767; – 每次读取字节数
v_buffer VARCHAR2(32767); – 读取缓冲区
v_server_charset VARCHAR(30); – 数据库服务器编码
BEGIN
– 1. 从VPARAMETER查询服务器编码
BEGIN
SELECT VALUE INTO v_server_charset
FROM VPARAMETER
WHERE NAME IN (‘SERVER_ENCODING’, ‘CHARSET’);
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_server_charset := ‘UNKNOWN’; – 若查询不到,默认标记为未知
END;
– 2. 用游标读取CLOB(旧版本兼容,避免SELECT INTO问题)
OPEN c_clob; – 打开游标
FETCH c_clob INTO v_clob; – 读取CLOB数据到变量
CLOSE c_clob; – 关闭游标
– 3. 检查是否读取到CLOB(解决“未找到记录”问题)
IF v_clob IS NULL THEN
RAISE_APPLICATION_ERROR(-20002, ‘未找到ID=’ || p_id || ’ 的CLOB记录(检查表Schema是否正确)’);
END IF;
– 4. 检查CLOB是否为空
v_clob_len := DBMS_LOB.GETLENGTH(v_clob);
IF v_clob_len = 0 THEN
RAISE_APPLICATION_ERROR(-20001, ‘ID=’ || p_id || ’ 的CLOB字段为空,无需导出’);
END IF;
– 5. 打开输出文件(4参数版本,旧版本兼容)
v_file_handle := UTL_FILE.FOPEN(
location => p_dir_name,
filename => p_output_file,
open_mode => ‘w’,
max_linesize => v_read_size
);
– 6. 循环分块读取CLOB,写入文件
WHILE v_read_offset <= v_clob_len LOOP
– 若剩余长度不足32767,读取剩余部分
IF (v_read_offset + v_read_size - 1) > v_clob_len THEN
v_read_size := v_clob_len - v_read_offset + 1;
END IF;
– 读取CLOB数据到缓冲区
DBMS_LOB.READ(
lob_loc => v_clob,
amount => v_read_size,
offset => v_read_offset,
buffer => v_buffer
);
– 写入文件
UTL_FILE.PUT(v_file_handle, v_buffer);
v_read_offset := v_read_offset + v_read_size;
END LOOP;
– 7. 关闭文件
UTL_FILE.FCLOSE(v_file_handle);
– 8. 输出成功信息
DBMS_OUTPUT.PUT_LINE(’================ 导出成功 ');
DBMS_OUTPUT.PUT_LINE('目标ID: ’ || p_id);
DBMS_OUTPUT.PUT_LINE('目录对象: ’ || p_dir_name);
DBMS_OUTPUT.PUT_LINE('输出文件: ’ || p_output_file);
DBMS_OUTPUT.PUT_LINE(‘文件字符集: ’ || v_server_charset || ‘(默认服务器编码)’);
DBMS_OUTPUT.PUT_LINE(‘导出大小: ’ || v_clob_len || ’ 字节’);
DBMS_OUTPUT.PUT_LINE(’==========================’);
– 异常处理
EXCEPTION
– 游标相关异常
WHEN CURSOR_ALREADY_OPEN THEN
CLOSE c_clob;
RAISE_APPLICATION_ERROR(-20007, ‘游标已打开,请检查代码逻辑’);
– 其他异常(含UTL_FILE错误)
WHEN OTHERS THEN
– 关闭游标和文件
IF c_clob%ISOPEN THEN
CLOSE c_clob;
END IF;
IF UTL_FILE.IS_OPEN(v_file_handle) THEN
UTL_FILE.FCLOSE(v_file_handle);
END IF;
– 判断错误类型
IF SQLCODE = -29280 THEN – 路径无效
RAISE_APPLICATION_ERROR(-20003, ‘目录对象无效或路径不存在:’ || p_dir_name);
ELSIF SQLCODE = -29282 THEN – 权限拒绝
RAISE_APPLICATION_ERROR(-20004, ‘无权限写入文件(检查目录权限):’ || p_output_file);
ELSIF SQLCODE = -29283 THEN – 模式错误
RAISE_APPLICATION_ERROR(-20005, ‘文件打开模式错误(仅支持 ‘‘r’’/’‘w’’/’‘a’’)’);
ELSE – 通用错误
RAISE_APPLICATION_ERROR(
-20000,
‘导出失败:’ || SQLERRM || '(SQLCODE: ’ || SQLCODE || ‘)’
);
END IF;
END;
/
CALL SP_EXPORT_CLOB_TO_FILE(1, ‘MY_FILES’, ‘clob_1_export.txt’);
文章
阅读量
获赞