Създайте файл в Java за зареждане в поле nvarchar в SQLServer 2005, като използвате BCP и UTF-16

Искам да използвам BCP за зареждане в таблица на SQL Server 2005 с поле nvarchar, използвайки контролен файл за зареждане. Доколкото разбирам, SQL Server 2005 поддържа само UTF-16 (и вярвам, че е UTF-16 LE). Файлът се извежда от Java програма. Начинът, по който съм го настроил в момента, е следният:

  1. Файл за зареждане на BCP в XML формат (създаден чрез следната команда: bcp test_table format nul -c -x -T -f test_table.xml -S server)

  2. 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();
    
  3. След това използвайте следната 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 кодиране, включително big endian и little endian без BOM, без резултат
  • опитах да изведа BOM ръчно във файла, тъй като прочетох някъде, че Microsoft наистина иска да използва информацията за BOM
  • разгледа опит да изведе файла като UCS-2 (вместо UTF-16), тъй като това е (очевидно) това, в което BCP всъщност чете файла като
  • опитах -w при импортиране на bcp, това наистина работи, но не и във връзка с файл с формат на зареждащото средство (има ли начин да се включи каквато и да е магия, която казва на BCP, че файлът е кодиран в UTF-16 във файла с формат?)
  • Мога да го накарам да работи, ако изведа файла в windows-1252 и посоча тази кодова страница като -c 1252 опция за bcp, когато зареждам файла (но не искам да правя това, тъй като ще загубя информация като UTF-16 е надмножество на това, което може да бъде представено в сравнение с 1252)

Някой успял ли е да накара bcp да се зареди в поле nvarchar, използвайки UTF-16 данни във връзка с конфигурационен файл на формат за зареждане?

Благодаря предварително,

-Джеймс


person James B    schedule 11.02.2010    source източник


Отговори (1)


Бях буквално зашеметен с отговори, но го разбих.

Зареждащият файл трябва да бъде генериран с флаг -w, така че командата за генериране на файла е:

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", както (погрешно) го наричат ​​от Microsoft) е двубайтово кодиране на знаци.

Някои бележки за разума на всеки друг, който се занимава с BCP по този начин:

  • Когато SQLServer говори за „местен“, те имат предвид естествени знаци, т.е. знаци с ударения
  • Когато SQLServer говори за Unicode, това, което всъщност имат предвид, е UTF16 (Little Endian) начин на кодиране на набора символи Unicode. Това е, за което се отнася -w
  • Когато пишете файл за зареждане в BCP с помощта на UTF-16, файлът трябва да бъде във формат UTF-16 Little Endian и не може да съдържа UTF BOM (тъй като BCP ще интерпретира това като байт, който трябва да бъде зареден и първият ви запис ще съдържа BOM, урх!)

Java кодът за изписване на файл в UTF-16, който може да бъде зареден по този начин, е както следва:

    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();
person James B    schedule 15.02.2010