在 Java 中创建一个文件,以便使用 BCP 和 UTF-16 加载到 SQLServer 2005 中的 nvarchar 字段
-
20-09-2019 - |
题
我想使用 BCP 使用加载程序控制文件加载到具有 nvarchar 字段的 SQL Server 2005 表中。据我了解,SQL Server 2005仅支持UTF-16(我相信它是UTF-16 LE)。该文件正在由 Java 程序输出。我目前的设置方式如下:
XML 格式的 BCP 加载程序文件(使用以下命令创建:
bcp test_table format nul -c -x -T -f test_table.xml -S server
)Java 程序使用以下代码编写输出:
File f = new File("from_java.txt"); String encoding = "x-UTF-16LE-BOM"; OutputStream os = new FileOutputStream(f); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(os, encoding); String theString = "áááááLittle Endian, BOM\r\n"; outputStreamWriter.append(theString); outputStreamWriter.flush(); outputStreamWriter.close();
然后使用以下 bcp 命令:
bcp test_table in from_java.txt -T -f test_table.xml -S server -error error.txt
我在表中得到的是 ÿþá
. 。并不是 áááááLittle Endian, BOM
我尝试了更改参数的几种不同排列:
- 改变我生成加载器控制文件的方式(使用 -n 表示本机数据而不是 -c 表示字符数据...我认为这可能与它有关,但我没有看到插入的数据有任何改进)
- 尝试了几种不同形式的UTF-16编码,包括大端和无BOM的小端,但无济于事
- 尝试在文件中手动输出 BOM,因为我在某处读到 Microsoft 非常喜欢使用 BOM 信息
- 考虑尝试将文件输出为 UCS-2(而不是 UTF-16),因为这(显然)是 BCP 实际读取文件的内容
- 在 bcp 导入上尝试了 -w ,这确实有效,但不能与加载程序格式文件结合使用(有没有办法将告诉 BCP 文件以 UTF-16 编码的任何魔法合并到格式文件中?)
- 如果我在 windows-1252 中输出文件并将该代码页指定为
-c 1252
当我加载文件时选择 bcp (但我不想这样做,因为我会丢失信息,因为 UTF-16 是与 1252 相比可以表示的超集)
有没有人设法使用 UTF-16 数据结合加载程序格式配置文件将 bcp 加载到 nvarchar 字段中?
提前致谢,
-詹姆士
解决方案
我对这些回应确实感到不知所措,但我已经破解了它。
加载文件需要生成 -w
flag,所以生成文件的命令是:
bcp <table> format nul -w -x T -f loader-control-w-format.xml -S <server> -t "||"
这会导致加载程序控制文件看起来有点不同,您会得到如下条目:
<FIELD ID="1" xsi:type="NCharTerm" TERMINATOR="|\0|\0" MAX_LENGTH="1000" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
请注意分隔符列为 |\0|\0
, ,零对应于文件中的额外字节,因为 UTF-16(或微软(错误地)称之为“unicode”)是双字节字符编码。
对于以这种方式处理 BCP 的其他人,请注意以下几点:
- 当 SQLServer 谈到“本机”时,他们指的是本机字符,即重音字符
- 当 SQLServer 谈到 Unicode 时,他们实际上指的是 UTF16(Little Endian)编码方式 统一字符集. 。这就是 -w 的作用
- 当使用 UTF-16 写入要加载到 BCP 的文件时,该文件必须采用 UTF-16 Little Endian 格式,并且不能包含 UTF BOM(因为 BCP 会将其解释为应该加载的字节,并且您的第一条记录将包含BOM,呃!)
以UTF-16格式写出可以通过这种方式加载的文件的Java代码如下:
final File f = new File("C:\\temp\\bcp_prob\\from_java-UTF-16.txt");
//LE with no BOM is important here:
final String encoding = "UTF-16LE";
final OutputStream os = new FileOutputStream(f);
final OutputStreamWriter outputStreamWriter = new OutputStreamWriter(os, encoding);
final String theString = "UTF-16-LE, intermetálico básicos intermetálico película magnética dinámicos||another_col\r\n";
outputStreamWriter.append(theString);
outputStreamWriter.flush();
outputStreamWriter.close();