UTL_FILE和字符集

时间:2014-02-26 12:08:46

标签: oracle plsql character-encoding

我已经做了好几天这件事了,这让我发疯了 我有一个使用UTL_FILE编写文件的oracle过程。 我曾经将我的值存储为NVARCHAR2并使用UTL_FILE.PUT_LINE_NCHAR过程编写我的文件,并将文件写入(notepad ++认为是)UTF8。
该文件然后由另一个程序使用,问题是所述程序使用WE8MSWIN1252读取它,我无法改变它,因为它是遗留代码。
所以我尝试使用UTL_FILE.PUT_LINE程序,但该文件仍被视为UTF8。 我在oracle的文档中看到NVARCHAR2使用了国家字符集(我的是AL16UTF16),所以我尝试使用这样的CONVERT方法:

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

它引发了ORA-29298字符集不匹配异常。 我没理解,我的NLS_NCHAR_CHARACTERSET是AL16UTF16为什么我不能把它转换成WE8MSWIN1252?
是否有另一种使用WE8MSWIN1252编写文件的方法?

3 个答案:

答案 0 :(得分: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; Notepad ++显示䡥汬,并说该文件是'ANSI as UTF-8'。

如果我将fopen更改为fopen_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。但是Notepad ++显示߿并且说该文件是ANSI。

而不是使用convert,哪个Oracle discourages,您可以通过raw跳转它:

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;
/

在显示为Hello的Linux中,文件报告为ASCII text; Notepad ++也将其显示为Hello,并再次表示该文件是ANSI。我不清楚这是否能让你到达你需要的地方......当然,你可能需要一种不同的语言和语言环境。

但我的数据库字符集是AL32UTF8,我的国家字符集是AL16UTF16,所以你可能会看到不同的行为;如果您的数据库字符集是WE8MSWIN1252,那么该文件也将被创建;来自the documentation

  

UTL_FILE期望UTL_FILE.FOPEN以文本模式打开文件   在数据库字符集中编码。它期望文件   在文本模式下由UTL_FILE.FOPEN_NCHAR打开的编码在UTF8中   字符集。

答案 1 :(得分:0)

也许这是一个选项,您可以将文件转换为已写入光盘,例如使用Java工具Native-to-ASCII Converter。

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

答案 2 :(得分: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;