utl_file不能访问外部表,只能读取操作系统文件;常见错误是ora-29280(目录对象未创建或权限不足),需dba执行create directory并显式授权;csv解析需处理引号、换行等复杂格式,建议用apex_data_parser;大批量插入应使用forall批量绑定并合理commit;超几千行应改用sql*loader或外部表。
utl_file 不能直接“访问外部表”,它读的是操作系统文件;而外部表是数据库对象,两者根本不在同一层。想用 utl_file 处理 csv,就得绕开外部表,走纯 pl/sql 文件 i/o 路线——但这条路容易卡在权限、编码、换行、字段分隔这些细节上。
UTL_FILE.FOPEN 报 ORA-29280:invalid directory path
这是最常遇到的拦路虎,不是路径写错了,而是目录对象没建对或权限没给够。
-
CREATE DIRECTORY必须由 DBA 或有CREATE ANY DIRECTORY权限的用户执行,且路径必须是数据库服务器本地路径(不是你本地电脑的 D:\) - 建完后必须显式授权:
GRANT READ, WRITE ON DIRECTORY utl_dir TO your_user;,public不自动拥有权限 - 调用
utl_file.fopen('UTL_DIR', 'test.csv', 'r')时,第一个参数必须和CREATE DIRECTORY的名字完全一致(大小写敏感,取决于创建时是否加引号) - Oracle 不会校验该路径下是否存在
test.csv,只校验目录对象是否可访问;文件不存在要等GET_LINE时才报NO_DATA_FOUND
CSV 含逗号、换行或双引号时,substr + instr 解析直接崩
原始示例里用 instr(v_text, ',', 1, 1) 找第一个逗号来切字段,这仅适用于最简 CSV(无转义、无嵌套、无多行字段)。真实数据一碰就错。
- 标准 CSV 字段若含逗号,会被包裹在双引号里:
"a,b",c→ 第一个逗号在引号内,不该切 - 字段含换行符(如 Excel 导出的备注列),
UTL_FILE.GET_LINE按行读取会提前截断 - 没有现成的 CSV 解析器,硬写逻辑极易漏 case;建议改用
APEX_DATA_PARSER(18c+ 自带):APEX_DATA_PARSER.PARSE(p_content => BLOB, p_file_name => 'x.csv')返回游标,天然处理引号与换行 - 若坚持用 UTL_FILE,至少把
max_linesize设大些:utl_file.fopen('DIR', 'f.csv', 'r', 32767),避免长行被截断
插入大量 CSV 行时性能骤降,甚至事务超时
每读一行就 INSERT INTO ... VALUES 一次,等于 N 次单行 DML,锁粒度大、日志暴涨、网络往返多。
- 把
INSERT改成批量绑定:FORALL i IN 1..v_urls.COUNT INSERT INTO test VALUES (v_urls(i), v_res_times(i)),需先用集合收集解析结果 - 确保过程末尾有
COMMIT,否则事务不结束,锁一直挂着;但别在循环里频繁COMMIT,会破坏一致性 - 如果 CSV 超过几千行,直接放弃 UTL_FILE,改用
SQL*Loader或外部表 —— 它们走 Oracle 底层批量路径,快一个数量级 -
UTL_FILE是同步阻塞操作,大文件读取期间会卡住 session,不适合交互式场景
真正难的不是写几行 utl_file.get_line,而是应对生产环境里那些带 BOM 的 UTF-8 文件、Windows 和 Linux 混用的 \r\n/\n、字段里藏了不可见控制字符的数据。这些细节不会报错,只会让入库数据悄悄错位——得靠日志打点、逐行 DUMP 字符码、对比原始文件才能揪出来。











