IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Java byte encodage


Sujet :

Java

  1. #21
    Rédacteur/Modérateur
    Avatar de Logan Mauzaize
    Homme Profil pro
    Architecte technique
    Inscrit en
    Août 2005
    Messages
    2 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : Transports

    Informations forums :
    Inscription : Août 2005
    Messages : 2 894
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Il n'y a pas si longtemps, 日本.txt aurait été un tel exemple, sauf si le Windows est configuré en Japonais.
    Bien sûr, à présent ça marche parfaitement sur tout ce que j'ai pu tester, histoire de me donner tort . (Il reste des malfonctions, mais seulement dans des cas bien plus compliqués qu'un simple listing de noms de fichiers à caractères visibles.)
    Je présente donc mes plus plates excuses et invite le monde entier à moinsser tout ça.



    UTF-16LE... Mais peu importe. Windows te donnera ce qu'il veut.
    Pour le coup, c'est Deltree et Nemek qui ont raison, en fait : Java efface la notion d'encodage, en s'arrangeant avec Windows pour ne travailler qu'avec des caractères. Et apparemment, il ne se trompe plus.

    Tu ne peux pas avoir "différents encodage" : deux noms de fichiers sont identiques ou équivalents ou différents. Cela n'a rien à voir avec l'encodage. Il n'y a rien dont tu aurais eu à te préoccuper à ce niveau-là (même si la situation que j'expose plus haut avait perduré.)
    Je trouve ça plutôt pertinent au vue de la demande, ça aurait très bien pu être son problème !
    Pour information as-tu essayé avec différentes versions de Java ?
    La classe qui gère le mapping entre le système de fichier et Java, c'est la classe java.io.FileSystem. Il y a une implémentation spécifique pour Windows. Peut-être que le code natif était buggé ?
    Il reste également possible que ce soit la version supporté d'Unicode qui est changée.

    Citation Envoyé par drKzs Voir le message
    Nemek
    Je récupère les noms des fichiers en String en UTF8, je les envoies via la socket en UTF8, et je les récupère en UTF8, ok (en C++, la Glib donne la classe ustring qui permet la manipulation UTF8, pour la précision). Mais sous linux (sous windows je sais pas) , il arrive qu'il ne trouve pas le fichier car le nom a été encodé en UTF8, et que certains caractères n'ont pu être convertis.
    Les noms des fichiers étant des String, ils sont "codés" en Unicode 4.0.
    Sauf problème de conversion lié à un bug dans la classe FileSystem.
    Il me semble que tout caractère Unicode est encodable en UTF-*, notemment grâce aux "surrogate pairs" (encodage d'un symbole sur plusieurs "code point").
    Vérifies côté Java que le nom du fichier n'est pas "déformé" (N'utilises pas la console car elle n'est pas nécessairement dans un encodage compatible.

    Ensuite le problème peut-être du côté C++ !

    Citation Envoyé par drKzs Voir le message
    thelvin
    Pourtant, je lis partout que lorsque tu crées une String, Java utilise forcément un charset (que tu peux préciser d'ailleurs dans le constructeur). Est-ce que je mélange les choses ?
    Le charset est utilisé pour convertir depuis ou vers les octets avec la représentation interne de Java qui n'utilise qu'un unique "codage".

    Plus d'information sur la classe Character.
    Java : Cours et tutoriels - FAQ - Java SE 8 API - Programmation concurrente
    Ceylon : Installation - Concepts de base - Typage - Appels et arguments

    ECM = Exemple(reproduit le problème) Complet (code compilable) Minimal (ne postez pas votre application !)
    Une solution vous convient ? N'oubliez pas le tag
    Signature par pitipoisson

  2. #22
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    Bon, je vais essayer de te résumer ce qui se passe:

    Sur le filesystem, j'ai un fichier. La nature même d'un filesystem fait que le nom du fichier est encodé sous forme binaire. Lorsque je demande à l'OS la liste des fichier d'un dossier, il existe deux manières de faire. Soit passer un char*, soit passer un byte*. Viens java et son API file. Cette API ne passe que par les appels de l'OS utilisant char*. L'OS ou JAva (faut voir les détaisl d'implémentation) va donc lire les byte[] du filesystem et les encoder suivant l'encodage utilisé pour monter le filesystem (c'est là qu'interviennent sous windows les bon vieux codepage). Et parfois, certains byte[] ne correspondent à rien et son traduits par du n'importe quoi, toujours au niveau de l'OS ou de l'implémentation interne java.

    Et là, tu l'a dans le baba, parce que ca veux dire que tu obtiens au final un String qui ne peux même plus être utilisée correctement avec new File() ou new FileInputStream()
    Bref, pour certains cas exotiques, t'as un fichier qui n'est tout simplement jamais ouvrable en java.

    C'est un problème avec Java et il y a déjà eu des RFE sur le bugtrack demandant que les api nio de java permettent l'accès aux noms de fichier sous forme de byte[]. Mais on promet on promet mais on vois rien venir


    Dans ton cas, pour localiser la cause réelle du problème: Pourrais tu faire ceci:

    Prendre coté java la String que tu as récupérée et tenter d'ouvrir le Fichier en java via un new FileInputStream(cheminComplet). Si ca marche, alors il n'y a pas eu de perte au niveau java, et l'erreur est coté C++. Ce sera juste une question de faire ceci
    1) envoyer à c++ le nom de fichier encodé en UTF-8
    2) dans l'application C++ faire la conversion UTF-8 -> encodage attendu par l'OS

    Si ce n'est pas le cas, tenter de relancer l'application java avec le paramètre -Dfile.encoding=.... mis à diférentes valeur (UTF-8, UTF-16LE, ISO8859-1 etc) histoire de voir si une des valeurs marche.

    Si pas tu l'a dans l'OS

  3. #23
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Septembre 2003
    Messages
    506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 506
    Par défaut
    aah oui, j'aime bien ce résumé

    Effectivement, impossible de réouvrir le fichier avec un FileInputStream Cette erreur me plaît, elle est logique ( on s'attache à rien parfois )

    Je vais essayer le truc du -Dfile.encoding pour voir, c'est intéressant. Cela dit l'encodage ça pose tellement de problème, du coté client j'ai un problème Xerces avec l'ouverture d'un xml au nom (et pas le contenu, le nom!) exotique

    Bon, je continue mes tests, je reviendrais

  4. #24
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    ce serait pas plutot un OS configuré avec des pieds palmés? Avoir une merde sur 1 fichier, ok, avoir des merde sur tous les fichiers: faut vraiment le faire exprès.

    Les noms de ficheir apparaissent correctement dans l'explorateur de l'OS (explorer/nautilus/autre) ??

  5. #25
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Septembre 2003
    Messages
    506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 506
    Par défaut
    C'est un peu plus palmé que ça, en réalité je reçois plein de fichiers de différents OS (que je ne connais pas) avec différentes locales (que je ne connais pas), donc parfois ça passe, parfois ça casse... D'où mon envie que ce soit complètement transparent

    Un exemple simple que j'avais fait dès le départ pour tester, je prends un fichier sous windows, avec un é. Je le copie sur mon client et mon serveur linux (locale UTF-8). Le nom s'affiche correctement sous Nautilus (pourquoi, je pensais qu'il utilisais la locale), mais pas sous la console, ni toutes les traces que je peux mettre dans mon programme C++ (via console eclipse configurée en UTF-8) : le é est affiché en ?.
    Si je passe par l'API JAVA File pour récupérer le nom de fichier, il est corrompu dès le départ, vu avec ton test (donc même avant le passage dans la socket, et la réception par mon serveur C++): le é est flingué. Si je passe le nom directement en byte, c'est OP, ça s'affiche toujours mal à l'arrivée mais le nom arrive intact à l'autre bout de la chaîne

  6. #26
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    ca prouve simplement que la partie "je le copie sur linux" s'est mal passée. C'est pas à l'applicatif de rattraper les merdes faites sous l'OS.

    Ici, sans aucun soucis:
    En console: "touch Чиз.txt"
    résultat du ls:
    Code x : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    me@xxx:/tmp$ ls test/
    Чиз.txt
    me@xxx:/tmp$
    résultat du code java suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    	public static void main(String[] args) throws IOException, ParseException {
    		for (String file : new File("/tmp/test").list()) {
    			System.out.println(file);
    		}
    	}

    maintenant, si je monte un vfat avec le charset ISO-8859-1, que j'y met un fichier avec un nom cyrillique, que je démonte, puis que je remonte avec le charset ISO-8859-7, j'obtiens ceci dans la console:

    Code x : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    me@xxx:/tmp$ sudo mount -t vfat -o loop,iocharset=iso8859-1 somefat mounted/
    me@xxx:/tmp$ sudo chmod a+w mounted/
    me@xxx:/tmp$ sudo mv test/* mounted/
    mv: impossible de préserver l'appartenance pour «mounted/Чиз2.txt»: Opération non permise
    mv: impossible de préserver l'appartenance pour «mounted/Чиз.txt»: Opération non permise
    me@xxx:/tmp$ ls mounted/
    Чиз2.txt  Чиз.txt
    me@xxx:/tmp$ sudo umount mounted/
    me@xxx:/tmp$ sudo mount -t vfat -o loop,iocharset=iso8859-7 somefat mounted/
    me@xxx:/tmp$ ls mounted/
    ??????	??????2.txt  ??????.txt

    et le résultat de mon code java dans ce cas
    Code x : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ?�???�2.txt
    ?�???�.txt
    ?�?�?�

    Bref c'est à l'OS hôte de ton application de faire ses mounts correctements.


    Pour ce qui est de l'envoi, il suffit que tes clients parlent tous le meme charset que ton serveur, que tu définis à ce que tu veux, ca ne concerne que la communication client<-> serveur. Au client de faire la conversion String-> byte[] dans le charset choisi et au serveur de faire la conversion byte[] -> char* en respectant le charset en question.

  7. #27
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Septembre 2003
    Messages
    506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 506
    Par défaut
    En console: "touch Чиз.txt"
    Si je me trompe pas, ici c'est le même système qui le crée et le lit (via le code JAva, mais qui doit utiliser les locales système), donc ce cas-là est sans problème, effectivement.

    ca prouve simplement que la partie "je le copie sur linux" s'est mal passée
    Justement, je ne suis pas sensé savoir comment (et doù) arrivent les fichiers, donc "le s'est mal passé", je risque d'y être souvent confronté (c'est même le cas normal en fait )

    C'est pas à l'applicatif de rattraper les merdes faites sous l'OS
    Au contraire, c'est ce qui m'importe, avoir une méthode qui couvre le maximum de cas
    Donc peu-importe comment a été convertit le nom, je veux simplement assurer que dans ma chaîne de bout en bout, je conserve la valeur brut du nom du fichier tel qu'il existe sur le système, sans rajouter d'encodage et risquer d'altérer un caractère, et assurer la conservation du nom ...

    Pour ce qui est de l'envoi, il suffit que tes clients parlent tous le meme charset que ton serveur, que tu définis à ce que tu veux, ca ne concerne que la communication client<-> serveur. Au client de faire la conversion String-> byte[] dans le charset choisi et au serveur de faire la conversion byte[] -> char* en respectant le charset en question.
    Oui, il reste à choisir un charset qui ne dénature aucun caractère (en somme qui couvre tous les caractères sans utiliser de caractère de remplacement) du charset d'origine, que je ne connais pas. C'est pourquoi passer par les byte me semblait plus simple, élégant, et sûr.

  8. #28
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    si j'ai bien suivi ta logique, le fichier est visible depuis deux OS différent. donc si il y a eu une merde au montage, a moins d'avoir la chance d'avoir fait exactement al même erreur de chaque coté, je ne vois pas pourquoi les nom binaire vu (sous forme de uint*) d'un coté serait identique du nom vu de l'autre coté. (exemple: un monte en ISO-8859-7, l'autre en ISO-8859-4)

    De toutes façon pour le nom en binaire, tu ne l'aura pas en java, point!

  9. #29
    Membre très actif
    Homme Profil pro
    Inscrit en
    Avril 2011
    Messages
    214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2011
    Messages : 214
    Par défaut
    Citation Envoyé par drKzs Voir le message
    Oui, il reste à choisir un charset qui ne dénature aucun caractère (en somme qui couvre tous les caractères sans utiliser de caractère de remplacement) du charset d'origine, que je ne connais pas.
    Tu ne t'en sortira pas pour autant. Ce n'est pas parce que deux encodages couvrent ont une plage commune de caractères qu'ils sont "compatibles" (même si on se limite à ces caractères en commun).

    Par exemple, prend un fichier nommé:
    Sur ton client le FS utilise "Cp1252" donc en lisant directement les octets tu trouves:
    Tu envois ces octets à ton serveur où le FS utilise "UTF-8" ce qui donne
    donc tes tableaux d'octets ne correspondent pas (ils n'ont même pas la même longueur d'ailleurs). Donc tu en déduis que ce ne sont pas les mêmes noms de fichiers !

  10. #30
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    Si j'ai bien suivi, sont problème est l'inverse, des deux cotés ils a

    Maintenant, d'un coté c'est monté en cp1252, donc en string il obtiens Ÿ.txt quand il liste le répertoire, information qui est transmise au serveur.

    De l'autre coté, serveur, il demande alors à ouvrir "Ÿ.txt" et le serveur cherche donc le fichier
    qui n'existe pas, car le fichier est
    qui s'affiche ?.txt

    Et ce qu'il voudrait ce serait plutot pouvoir directement transmettre
    9F 2E 74 78 74 afin que coté server il fasse un open(9F 2E 74 78 74)

  11. #31
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Septembre 2003
    Messages
    506
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 506
    Par défaut
    si j'ai bien suivi ta logique, le fichier est visible depuis deux OS différent. donc si il y a eu une merde au montage, a moins d'avoir la chance d'avoir fait exactement al même erreur de chaque coté, je ne vois pas pourquoi les nom binaire vu (sous forme de uint*) d'un coté serait identique du nom vu de l'autre coté. (exemple: un monte en ISO-8859-7, l'autre en ISO-8859-4)
    Oui, c'est complètement vrai ça Mais cette configuration là c'est pour mes premiers tests, en réalité les fichiers seront accessibles depuis le serveur, et la liste des noms sera du coté client. Comme ceux qui s'en occupent utilisent des appli Java et ont déjà eu le problème, je blinde ma partie le plus possible en faisant des tests tout moisis, et je suis tombé sur ce cas intéressant qui a donné dans ce forum une discussion intéressante

    De toutes façon pour le nom en binaire, tu ne l'aura pas en java, point!
    oui, j'ai bien compris que ça se mérite

    Et ce qu'il voudrait ce serait plutot pouvoir directement transmettre
    9F 2E 74 78 74 afin que coté server il fasse un open(9F 2E 74 78 74)
    Oui c'est ça, un tunnel brut

  12. #32
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    comme déjà dit, c'est pas le tunnel le problème

Discussions similaires

  1. Java EE, Encodage des caractères dans un formulaire
    Par sanzo1988 dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 09/06/2012, 13h21
  2. Différence entre Java byte-code et MSIL
    Par medamin27 dans le forum Général Java
    Réponses: 0
    Dernier message: 10/06/2011, 02h14
  3. java byte[][] vs. C void**
    Par lvr dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 15/09/2008, 14h47
  4. problème java-mysql encodage des caracteres
    Par mrdindo dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 14/06/2008, 15h13
  5. [ENCODAGE][JAVA]Afficher correctement des accents
    Par kornelius dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 17/02/2004, 17h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo