Oracle PL/SQL需通过目录对象+Java Stored Procedure获取文件列表,再用DBMS_SCHEDULER定时触发;必须创建并授权目录对象,UTL_FILE仅支持已定义的本地路径;Java类须校验路径前缀确保安全。
oracle pl/sql 本身不能直接扫描任意目录,必须依赖目录对象 + java stored procedure 组合实现文件列表获取,再配合 dbms_scheduler 定期触发处理逻辑。绕过这个限制的方案要么不安全(如启用 utl_file_dir),要么不可控(如外部脚本调用),生产环境应避免。
创建并授权 Oracle 目录对象是前提,不是可选步骤
PL/SQL 只能通过 UTL_FILE 访问已定义的目录对象,且路径必须是数据库服务器本地路径(不是客户端或网络共享路径)。常见错误是路径写错、权限漏授或大小写不匹配。
-
CREATE OR REPLACE DIRECTORY ETL_IN AS '/u01/app/oracle/etl/in'—— 路径末尾不加斜杠,ETL_IN是目录名(大写敏感),/u01/app/oracle/etl/in必须由 DBA 在数据库服务器上真实存在且 Oracle 进程有读权限 -
GRANT READ ON DIRECTORY ETL_IN TO etl_user—— 仅需READ(扫描只需列出文件),WRITE不必要,也不建议授予 - 执行后查
SELECT * FROM dba_directories WHERE directory_name = 'ETL_IN'确认存在;查SELECT * FROM dba_tab_privs WHERE table_name = 'ETL_IN'确认授权生效
用 Java Stored Procedure 获取文件列表,不是 UTL_FILE 的功能范围
UTL_FILE 没有 list_files() 或类似接口,它只支持按已知文件名打开单个文件。要动态获取目录下所有 .sql 或 .csv 文件名,必须走 Java 路径。这涉及三步:加载 Java 类、建 SQL 类型、封装函数。
- Java 类需编译后用
CREATE OR REPLACE AND RESOLVE JAVA SOURCE加载,注意类中dir.list()返回null表示路径无效或无读权限,此时抛出SQLException,不是静默失败 -
CREATE OR REPLACE TYPE STRING_LIST AS TABLE OF VARCHAR2(256)—— 类型长度要覆盖最长文件名(含扩展名),否则截断 - 函数声明里
LANGUAGE JAVA NAME 'DirLister.listFiles(java.lang.String) return oracle.sql.ARRAY'中的类名、方法名、参数类型必须与 Java 源码严格一致,大小写敏感
定时扫描 + 入库需拆成两个独立 PL/SQL 单元
不能把“扫描→读文件→解析→插入”全塞进一个作业里。Java 列表函数返回的是 STRING_LIST,而 UTL_FILE 读取单个文件需要显式传入文件名。中间必须用游标循环处理,且每个文件操作都应单独异常捕获。
- 先写一个主过程
proc_scan_and_load:调用get_dir_files('ETL_IN')得到文件名集合 → 用FOR i IN (SELECT column_value f FROM TABLE(...)) LOOP遍历 → 对每个i.f,用UTL_FILE.FOPEN('ETL_IN', i.f, 'R')打开 → 按行读取 →EXECUTE IMMEDIATE执行 SQL 或INSERT插入数据 - 再用
DBMS_SCHEDULER.CREATE_JOB创建作业,job_action指向该过程,start_date和repeat_interval设为所需频率(如'FREQ=DAILY; BYHOUR=2; BYMINUTE=0') - 关键点:每次只处理一个文件,处理完立即
UTL_FILE.FCLOSE;若某文件格式错误,EXCEPTION WHEN OTHERS THEN CONTINUE跳过,避免阻塞后续文件
安全与性能边界必须人工划定,没法靠代码自动兜底
Java Stored Procedure 调用 java.io.File.list() 实际上绕过了 Oracle 的目录访问控制,只要 Java 类能加载成功,就可能被用于读取任意路径(取决于 JVM 权限)。生产环境必须:
- Java 类中硬编码校验路径前缀,比如只允许
p_dir_path LIKE '/u01/app/oracle/etl/%',否则直接抛异常 - 目录对象
ETL_IN的 OS 层权限设为仅 Oracle 用户可读,禁止写入和执行 - 调度作业的
max_runs和max_failures必须设限,防止因文件暴增导致作业长时间挂起











