在上一章介紹expdp/impdp時曾使用過directory這個概念,下面再簡單說明下directory的點點滴滴。
mos上對directory的解釋(266875.1):
(1)、基于服務端 vs 基于用戶端
directory變量指出了expdp導出資料泵或impdp導入資料泵将dump檔案、log檔案以及sql檔案(僅适用于impdp)寫到什麼路徑。
因為導出資料泵和導入資料泵都是基于服務端的,不是基于用戶端的,是以輸出檔案的路徑都是相對于服務端目錄的路徑。資料泵要求将目錄路徑作為一個目錄對象。一個目錄對象将檔案系統的一個目錄路徑映射為一個名稱。
(2)、如何建立一個目錄對象?
為了建立目錄,必須具有dba角色或者賦予了create any directory權限。
示例:
window平台
connect system/manager
create or replace directory my_dir as ‘d:\datapump‘;
create or replace directory my_logdir as ‘e:\logs‘;
grant read, write on directory my_dir to scott;
grant read, write on directory my_logdir to scott;
unix平台
grant create any directory to scott;
connect scott/tiger
create or replace directory my_dir as ‘/usr/datapump‘;
create or replace directory my_logdir as ‘/usr/logs‘;
如果普通使用者被賦予了create any directory權限,那麼使用者就自動具備目錄的read和write權限。
注意:create directory語句不會建立磁盤的真實目錄,如果目錄是無效的,資料泵作業會報錯:
ora-39002: invalid operation
ora-39070: unable to open the log file.
ora-29283: invalid file operation
ora-06512: at "sys.utl_file", line 475
ora-29283: invalid file operation
(3)、如何查詢可用的目錄?
可以使用如下sql查詢具有read和write權限的目錄:
set lines 80
col grantee format a20
col privilege format a10
select directory_name, grantee, privilege
from user_tab_privs t, all_directories d
where t.table_name(+)=d.directory_name
order by 1,2,3;
directory_name grantee privilege
------------------------------ -------------------- ----------
data_pump_dir exp_full_database read
data_pump_dir exp_full_database write
data_pump_dir imp_full_database read
data_pump_dir imp_full_database write
my_dir scott read
my_dir scott write
my_dir system read
my_dir system write
my_logdir scott read
my_logdir scott write
my_logdir system read
my_logdir system write
...
(4)、需要的作業系統權限。
對目錄對象的read或write權限僅僅表示oracle将會替你讀或寫這個檔案。你并沒有通路oracle以外檔案的權限,除非你具備合适的作業系統權限。
(5)、資料泵如何決定檔案的路徑
5.1 如果目錄對象是檔案标示符的一部分,那麼目錄對象指定的路徑就需要使用。在目錄my_dir建立dump檔案的示例:
> expdp scott/tiger dumpfile=my_dir:expdp_s.dmp nologfile=y
5.2 如果目錄對象不代表一個檔案,那麼就需要使用directory變量命名的目錄對象。目錄my_dir中建立dump檔案,目錄my_dir_log中建立日志檔案的示例:
> expdp scott/tiger directory=my_dir dumpfile=expdp_s.dmp \
logfile=my_logdir:expdp_s.log
5.3 如果沒有明确目錄對象,也沒有以directory變量命名的目錄對象,那麼環境變量data_pump_dir将會使用。環境變量是在在運作導出和導入資料泵應用的用戶端系統中使用作業系統指令定義的,配置設定給基于用戶端環境變量的取值必須和基于服務端的目錄對象一緻,且必須首先在伺服器端建立。
目錄my_dir中建立dump檔案和my_dir_log中建立日志檔案的示例:
在使用expdp的用戶端機器上,設定環境變量:
-- on windows, place all expdp parameters on one single line:
c:\> set data_pump_dir=my_dir
c:\> expdp scott/tiger@my_db_alias dumpfile=expdp_s.dmp
注意環境變量data_dump_dir對應的目錄名稱是大小寫敏感的。設定錯誤的data_pump_dir環境變量會報錯,例如:data_pump_dir=my_dir:
ora-39087: directory name my_dir is invalid
5.4 如果之前三種情況都沒有建立目錄對象,作為一個具有權限的使用者(例如具有exp_full_database或imp_full_database角色),那麼資料泵試圖使用預設的基于伺服器端的目錄對象,data_pump_dir。了解資料泵不會建立data_pump_dir目錄對象是非常重要的。僅當授權使用者未使用任何之前提到的機制建立的目錄對象時,才會嘗試使用data_pump_dir。這個預設的目錄對象必須首先由dba建立。不要将這個和同名的基于用戶端的環境變量相混淆。
首先,清空data_pump_dir環境變量:
c:\> set data_pump_dir=
建立data_pump_dir的目錄:
connect system/manager
create or replace directory data_pump_dir as ‘d:\datapump‘;
grant read, write on directory data_pump_dir to scott;
-- on windows, place all expdp parameters on one single line:
c:\> expdp system/manager@my_db_alias dumpfile=expdp_s.dmp
logfile=expdp_s.log schemas=scott
如果scott使用者不是授權使用者,不能使用預設的data_pump_dir。
ora-39145: directory object parameter must be specified and non-null
使用者scott的解決方法:如上面5.3,scott可以設定環境變量data_pump_dir為my_dir:
-- on windows, place all expdp parameters on one single line:
c:\> set data_pump_dir=my_dir
或者這種特定場景下,使用者scott也可以有目錄data_pump_dir的讀和寫權限:
c:\> set data_pump_dir=data_pump_dir
實驗:
建立目錄:create directory utl_file_dir as ‘/oracle/backup‘;
向用目錄對象辨別的檔案寫内容:
sql> declare
2 fhandle utl_file.file_type;
3 begin
4 fhandle := utl_file.fopen(‘utl_file_dir‘, ‘example.txt‘, ‘w‘);
5 utl_file.put_line(fhandle, ‘test write one‘);
6 utl_file.put_line(fhandle, ‘test write two‘);
7 utl_file.fclose(fhandle);
8 end;
9 /
pl/sql procedure successfully completed.
sql> !
ora10g@vm-vmw4131-t$ more /oracle/backup/example.txt
test write one
test write two
讀取使用目錄對象directory辨別的檔案内容:
3 fp_buffer varchar2(4000);
4 begin
5 fhandle := utl_file.fopen(‘utl_file_dir‘, ‘example.txt‘, ‘r‘);
6 utl_file.get_line(fhandle, fp_buffer);
7 dbms_output.put_line(fp_buffer);
8 utl_file.get_line(fhandle, fp_buffer);
9 dbms_output.put_line(fp_buffer);
10 utl_file.fclose(fhandle);
11 end;
12 /
sql> /
此時沒有任何輸出,設定serveroutput:
sql>
set serveroutput on
列印檔案内容。
directory的目就在于可以讓我們在oracle中靈活地對檔案系統中的檔案進行操作。