Кодировка символов в CSV
У нас есть требование выбрать данные из таблицы БД Oracle и выгрузить эти данные в файл csv и текстовый файл, разделенный на простой канал. Дайте пользователю ссылку на приложение, чтобы пользователь мог просматривать сгенерированные CSV / текстовые файлы.
Мы занимались анализом, поэтому мы написали сценарий оболочки Unix и вызвали его из приложения Struts / J2ee.
Ранее мы теряли символы китайского и римского алфавита в сгенерированных файлах, и в сгенерированном файле использовалась кодировка us-ascii (проверяется с помощью-> file -i). Позже мы использовали NLS_LANG=AMERICAN_AMERICA.AL32UTF8
и это дало нам файлы формата utf-8.
Но все же символы были бессмысленными, поэтому мы снова попробовали команду iconv и преобразовали файлы utf-8 в кодировку utf-16le.iconv -f utf-8 -t utf-16le $recordFile > $tempFile
Это прекрасно работает для сгенерированного текстового файла. Но с CSV китайские и римские буквы все еще не верны. Теперь, если мы откроем этот CSV-файл в блокноте и введем новую строку, нажав клавишу ввода на клавиатуре, сохраните его. Откройте его в MS-Excel, все символы идут хорошо, включая китайцев и римлян, но теперь текст в одной строке для каждой строки вместо столбцов.
Не уверен, что происходит.
Java-код
PrintWriter out = servletResponse.getWriter();
servletResponse.setContentType("application/vnd.ms-excel; charset=UTF-8");
servletResponse.setCharacterEncoding("UTF-8");
servletResponse.setHeader("Content-Disposition","attachment; filename="+ fileName.toString());
FileInputStream fileInputStream = new FileInputStream(fileLoc + fileName);
int i;
while ((i=fileInputStream.read()) != -1) {
out.write(i);
}
fileInputStream.close();
out.close();
Пожалуйста, дайте мне знать, если я пропустил какие-либо детали. Спасибо всем, что нашли время, чтобы пройти через это.
2 ответа
Был в состоянии решить это. Сначала, как упомянул Аарон, удалили UTF-16LE
кодирование, чтобы избежать будущих проблем и закодированных файлов в UTF-8
, Изменил PrintWriter
в коде Java для OutputStream
и смог увидеть правильные символы в моем текстовом файле.
CSV все еще показывал мусор. Мы узнали, что нам нужно добавить EF BB BF в начале файла как BOM
осведомленное программное обеспечение, как MS-Excel
нужно это Таким образом, изменение кода Java, как показано ниже, помогло csv.
OutputStream out = servletResponse.getOutputStream();
os.write(239); //0xEF
os.write(187); //0xBB
out.write(191); //0xBF
FileInputStream fileInputStream = new FileInputStream(fileLoc + fileName);
int i;
while ((i=fileInputStream.read()) != -1) {
out.write(i);
}
fileInputStream.close();
out.flush();
out.close();
Как всегда с проблемами Unicode, каждый шаг цепочки преобразований должен работать идеально. Если вы допустите ошибку в одном месте, данные будут молча повреждены. Нет простого способа выяснить, где это происходит, вы должны отлаживать код или писать модульные тесты.
Приведенный выше код Java работает, только если файл на самом деле содержит данные в кодировке UTF-8; он не "волшебным образом" выясняет, что находится в файле, и преобразует его в UTF-8. Так что, если файл уже содержит мусор, вы просто добавляете на него ярлык "это UTF-8", но он по-прежнему мусор.
Для вас это означает, что вам нужно создавать контрольные примеры, которые берут известные тестовые данные и перемещают их на каждом этапе цепочки: вставка в базу данных, чтение из базы данных, запись в CSV, запись в текстовый файл, чтение этих файлов и загрузка пользователю.
Для каждого шага вам нужно написать модульные тесты, которые принимают известную строку Unicode, такую как abc öäü
и обрабатывает его, а затем проверяет результат. Чтобы упростить ввод в код Java, используйте "abc \u00f6\u00e4\u00fc"
Вы также можете добавить пробелы в начале и конце строки, чтобы увидеть, правильно ли они сохранены или нет.
file -i
здесь вам мало что поможет, так как он просто делает предположение, что содержит файл. В текстовом файле нет индикатора (данных или метаданных), который говорит "это UTF-8". UTF-16 поддерживает заголовок спецификации для этого, но почти никто не использует UTF-16, поэтому многие инструменты не поддерживают его (правильно).