Oracle UTL_FILE 文件操作
Oracle UTL_FILE 文件操作
适用版本:Oracle Database 9i / 10g / 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07
1. 概述
UTL_FILE 包用于读写操作系统文件[1]:
2. 配置目录
2.1 创建目录对象
CREATE DIRECTORY data_dir AS '/u01/data';
GRANT READ, WRITE ON DIRECTORY data_dir TO scott;
2.2 查看目录
SELECT directory_name, directory_path
FROM all_directories;
3. 写文件
3.1 基本写
DECLARE
f_handle UTL_FILE.FILE_TYPE;
BEGIN
f_handle := UTL_FILE.FOPEN('DATA_DIR', 'test.txt', 'W');
UTL_FILE.PUT_LINE(f_handle, 'Hello World');
UTL_FILE.PUT(f_handle, 'No newline');
UTL_FILE.NEW_LINE(f_handle);
UTL_FILE.PUTF(f_handle, 'Formatted: %s, %s\n', 'Alice', 30);
UTL_FILE.FCLOSE(f_handle);
END;
3.2 追加模式
f_handle := UTL_FILE.FOPEN('DATA_DIR', 'log.txt', 'A');
4. 读文件
4.1 逐行读
DECLARE
f_handle UTL_FILE.FILE_TYPE;
v_line VARCHAR2(4000);
BEGIN
f_handle := UTL_FILE.FOPEN('DATA_DIR', 'test.txt', 'R');
LOOP
UTL_FILE.GET_LINE(f_handle, v_line);
DBMS_OUTPUT.PUT_LINE(v_line);
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
UTL_FILE.FCLOSE(f_handle);
END;
4.2 文件存在
DECLARE
v_exists BOOLEAN;
v_len NUMBER;
v_block NUMBER;
BEGIN
UTL_FILE.FGETATTR('DATA_DIR', 'test.txt', v_exists, v_len, v_block);
IF v_exists THEN
DBMS_OUTPUT.PUT_LINE('Size: ' || v_len);
END IF;
END;
5. 二进制文件
5.1 写 RAW
DECLARE
f_handle UTL_FILE.FILE_TYPE;
v_data RAW(32767);
BEGIN
f_handle := UTL_FILE.FOPEN('DATA_DIR', 'data.bin', 'WB');
-- WB: 二进制写
UTL_FILE.PUT_RAW(f_handle, v_data);
UTL_FILE.FCLOSE(f_handle);
END;
5.2 读 RAW
DECLARE
f_handle UTL_FILE.FILE_TYPE;
v_data RAW(32767);
BEGIN
f_handle := UTL_FILE.FOPEN('DATA_DIR', 'data.bin', 'RB');
UTL_FILE.GET_RAW(f_handle, v_data, 32767);
UTL_FILE.FCLOSE(f_handle);
END;
6. 文件操作
6.1 重命名
UTL_FILE.FRENAME('DATA_DIR', 'old.txt', 'DATA_DIR', 'new.txt', FALSE);
6.2 复制
UTL_FILE.FCOPY('DATA_DIR', 'src.txt', 'DATA_DIR', 'dst.txt');
6.3 删除
UTL_FILE.FREMOVE('DATA_DIR', 'test.txt');
6.4 属性
DECLARE
v_exists BOOLEAN;
v_len NUMBER;
v_block NUMBER;
BEGIN
UTL_FILE.FGETATTR('DATA_DIR', 'test.txt', v_exists, v_len, v_block);
END;
7. 应用场景
7.1 日志记录
CREATE OR REPLACE PROCEDURE log_message(p_msg VARCHAR2) AS
f_handle UTL_FILE.FILE_TYPE;
BEGIN
f_handle := UTL_FILE.FOPEN('LOG_DIR', 'app.log', 'A');
UTL_FILE.PUT_LINE(f_handle, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') || ': ' || p_msg);
UTL_FILE.FCLOSE(f_handle);
EXCEPTION
WHEN OTHERS THEN
NULL; -- 日志失败不影响主流程
END;
/
7.2 数据导出
CREATE OR REPLACE PROCEDURE export_to_csv AS
f_handle UTL_FILE.FILE_TYPE;
CURSOR c IS SELECT * FROM employees;
BEGIN
f_handle := UTL_FILE.FOPEN('DATA_DIR', 'employees.csv', 'W');
-- 表头
UTL_FILE.PUT_LINE(f_handle, 'ID,Name,Salary');
-- 数据
FOR rec IN c LOOP
UTL_FILE.PUT_LINE(f_handle, rec.id || ',' || rec.name || ',' || rec.salary);
END LOOP;
UTL_FILE.FCLOSE(f_handle);
END;
/
7.3 数据加载
CREATE OR REPLACE PROCEDURE load_from_csv AS
f_handle UTL_FILE.FILE_TYPE;
v_line VARCHAR2(4000);
BEGIN
f_handle := UTL_FILE.FOPEN('DATA_DIR', 'data.csv', 'R');
-- 跳过表头
UTL_FILE.GET_LINE(f_handle, v_line);
LOOP
BEGIN
UTL_FILE.GET_LINE(f_handle, v_line);
-- 解析 CSV
INSERT INTO employees VALUES (...);
EXCEPTION
WHEN NO_DATA_FOUND THEN EXIT;
END;
END LOOP;
UTL_FILE.FCLOSE(f_handle);
COMMIT;
END;
/
8. 常见坑与排错
8.1 ORA-29280: 无效目录路径
-- 1. 检查目录对象
SELECT * FROM all_directories;
-- 2. 检查权限
GRANT READ, WRITE ON DIRECTORY xxx TO user;
8.2 ORA-29283: 文件操作失败
-- 1. 检查文件是否存在
-- 2. 检查 OS 权限
-- 3. 检查路径
8.3 ORA-29285: 文件写入错误
-- 行太长
-- 使用 PUT_RAW 或 分块
8.4 ORA-06502: 缓冲区太小
-- GET_LINE 默认 1024
UTL_FILE.GET_LINE(f_handle, v_line, 32767);
9. 最佳实践
- 使用目录对象:不用 init.ora
- 异常处理关闭文件:避免泄漏
- 批量 PUT_LINE:性能
- 二进制用 RAW:完整
- 检查文件存在:FGETATTR
- 日志用追加模式:保留
- 定期清理日志:空间
- 权限最小化:安全
- 监控文件大小:避免过大
- 测试边界:空文件等
10. 参考资料
[1] Oracle Database PL/SQL Packages and Types Reference 19c, “UTL_FILE” https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/UTL_FILE.html