2016-01-28 1 views
0

J'écris un fichier csv que j'ai également besoin de compresser, et j'utilise java.util.zip.ZipEntry et java.util.zip.ZipOutputStream.Écrire des caractères coréens dans un fichier .csv compressé en Java

Tout fonctionne très bien quand j'ai des caractères occidentaux dans toutes les colonnes, mais quand j'utilise des caractères coréens, il ne reconnait pas le/n et tout semble foiré et sur la même ligne. Je l'écris en caractères UTF-8, et je m'attends à ce que ça couvre le coréen.

import java.io.BufferedOutputStream; 
import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipOutputStream; 

import org.joda.time.DateTime; 
import org.joda.time.DateTimeZone; 
import org.joda.time.format.DateTimeFormat; 
import org.joda.time.format.DateTimeFormatter; 

public class CreateCSV { 

public static void main(String[] args) throws IOException { 

    DateTime utcDateTime = new DateTime().toDateTime(DateTimeZone.UTC); 
    DateTime newDateTime = utcDateTime.toDateTime(); 
    DateTimeFormatter dateFormatter = DateTimeFormat.forPattern("yyyyMMdd-HHmmss-SSS-"); 
    File zipFile = new File("C:/TestCSVKorean/"+ dateFormatter.print(newDateTime) + "Export.zip"); 

    FileOutputStream fileOutputStream = new FileOutputStream(zipFile); 
    // Open up the zipfile and create the csv entry 
    ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fileOutputStream)); 
    zos.putNextEntry(new ZipEntry(dateFormatter.print(newDateTime) + "tics.csv")); 
    // The first line of the CSV is a header line 
    StringBuffer csvHeader = new StringBuffer(
      "Time,Name,Rev,Appme,EnvName,PlanName,PlanRev," 
       + "Og Name,Op Name," 
       + "TTR,Lat,Bys Rec,Bytt," 
        + "RPl,Request Method,URI Path,Query String,HTTP Status Code," 
        + "HTTP Request Headers,User Agent,Request Body,HTTP Response Headers,Response Body\n"); 
    zos.write(csvHeader.toString().getBytes(), 0, csvHeader.length()); 

    StringBuffer csvData = new StringBuffer(""); 

    csvData.append("\"" + newDateTime + "\",\"" + 
      "apiName" + "\"," + 
      "2.0.0" + ",\"" + 
      "app name" + "\",\"" + 
      "env name" + "\",\"" + 
      "plan name" + "\"," + 
      "2" + ",\"" + 
      "dev org name" + "\",\"" + 
      "ìº˜ë¦°ë” ëª©ë¡ì¡°íšŒ(ë‚´ 캘린ë”, 구ë…가능한 캘린ë”, 시스템 캘린ë”, ê´€ë¦¬ìž ìº˜ë¦°ë”)" + "\"," + 
      "123" + "," + 
      "inifd: 334;dshs: 343" + ", " + 
      "10" + "," + 
      "33" + ",\"" + 
      "http" + "\",\"" + 
      "GET" + "\",\"" + 
      "/dsfs/sdf/ds" + "\",\"" + "query string" + "\",\"" + 
      "200" + "\",\"" + 
      "jshkshdf" + "\",\"" + 
      "sdjhfks/sdfs/" + "\",\"" +        
      "jhksdfhks dsfs" + "\",\"" +  
      "dsfsdfs" + "\",\"" +  
      "dsfsfs" + "\"\n"); 

    zos.write(csvData.toString().getBytes("UTF-8"), 0, csvData.length()); 

    csvData = new StringBuffer(""); 

    csvData.append("\"" + newDateTime + "\",\"" + 
      "apiName" + "\"," + 
      "2.0.0" + ",\"" + 
      "app name" + "\",\"" + 
      "env name" + "\",\"" + 
      "plan name" + "\"," + 
      "2" + ",\"" + 
      "dev org name" + "\",\"" + 
      "ìº˜ë¦°ë” ëª©ë¡ì¡°íšŒ(ë‚´ 캘린ë”, 구ë…가능한 캘린ë”, 시스템 캘린ë”, ê´€ë¦¬ìž ìº˜ë¦°ë”)" + "\"," + 
      "123" + "," + 
      "inifd: 334;dshs: 343" + ", " + 
      "10" + "," + 
      "33" + ",\"" + 
      "http" + "\",\"" + 
      "GET" + "\",\"" + 
      "/dsfs/sdf/ds" + "\",\"" + "query string" + "\",\"" + 
      "200" + "\",\"" + 
      "jshkshdf" + "\",\"" + 
      "sdjhfks/sdfs/" + "\",\"" +        
      "jhksdfhks dsfs" + "\",\"" +  
      "dsfsdfs" + "\",\"" +  
      "dsfsfs" + "\"\n"); 


    zos.write(csvData.toString().getBytes("UTF-8"), 0, csvData.length()); 

    zos.close(); 

} 

}

C'est ce que je vois quand j'ouvre le fichier csv:

Nom Temps Rev Appme envname PlanName PlanRev Og Nom Op Nom TTR Lat Bys Rec Bytt RPL Demande Méthode URI Chemin de requête Chaîne HTTP Code d'état HTTP En-tête de requête Agent utilisateur Corps de la requête HTTP En-tête de réponse Corps de la réponse
2016-01-28T17: 20: 56.859Z apiName 2.0.0 nom de l'application env name nom du plan 2 dev org nom 캘à °  ° ° «Â ª ª ° (((((((((((((((((€, à € à € à € à € à € à € à € à € à € à € à € à € |Å "ì ° °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° que 123 343 10 33 http 2016-01-28T17: 20: 56.859Z apiName 2.0.0 nom de l'application env nom nom du plan 2 dev nom de l'organisation 캘à° Ã⠀ šÃƒÂ © Ãà ¡Â °  (à € à € à € à € à € à € à € à € à € à € à € à € ì ° ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃà [rÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃrà ... |¬ìž ìº˜à «Â| ° ë AA €) 123: 334; inifd DSHS: 343 10 33 http

Il est collé le champ de date à partir de la deuxième rangée en t Il demande le champ de méthode du premier: 2016-01-28T17: 20: 56.859Z

+0

Votre fichier CSV semble correct. Le problème est dans la façon dont vous le voyez. Quel programme utilisez-vous pour l'ouvrir? – VGR

Répondre

2

D'abord, vous devriez sortir de l'habitude d'utiliser StringBuffer. C'est une classe obsolète. Si vous devez ajouter du texte petit à petit, vous utiliserez normalement StringBuilder à la place.

Dans votre cas, cependant, vous n'avez pas besoin de StringBuilder ou de StringBuffer. Il suffit d'utiliser la chaîne:

String csvHeader = 
     "Time,Name,Rev,Appme,EnvName,PlanName,PlanRev," 
      + "Og Name,Op Name," 
      + "TTR,Lat,Bys Rec,Bytt," 
       + "RPl,Request Method,URI Path,Query String,HTTP Status Code," 
       + "HTTP Request Headers,User Agent,Request Body,HTTP Response Headers,Response Body\n"; 

Et ...

String csvData = "\"" + newDateTime + "\",\"" + 
     "apiName" + "\"," + 
     "2.0.0" + ",\"" + 
     "app name" + "\",\"" + 
     // etc. 

Deuxièmement, faire attention à ne pas confondre le nombre d'octets avec le nombre de caractères. Lorsque vous convertissez une chaîne en octets à l'aide du jeu de caractères UTF-8, tous les caractères non compris dans la plage US-ASCII (0-127) seront convertis en plusieurs octets. Par conséquent, le nombre d'octets sera supérieur à la longueur de la chaîne (qui représente le nombre de caractères qu'elle contient, et non le nombre d'octets qu'elle prend en charge lorsqu'elle est codée en UTF-8).

Ainsi, votre opération d'écriture doit être juste:

zos.write(csvData.toString().getBytes("UTF-8")); 

Troisièmement, je ne sais pas coréen, mais je sais ce que les personnages ressemblent à Hangul, et je ne vois pas dans votre code. Je suppose que vous l'intention d'être ces Hangul:

"ìº˜ë¦°ë” ëª©ë¡ì¡°íšŒ(ë‚´ 캘린ë”, 구ë…가능한 캘린ë”, 시스템 캘린ë”, ê´€ë¦¬ìž ìº˜ë¦°ë”)" + "\"," + 

Il semble que vous utilisez Windows pour placer chaque UTF-8 octets individuel dans votre chaîne comme si elle était un personnage. Mais en Java, les octets sont et non caractères, et ne sont pas interchangeables avec les caractères.

Je suppose que votre utilisation de Windows, parce que le troisième caractère, l'espacement des caractères Unicode SMALL TILDE, est \u02dc qui normalement prendre deux octets, mais dans l'encodage Windows-1252, il est le seul octet 0x98.

Donc, si je suppose que vous tiriez les personnages des UTF-8 octets de caractères Hangul, les six premiers octets dans la chaîne ci-dessus sont:

ec ba 98 eb a6 b0 
ì º ˜ ë ¦ ° 

Ces octets sont la représentation UTF-8 de la deux caractères Hangul U + CE98 et U + B9B0. La bonne façon de placer ces deux caractères dans une chaîne Java est:

"\uce98\ub9b0" 

Si vous avez le texte Hangul d'origine dans un fichier, vous pouvez facilement convertir le texte en entier à une série de séquences d'échappement Java comme la ligne ci-dessus , en utilisant l'outil native2ascii fourni avec chaque JDK. Une telle commande pourrait ressembler à:

native2ascii -encoding UTF-8 hangul.txt hangulstrings.java 

Une autre approche que je ne recommande pas, si vous ne voulez pas être dérangé pour écrire vos chaînes correctement, est de forcer vos actuels « pseudo-octets » string être interprété comme UTF-8 octets en reconnaissant qu'il contient des caractères Windows 1252 représentant octets et la restauration à ces octets:

zos.write(csvData.getBytes("windows-1252")); 

L'entrée zip résultant sera toujours encodées en UTF-8, puisque vos octets sont une représentation UTF-8 de votre texte Hangul. Donc, vous devez vous assurer que vous ouvrez le fichier en utilisant un outil qui reconnaît que le fichier est UTF-8.

Windows n'est pas particulièrement adapté à la reconnaissance d'un fichier UTF-8. Le bloc-notes est particulièrement pauvre. Une façon de signaler à Windows qu'un fichier est un fichier UTF-8 est d'écrire un caractère de commande d'octet comme premier caractère du fichier:

String csvHeader = "\ufeff" 
     + "Time,Name,Rev,Appme,EnvName,PlanName,PlanRev," 
     // etc. 
+0

Réponse fantastique, merci beaucoup. Cela a fonctionné: zos.write (csvData.toString(). GetBytes ("UTF-8")); – IainS