Ich versuche, CSV-Dateien mit Java zu lesen. Einige der Dateien haben am Anfang möglicherweise eine Bytereihenfolge, aber nicht alle. Wenn vorhanden, wird die Bytereihenfolge zusammen mit dem Rest der ersten Zeile gelesen, was zu Problemen beim Vergleichen von Zeichenfolgen führt.
Gibt es eine einfache Möglichkeit, das Byte-Bestellzeichen zu überspringen, wenn es vorhanden ist?
Vielen Dank!
Antworten:
BEARBEITEN : Ich habe eine ordnungsgemäße Version auf GitHub erstellt: https://github.com/gpakosz/UnicodeBOMInputStream
Hier ist eine Klasse, die ich vor einiger Zeit codiert habe. Ich habe gerade den Paketnamen vor dem Einfügen bearbeitet. Nichts Besonderes, es ist den in der Fehlerdatenbank von SUN veröffentlichten Lösungen ziemlich ähnlich. Integrieren Sie es in Ihren Code und es geht Ihnen gut.
Und Sie verwenden es so:
quelle
Die Apache Commons IO- Bibliothek verfügt über eine
InputStream
, die Stücklisten erkennen und verwerfen kann:BOMInputStream
(javadoc) :Wenn Sie auch unterschiedliche Codierungen erkennen müssen, können Sie auch zwischen verschiedenen Byte-Reihenfolge-Markierungen unterscheiden, z. B. UTF-8 vs. UTF-16 Big + Little Endian - Details unter dem obigen Doc-Link. Sie können dann das Erkannte verwenden
ByteOrderMark
, um aCharset
zum Dekodieren des Streams auszuwählen . (Es gibt wahrscheinlich eine optimierte Möglichkeit, dies zu tun, wenn Sie all diese Funktionen benötigen - vielleicht den UnicodeReader in der Antwort von BalusC?). Beachten Sie, dass es im Allgemeinen keine sehr gute Möglichkeit gibt, die Codierung einiger Bytes zu erkennen. Wenn der Stream jedoch mit einer Stückliste beginnt, kann dies anscheinend hilfreich sein.Bearbeiten : Wenn Sie die Stückliste in UTF-16, UTF-32 usw. erkennen müssen, sollte der Konstruktor wie folgt lauten:
Kommentar von Upvote @ martin-charlesworth :)
quelle
boolean
Argument hinzufügen, um anzugeben, ob die Stückliste eingeschlossen oder ausgeschlossen werden soll. Beispiel:BOMInputStream bomIn = new BOMInputStream(in, false); // don't include the BOM
BOMInputStream bomIn = new BOMInputStream(is, ByteOrderMark.UTF_8, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_32BE, ByteOrderMark.UTF_32LE);
BOMInputStream(InputStream delegate) Constructs a new BOM InputStream that excludes a ByteOrderMark.UTF_8 BOM.
Einfachere Lösung:
Anwendungsbeispiel:
Es funktioniert mit allen 5 UTF-Codierungen!
quelle
Die Google Data API verfügt über eine,
UnicodeReader
die die Codierung automatisch erkennt.Sie können es anstelle von verwenden
InputStreamReader
. Hier ist ein leicht komprimierter Auszug seiner Quelle, der ziemlich einfach ist:quelle
(bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)
wahr zu sein, hätte der UTF-16LE-Fall ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)
) bereits übereinstimmen können.Der BOMInputStream
Apache Commons IO
der Bibliothek wurde bereits von @rescdsk erwähnt, aber ich habe nicht erwähnt, wie man einenInputStream
ohne die Stückliste erhält .So habe ich es in Scala gemacht.
quelle
public BOMInputStream(InputStream delegate) { this(delegate, false, ByteOrderMark.UTF_8); }
. Es schließtUTF-8 BOM
standardmäßig aus.Constructs a new BOM InputStream that excludes a ByteOrderMark.UTF_8 BOM.
Um die Stücklistenzeichen einfach aus Ihrer Datei zu entfernen, empfehle ich die Verwendung von Apache Common IO
Wenn Sie include auf false setzen, werden Ihre Stücklistenzeichen ausgeschlossen.
quelle
Leider nicht. Sie müssen sich identifizieren und überspringen. Auf dieser Seite erfahren Sie, worauf Sie achten müssen. Siehe auch diese SO-Frage für weitere Details.
quelle
Ich hatte das gleiche Problem und weil ich nicht in einer Reihe von Dateien gelesen habe, habe ich eine einfachere Lösung gefunden. Ich glaube, meine Codierung war UTF-8, weil ich beim Ausdrucken des betreffenden Zeichens mithilfe dieser Seite Folgendes festgestellt habe : Unicode-Wert eines Zeichens abrufen
\ufeff
. Ich habe den Code verwendetSystem.out.println( "\\u" + Integer.toHexString(str.charAt(0) | 0x10000).substring(1) );
, um den fehlerhaften Unicode-Wert auszudrucken.Sobald ich den fehlerhaften Unicode-Wert hatte, ersetzte ich ihn in der ersten Zeile meiner Datei, bevor ich weiter las. Die Geschäftslogik dieses Abschnitts:
Dies hat mein Problem behoben. Dann konnte ich die Datei ohne Probleme weiter verarbeiten. Ich habe hinzugefügt,
trim()
nur für den Fall eines führenden oder nachfolgenden Leerzeichens, dass Sie dies tun können oder nicht, je nachdem, was Ihre spezifischen Anforderungen sind.quelle