Путаница с преобразованием байтов Java в строку для сравнения «меток порядка следования байтов» - PullRequest
3 голосов
/ 24 августа 2011

Я пытаюсь распознать спецификацию для UTF-8 при чтении файла.Конечно, Java-файлы любят иметь дело с 16-битными символами, а символы спецификации имеют восьмибитные байты.

Мой тестовый код выглядит следующим образом:

public void testByteOrderMarks() {
    System.out.println("test byte order marks");

    byte[] bytes = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF, (byte) 'a', (byte) 'b',(byte) 'c'};
    String test = new String(bytes,  Charset.availableCharsets().get("UTF-8"));
    System.out.printf("test len: %s  value %s\n", test.length(), test);
    String three = test.substring(0,3);
    System.out.printf("len %d  >%s<\n", three.length(), three);
    for (int i = 0; i < test.length();i++) {
        byte b = bytes[i];
        char c = test.charAt(i);
        System.out.printf("b: %s %x c: %s %x\n", (char) b, b,  c, (int) c); 
    }
}

и результат:

метки порядка следования байтов
test len: 4 значения? Abc
len 3>? Ab <<br> b:?ef> c:?feff
b:?bb c: a 61
b:?bf c: b 62
b: a 61 c: c 63

Я не могу понять, почему длина "теста" равна 4, а не 6. Я не могу понять,почему я не беру каждый 8-битный байт для сравнения.

Спасибо

Ответы [ 3 ]

2 голосов
/ 24 августа 2011

Не используйте символы при попытке выяснить заголовок спецификации. Заголовок спецификации имеет два или три байта , поэтому вы должны открыть (File) InputStream, прочитать два байта и обработать их.

Между прочим, заголовок XML (<?xml version=... encoding=...>) является чистым ASCII, поэтому его также можно безопасно загружать как поток байтов (хорошо, если только нет спецификации, указывающей, что файл сохраняется с 16-битными символами и не как UTF-8).

Мое решение (см. XMLInputStreamReader DecentXML ) - загрузить первые несколько байтов файла и проанализировать их. Это дает мне достаточно информации для правильного декодирования Reader из InputStream.

1 голос
/ 06 марта 2012

Если вы хотите распознать файл спецификации, лучшее решение (и оно работает для меня) будет использовать библиотеку детектора кодирования Mozilla: http://code.google.com/p/juniversalchardet/ В этой ссылке легко описано, как ее использовать:

import org.mozilla.universalchardet.UniversalDetector;

public class TestDetector {
  public static void main(String[] args) throws java.io.IOException {
    byte[] buf = new byte[4096];
    String fileName = "testFile.";
    java.io.FileInputStream fis = new java.io.FileInputStream(fileName);

    // (1)
    UniversalDetector detector = new UniversalDetector(null);

    // (2)
    int nread;
    while ((nread = fis.read(buf)) > 0 && !detector.isDone()) {
      detector.handleData(buf, 0, nread);
    }
    // (3)
    detector.dataEnd();

    // (4)
    String encoding = detector.getDetectedCharset();
    if (encoding != null) {
      System.out.println("Detected encoding = " + encoding);
    } else {
      System.out.println("No encoding detected.");
    }

    // (5)
    detector.reset();
  }
}

Если вы используете maven, зависимость будет:

<dependency>
    <groupId>com.googlecode.juniversalchardet</groupId>
    <artifactId>juniversalchardet</artifactId>
    <version>1.0.3</version>
</dependency>
1 голос
/ 24 августа 2011

Персонаж - это персонаж. Метка порядка байтов - это символ Unicode U + FEFF. В Java это символ '\uFEFF'. Нет необходимости копаться в байтах. Просто прочитайте первый символ файла, и если он соответствует '\uFEFF', это спецификация. Если он не совпадает, то файл был записан без спецификации.

private final static char BOM = '\uFEFF';    // Unicode Byte Order Mark
String firstLine = readFirstLineOfFile("filename.txt");
if (firstLine.charAt(0) == BOM) {
    // We have a BOM
} else {
    // No BOM present.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...