Crie um arquivo em Java para carregar em um campo Nvarchar no SQLServer 2005 usando o BCP e o UTF-16
-
20-09-2019 - |
Pergunta
Quero usar o BCP para carregar em uma tabela SQL Server 2005 com um campo Nvarchar usando um arquivo de controle de carregador. Pelo que entendi, o SQL Server 2005 suporta apenas o UTF-16 (e acredito que é UTF-16 LE). O arquivo está sendo produzido por um programa Java. A maneira como eu tenho atualmente configurada é a seguinte:
Um arquivo de carregador BCP do formato XML (criado usando o seguinte comando:
bcp test_table format nul -c -x -T -f test_table.xml -S server
)Um programa Java usando o seguinte código para escrever a saída:
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();
Em seguida, usando o seguinte comando bcp:
bcp test_table in from_java.txt -T -f test_table.xml -S server -error error.txt
O que eu recebo na tabela é ÿþá
. e não áááááLittle Endian, BOM
Eu tentei algumas permutações diferentes de mudança de parâmetros:
- Alterar a maneira como eu gero o arquivo de controle do carregador (usando -n para dados nativos em vez de -c para dados de caracteres ... acho que isso pode ter algo a ver com isso, mas não vi nenhuma melhoria nos meus dados inseridos)
- Tentei várias formas diferentes da codificação UTF-16, incluindo Big Endian e Little Endian sem nascimento, sem sucesso
- Tentei gerar o nascimento manualmente no arquivo enquanto leio em algum lugar que a Microsoft realmente gosta de usar informações da BOM
- analisou a tentativa de produzir o arquivo como UCS-2 (em vez de UTF-16) como é (aparentemente) o que o BCP está realmente lendo o arquivo como
- Tentado -w na importação do BCP, isso funciona, mas não em conjunto com um arquivo de formato de carregador (existe uma maneira de incorporar qualquer magia dizer ao BCP que o arquivo é codificado no UTF -16 no arquivo de formato?)
- Eu posso fazê-lo funcionar se eu produzir o arquivo no Windows-1252 e especificar essa correção de codificação como um
-c 1252
Opção para o BCP quando carrego o arquivo (mas não quero fazer isso, pois vou perder informações, pois o UTF-16 é um superconjunto do que pode ser representado em comparação com 1252)
Alguém conseguiu fazer com que o BCP carregue em um campo Nvarchar usando dados UTF-16 em conjunto com um arquivo de configuração de formato de carregador?
Desde já, obrigado,
-James
Solução
Fiquei literalmente desapontado com as respostas, mas eu a quebrei.
O arquivo de carregador precisa ser gerado com um -w
Flag, então o comando para gerar o arquivo é:
bcp <table> format nul -w -x T -f loader-control-w-format.xml -S <server> -t "||"
Isso leva a um arquivo de controle de carregador que parece um pouco diferente, você obtém entradas como:
<FIELD ID="1" xsi:type="NCharTerm" TERMINATOR="|\0|\0" MAX_LENGTH="1000" COLLATION="SQL_Latin1_General_CP1_CI_AS"/>
Observe que o delimitador está listado como |\0|\0
, os zeros correspondem ao byte extra no arquivo como UTF-16 (ou apenas "unicode" como Microsoft (erroneamente) chama) é uma codificação de caracteres de byte duplo.
Algumas notas para a sanidade de qualquer outra pessoa que lide com o BCP dessa maneira:
- Quando o sqlserver fala de "nativo", eles significam personagens nativos, ou seja, personagens acentuados
- Quando o sqlserver fala de unicode, o que eles realmente querem dizer é a maneira UTF16 (Little Endian) de codificar o Unicode caracteres. É isso que o -w pertence a
- Ao escrever um arquivo para carregar no BCP usando o UTF-16, o arquivo deve estar no formato Little Endian UTF-16 e não pode conter um UTF BOM (como o BCP interpretará esse byte que deve ser carregado e seu primeiro registro conterá o nascido, urgh!)
O código Java para escrever um arquivo no UTF-16 que pode ser carregado dessa maneira é o seguinte:
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();