2014-02-26 52 views
4

我一直在爲這件事工作好幾天,這讓我發瘋。
我有一個使用UTL_FILE寫入文件的oracle程序。 我曾經將我的值存儲爲NVARCHAR2並使用UTL_FILE.PUT_LINE_NCHAR過程編寫我的文件,並且它在(記事本++認爲)UTF8中寫入文件。
該文件然後被另一個程序使用,問題在於所述程序使用WE8MSWIN1252來讀取它,並且由於它是遺留代碼,所以我無法更改該文件。
所以我嘗試使用UTL_FILE.PUT_LINE過程,但該文件仍被視爲UTF8。 我的Oracle文檔中看到NVARCHAR2使用國家字符集(我的是AL16UTF16),所以我試圖用CONVERT方法是這樣的:UTL_FILE和字符集

CONVERT(whatIWantToWrite, 'WE8MSWIN1252', 'AL16UTF16')) 

,並提出了ORA-29298字符集不匹配的異常。 我不明白,我NLS_NCHAR_CHARACTERSET是AL16UTF16爲什麼我不能將它轉換爲WE8MSWIN1252?
是否有另一種使用WE8MSWIN1252編寫文件的方法?

+0

當您從'put_line_nchar'改爲'put_line',你也從'fopen_nchar'改變'打開'? 'whatIWantToWrite'是你的'nvarchar2'列還是一個PL/SQL變量,如果後者是什麼數據類型呢? –

+0

你猜對了。我忘了用'fopen'替換'fopen_nchar'。我不敢相信我在這上面花了太多時間。 無論如何,非常感謝你。 – DeadlyJesus

回答

6

這似乎是因爲你仍然打開文件fopen_nchar。如果我這樣做:

create table t42(str nvarchar2(20)); 
insert into t42 values ('Hello'); 

declare 
    file utl_file.file_type; 
    l_str nvarchar2(20); 
begin 
    select str into l_str from t42; 
    file := utl_file.fopen('<directory>', 'dummy.dat', 'w', 32767); 
    utl_file.put_line(file, convert(l_str, 'WE8MSWIN1252', 'AL16UTF16')); 
    utl_file.fclose(file); 
end; 
/

...然後我得到包含䡥汬一個文件,該文件在Linux file命令報告爲UTF-8 Unicode text;記事本++顯示䡥汬並且說文件是'ANSI as UTF-8'。

如果我改變fopenfopen_nchar

file := utl_file.fopen_nchar('CENSYS_EXPORT_DIR', 'dummy.dat', 'w', 32767); 

...然後我得到ORA-29298: Character set mismatch和一個空文件。

如果我回去fopen但是PL/SQL變量更改爲varchar2

declare 
    file utl_file.file_type; 
    l_str varchar2(20); 
begin 
    select str into l_str from t42; 
    file := utl_file.fopen('<directory>', 'dummy.dat', 'w', 32767); 
    utl_file.put_line(file, convert(l_str, 'WE8MSWIN1252', 'AL16UTF16')); 
    utl_file.fclose(file); 
end; 
/

...然後將文件包含¿¿(在vim)和文件報告爲ISO-8859 text。但記事本++顯示߿並說文件是ANSI。

而不是使用convert,甲骨文discourages,您可以通過原始反彈嗎:

declare 
    file utl_file.file_type; 
    l_str varchar2(20); 
begin 
    select str into l_str from t42; 
    file := utl_file.fopen('<directory>', 'dummy.dat', 'w', 32767); 
    utl_file.put_line(file, 
    utl_raw.cast_to_varchar2(utl_raw.convert(utl_raw.cast_to_raw(l_str), 
     'ENGLISH_UNITED KINGDOM.WE8MSWIN1252', 'ENGLISH_UNITED KINGDOM.UTF8'))); 
    utl_file.fclose(file); 
end; 
/

在Linux中,顯示爲Hello和文件報告爲ASCII text; Notepad ++也將其顯示爲Hello,並再次表示該文件是ANSI。我不清楚這是否會讓你得到你需要的地方......當然,你可能需要不同的語言和語言環境。

但是我的數據庫字符集是AL32UTF8,我的國家字符集是AL16UTF16,所以你可能會看到不同的行爲;如果你的數據庫字符集是WE8MSWIN1252,那麼該文件也將被創建;從the documentation

UTL_FILE預計,UTL_FILE.FOPEN在文本模式下 打開的文件在數據庫中的字符集編碼。它預期在文本模式下打開UTL_FILE.FOPEN_NCHAR的文件 將以UTF8 字符集編碼。

0

也許這是一個選項,可以讓您在將文件寫入光盤之後進行轉換。用Java工具Native-to-ASCII轉換器。

native2ascii -encoding UTF8 my_text_file_utf.txt my_text_file.tmp 
native2ascii -reverse -encoding windows-1252 my_text_file.tmp my_text_file_1252.txt 
0

您可以使用dbms_xslprocessor.clob2file

declare 
    l_str varchar2(20); 
BEGIN 
    select str into l_str from t42; 
    dbms_xslprocessor.clob2file(to_clob(l_str), 'UTLDIR', 'file.txt', 2000); 
END; 

AL16UTF16(CSID)= 2000 WE8MSWIN1252(CSID)= 178 要獲得CSID

SELECT NLS_CHARSET_ID('WE8MSWIN1252') FROM DUAL;