Het toevoegen van een UTF-8-BOM in java

Ik heb een stored procedure die haalt record uit de tabel met Resultaatset object en maakt een csv-bestand.

BLOB retBLOB = BLOB.createTemporary(conn, true, BLOB.DURATION_SESSION);
retBLOB.open(BLOB.MODE_READWRITE);
OutputStream bOut = retBLOB.setBinaryStream(0L);
ZipOutputStream zipOut = new ZipOutputStream(bOut);
PrintStream out = new PrintStream(zipOut,false,"UTF-8");
out.write('\ufeff');
out.flush();
zipOut.putNextEntry(new ZipEntry("filename.csv"));
while (rs.next()){
    out.print("\"" + rs.getString(i) + "\"");
    out.print(",");
}
out.flush();
zipOut.closeEntry();
zipOut.close();
retBLOB.close();
return retBLOB;

Maar de aangemaakte csv-bestand niet de juiste duits karakter. Oracle database heeft ook een NLS_CHARACTERSET waarde van UTF8.

Stel.

  • Voor het geval je het nog niet tegengekomen dit voor rekening mee dat de Unicode-standaard niet vereist is of raden het gebruik van een BOM met UTF-8. Het is niet illegaal, maar mogen niet gebruikt worden zonder onderscheid. Zie hier voor de details, waaronder een aantal richtlijnen over wanneer en waar deze te gebruiken. Als u probeert te bekijken van het csv-bestand in Windows, dit is waarschijnlijk een geldig gebruik van de BOM.
  • Ja, we zijn bezig om de weergave van de csv in Windows, maar de aangemaakte csv toont nog steeds een rommelig karakter voor de duitse tekens. Is dit de juiste manier om de BOM?
  • Ja, dat klopt. De Unicode-standaard adviseert tegen met behulp van een zogenaamde BOM (het is niet echt) met de UTF-8.
  • zij beveelt aan tegen het gebruik van een BOM bij het omgaan met de software en protocollen die uitzonderingen ASCII-alleen tekens. Als het OP is weet dat de Windows-software die hij gebruikt, zal het gebruik van de BOM op te sporen dat het bestand daadwerkelijk wordt gecodeerd in UTF-8 (we don ‘ t care over het feit dat het niet een BOM, wij de zorg over de feit dat maakt het mogelijk om bepaalde software te detecteren is dat de codering UTF-8). Merk ook op dat als je een BOM naar UTF-8 en de nodige software falen, dan is deze software zijn gebroken, omdat een BOM aan het begin van een UTF-8 is perfect geldig.
  • Natuurlijk is het echte probleem hier is dat het CSV-bestand geen metagegevens noch specificaties die de codering van het bestand te worden aangegeven. Het is in principe hetzelfde oude SNAFU dat is ook van invloed .java-bestand en vele andere crappy-underspec ‘ ed bestand formaten.
  • Ik realiseer me dat dit in het beste geval een gedeeltelijke oplossing voor het probleem, maar ik zou heel graag zien dat er een norm per-bron-eenheid annotatie zoals @encoding UTF-8 in Java-bestanden. Ik begrijp dat dit werkt alleen voor supersets van ASCII-zoals UTF-8, ISO-8859-?, MacRoman, of CP1252, en dat het optreden voor een niet-ASCII-tekens worden gezien. Maar dit is dezelfde beperking als in-band codering specificaties in het XML -, Perl en Python. Ik heb gehoord dat het niet zou worden, niet te hard en implementeren van een presentator, maar afgezien van regexes en coderingen, mijn Java-fu is zwak. Zou zeker nuttig zijn, eh?!
  • Voor de volledigheid van de BOM discussie. Excel 2003 strikt vereist dat de BOM in UTF-8 gecodeerd CSV-bestanden. Anders multibyte-tekens onleesbaar zijn.

InformationsquelleAutor Fadd | 2010-12-08

 

5 Replies
  1. 9

    Schrijven van een BOM in UTF-8 moet je PrintStream.print(), niet PrintStream.write().

    Ook als u wilt BOM in uw csv bestand, ik denk dat u wilt afdrukken een BOM na putNextEntry().

    • Niet alle PrintStreams fundamenteel gebrekkig omdat ze leggen alle fouten die zich kunnen voordoen op de stream, inclusief I/O-fouten, volledige bestandssystemen, netwerk onderbrekingen en coderen van mismatches? Als dit niet uitkomt, kunt u mij misschien vertellen hoe ze betrouwbare (want ik wil om ze te gebruiken)? Maar als het waar is, kunt u uitleggen wanneer het ooit zou kunnen zijn geschikt voor het gebruik van een output methode die onderdrukt juistheid zorgen? Dit is een serieuze vraag, want ik begrijp niet waarom dit was zo gevaarlijk zijn. Bedankt voor alle inzichten.
    • het is waar dat PrintStreams onderdrukken fouten. Echter … 1) ze worden niet volledig gewist: u kunt controleren om te zien als er een fout is opgetreden. 2) Er zijn gevallen waarin u niet hoeft te weten over fouten. Een onbetwistbaar het geval is wanneer u het verzenden van tekens naar een stroom die aan het schrijven is aan een in-memory-buffer.
    • Ik denk dat dit is veroorzaakt door het gebruik van gecontroleerd uitzonderingen. Normaal gesproken zou je gewoon gooien op een fout en gelukkig te zijn. Je zou kunnen maken van een bestaande PrintStream “veilig” door het wikkelen van elk gesprek en het toevoegen van checkError en voorwaardelijk gooien. Maar de informatie over de uitzondering is verloren. Zo ja, PrintStream is een hopeloze onzin.
  2. 61
    BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(...), StandardCharsets.UTF_8));
    out.write('\ufeff');
    out.write(...);

    Dit correct schrijft 0xEF 0xBB 0xBF naar het bestand, dat is de UTF-8 vertegenwoordiging van de BOM.

    • Deze code is gevoelig voor standaard platform-codering. Op Windows, ik eindigde met 0x3F naar het bestand geschreven. De juiste manier om de BufferedWriter is: BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(the File), StandardCharsets.UTF_8))
  3. 8

    Ik denk dat out.write('\ufeff'); eigenlijk out.print('\ufeff');.

    Volgens de javadoc, de write(int) methode eigenlijk schrijft een byte … zonder enig karakter codering. Dus out.write('\ufeff'); schrijft de byte 0xff. Door contrast, de print(char) methode codeert het teken als één of bytes via de stream encoding, en dan schrijft die bytes.

    • Is niet de enige veilige manier te doen gecodeerde uitvoer in Java is het gebruik van de zelden vertoonde OutputStreamWriter(OutputStream out, CharsetEncoder enc) voor van de constructeur, de enige van de vier met een expliciete CharsetEncoder argument, en nooit met de PrintStream die je hebt aanbevolen hier?
    • 1) aantal 2) ik had geen raden PrintStream. Ik heb gewoon gezegd hoe het moet doen wat het vroeg OP te doen met behulp van de PrintStream hij was al in gebruik. 3) In dit geval PrintStream moet veilig zijn omdat het wordt gevolgd door andere activiteiten die ertoe zal leiden dat schrijft de onderliggende stream (socket) en het gooien van een uitzondering als de vorige PrintStream schrijft had stilletjes mislukt.
  4. 8

    Slechts in het geval dat mensen zijn met PrintStreams, die u nodig hebt om het te doen een beetje anders. Terwijl een Writer zal aan magie doen, om te zetten in een enkele byte in 3 bytes, een PrintStream vereist dat alle 3 bytes van de UTF-8 BOM individueel:

        //Print utf-8 BOM
        PrintStream out = System.out;
        out.write('\ufeef'); //emits 0xef
        out.write('\ufebb'); //emits 0xbb
        out.write('\ufebf'); //emits 0xbf

    U kunt ook gebruik maken van de hex-waarden voor degenen die direct:

        PrintStream out = System.out;
        out.write(0xef); //emits 0xef
        out.write(0xbb); //emits 0xbb
        out.write(0xbf); //emits 0xbf
  5. 0

    In mijn geval is het werken met de code:

    PrintWriter out = new PrintWriter(new File(filePath), "UTF-8");
    out.write(csvContent);
    out.flush();
    out.close();

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *