Oracle E-Business Suite (EBS) 常需與作業系統檔案系統互動(報表輸出、介面檔案交換、日誌記錄)。本文詳細說明 CREATE DIRECTORY 權限模型、OS 層面目錄建立與權限設定、UTL_FILE 讀寫實戰與常見錯誤排查。
+------------------+ CREATE DIRECTORY +------------------+
| Oracle Database | -----------------------> | OS File System |
| | DIRECTORY Object | |
| UTL_FILE PKG | READ/WRITE GRANT | /mail_file/ |
| | <---------------------- | data/PROD/ |
+------------------+ OS Permissions +------------------+
^ ^
| |
DB User oracle OS User
-- 必須具備 CREATE ANY DIRECTORY 權限 (通常由 SYS 執行)
CONN / AS SYSDBA
CREATE OR REPLACE DIRECTORY MAIL_FILE_DIR AS '/mail_file/data/PROD';
-- 授權給應用使用者或 PUBLIC (視安全策略而定)
GRANT READ, WRITE ON DIRECTORY MAIL_FILE_DIR TO APPS_USER;
-- 或
GRANT READ, WRITE ON DIRECTORY MAIL_FILE_DIR TO PUBLIC;
雙節點環境下,兩個節點的資料庫皆需執行上述 SQL。目錄物件屬於資料庫字典物件,透過 Data Guard/閃回同步,但建議雙邊手動執行確保一致性。
# 切換至 root 或 oracle 安裝擁有者
cd /
# 建立多層目錄
mkdir -p /mail_file/data/PROD
# 設定權限:確保 oracle OS 使用者可讀寫
chown oracle:oinstall /mail_file/data/PROD
chmod 775 /mail_file/data/PROD # 建議 775,避免 775 安全風險
# 驗證
ls -ld /mail_file/data/PROD
# 輸出應為:drwxrwxr-x 2 oracle oinstall 4096 ... /mail_file/data/PROD
DECLARE
fhandle UTL_FILE.FILE_TYPE;
v_dir VARCHAR2(30) := 'MAIL_FILE_DIR';
v_file VARCHAR2(100) := 'example.txt';
BEGIN
-- 開啟檔案寫入模式 (W = Write, 覆寫)
fhandle := UTL_FILE.FOPEN(v_dir, v_file, 'W', 32767); -- max_linesize 32KB
UTL_FILE.PUT_LINE(fhandle, 'gh test write one');
UTL_FILE.PUT_LINE(fhandle, 'gh test write two');
UTL_FILE.PUT_LINE(fhandle, 'Timestamp: ' || TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
-- 關閉檔案 (強制刷新緩衝區)
UTL_FILE.FCLOSE(fhandle);
DBMS_OUTPUT.PUT_LINE('File written successfully.');
EXCEPTION
WHEN UTL_FILE.INVALID_PATH THEN
DBMS_OUTPUT.PUT_LINE('ERROR: Invalid directory path or object.');
WHEN UTL_FILE.INVALID_MODE THEN
DBMS_OUTPUT.PUT_LINE('ERROR: Invalid open mode.');
WHEN UTL_FILE.WRITE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('ERROR: Write failed (disk full/permissions).');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLERRM);
IF UTL_FILE.IS_OPEN(fhandle) THEN
UTL_FILE.FCLOSE(fhandle);
END IF;
END;
/
DECLARE
fhandle UTL_FILE.FILE_TYPE;
v_buffer VARCHAR2(4000);
v_dir VARCHAR2(30) := 'MAIL_FILE_DIR';
v_file VARCHAR2(100) := 'example.txt';
BEGIN
fhandle := UTL_FILE.FOPEN(v_dir, v_file, 'R', 32767);
LOOP
BEGIN
UTL_FILE.GET_LINE(fhandle, v_buffer);
DBMS_OUTPUT.PUT_LINE(v_buffer);
EXCEPTION
WHEN NO_DATA_FOUND THEN
EXIT; -- 讀取完畢
END;
END LOOP;
UTL_FILE.FCLOSE(fhandle);
EXCEPTION
WHEN UTL_FILE.INVALID_PATH THEN
DBMS_OUTPUT.PUT_LINE('ERROR: Directory object not found or OS path invalid.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR: ' || SQLERRM);
IF UTL_FILE.IS_OPEN(fhandle) THEN
UTL_FILE.FCLOSE(fhandle);
END IF;
END;
/
| 錯誤代碼 | 錯誤訊息 | 根本原因 | 解決方案 |
|---|---|---|---|
| ORA-29280 | invalid directory path | Directory 物件不存在或路徑拼寫錯誤 | 檢查 DBA_DIRECTORIES 路徑大小寫 |
| ORA-29283 | invalid file operation | OS 路徑不存在、權限不足、磁碟滿 | 檢查 OS 目錄存在性、oracle 用戶權限、磁碟空間 |
| ORA-29285 | file write error | 寫入失敗 | 檢查磁碟空間、檔案系統唯讀、inode 耗盡 |
| ORA-29282 | invalid file ID | 檔案控制代碼無效 (未開啟/已關閉) | 檢查 FOPEN 回傳值、FCLOSE 配對 |
| ORA-06512 | at "SYS.UTL_FILE", line 449 | 內部錯誤堆疊 | 參考前置錯誤代碼 (29283 等) |
-- 彈性配置:不同環境 (DEV/UAT/PROD) 僅需修改 Directory 物件路徑
-- 程式碼無需變更
SELECT directory_name, directory_path FROM dba_directories WHERE directory_name = 'MAIL_FILE_DIR';
-- 寫入大量資料時,定期 FFUSH 避免記憶體暴增
UTL_FILE.PUT_RAW(fhandle, UTL_RAW.CAST_TO_RAW(large_blob_chunk), TRUE); -- TRUE = auto flush
-- 或
UTL_FILE.FFLUSH(fhandle);
AUDIT READ, WRITE ON DIRECTORY MAIL_FILE_DIR BY ACCESS;| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| UTL_FILE | 原生 PL/SQL、無額外元件 | 效能較低、需 OS 權限配合 | 中小檔案、報表輸出、介面交換 |
| External Table | SQL 直接查詢、支援並行 | 唯讀、需預知格式 | 大量資料載入、ETL 階段 |
| DBMS_SCHEDULER + Shell | 功能豐富、可呼叫外部程式 | 複雜度高、需憑證管理 | 複雜檔案處理、加密/壓縮 |
| Oracle File Watcher (12c+) | 事件驅動、自動觸發 | 版本限制 | 即時檔案處理、自動化流程 |
UTL_FILE 仍是 PL/SQL 操作 OS 檔案的基石,但生產環境務必建立「目錄物件管理規範」:集中登記、定期審計、權限最小化、路徑隔離。EBS 環境更應配合 Apps 模組標準目錄結構 ($APPLCSF/$APPLLOG 等) 統一規劃。