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 :

Traiter séparément CR et LF


Sujet :

Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 22
    Par défaut Traiter séparément CR et LF
    Bonjour,

    Je développe une Applet Java qui a pour but de remplacer une ancienne console ASCII. Le système auquel je suis relié envoie donc des caractères CR ou LF tantôt séparés tantôt à la suite (CRLF pour nouvelle ligne).
    Je voudrais pouvoir traiter tous les cas.

    Je reçois ces caractères d'une DataInputStream
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public tcpip(InetAddress ipa, int port)
     {
    	 Socket s1 = null;
    	 try {               // Open the socket
    	 s1 = new Socket(ipa.getHostAddress(), port);
    	 }
    	 catch (IOException e) {
    	 System.out.println("Error opening socket");
    	 return;
    	 }
    	 s = s1;
    	 try {               // Create an input stream
    	 dis = new DataInputStream(new BufferedInputStream(s.getInputStream()));
    	 }
    	 catch(Exception ex) {
    	 System.out.println("Error creating input stream");
    	 }
    	 try {               // Create an output stream
    	 dos = new DataOutputStream(new BufferedOutputStream(s.getOutputStream()));
    	 }
    	 catch(Exception ex) {
    	 System.out.println("Error creating output stream");
    	 }
    	 Poll = new Thread (this);
     }
    Je décode donc le flot d'octet que je reçois de la manière suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    switch(CslText[CslIndex])
    			{
    			case CAR_ESC:
    				TemoinESC=true;
    				break;
    			case CAR_TAB:
    				//Avance au prochain caractère
    				console.DeplaceCurseur(+1);
    				break;
    			case CAR_BS:
    				//Reculer Car. Précédent
    				console.DeplaceCurseur(-1);
    				break;
    			case CAR_CR:
    				//aller au début de ligne
    				console.CurrentPosition=NbLigneCnsl*console.Xmax;
    				console.FConsole.setCaretPosition(console.CurrentPosition);
    				TemoinSL=true;
    				break;
    			case CAR_LF:
    				//saut de ligne
    Mais durant mes tests, je m'aperçois que si tous se passe bien lorsque je reçois CR et LF séparément. Si je les reçois à la suite l'un de l'autre CRLF Java me fait sauter LF.

    D'où ma question: Comment forcer Java à traiter tous les caractères reçus?

    Merci d'avance.

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par Slartibartfast Voir le message
    Si je les reçois à la suite l'un de l'autre CRLF Java me fait sauter LF.
    Non, il ne se passe rien de ce genre avec un DataInputStream. Fais voir le code qui t'a fait penser ça.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 22
    Par défaut
    Pourtant, cela semble être la seule explication rationnelle.
    Voici comment je procède à mes tests.
    Je suis sur un PC qui envoie un fichier texte complet sur sa liaison série.
    Ce fichier texte est un fichier assez long d'un texte pris au hasard sur une page de Wikipedia (pour la longueur), mais que j'édite avec un éditeur hexadécimale afin d'y rajouter les caractères souhaités.
    Ce texte passe par un appareil de ce type et mon Applet connecté à ses sockets m'affiche les caractères reçus.

    Le résultat est simple :
    Que j'envoie CR ou LF à n'importe quel endroit dans le texte, ils sont pris en compte s'ils sont séparés, même ne serait-ce que du caractère nul.
    Par contre s'ils se suivent tous se passe comme si le premier caractère seulement me parvenait.
    Mon texte est assez long (presque 2000 caractères) et je ne perd aucun caractère en dehors de ce cas.
    Je suppose que le comportement par défaut d'un des objets java que j'utilise est de remplacer ces 2 caractère consécutif par un seul étant donné qu'ils font souvent double emploi dans les systèmes modernes.
    Mais le système sur lequel je dois me brancher a plus de 20 ans.

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    C'est cool de nous donner un peu de contexte. Fais voir le code !

    Pourtant, cela semble être la seule explication rationnelle.
    C'est de l'informatique. Les choses n'ont pas à sembler, les choses se prouvent, se démontrent mathématiquement.

    Ceci étant dit, il se pourrait bien que ce soit la suite d'appareillages utilisée, qui modifie les choses de l'entrée à la sortie. Je ne sauterais pas tout de suite sur cette conclusion, parce que Java a un certain nombre de méthodes qui ignorent volontairement si les fins de ligne sont LF, CR, ou CRLF. Mais ces méthodes-là ne remplacent pas la fin de ligne par LF ou par CR ou quoi que ce soit. Ces méthodes n'indiquent pas le caractère de fin de ligne, d'aucune façon que ce soit. Ce qui ne correspond pas à ta description du problème. Donc, faut voir le code.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 22
    Par défaut
    Le code entier fait plusieurs pages, et je ne suis pas sûr de pouvoir le publier. Mais pour aider au debug voilà le bout de code qui correspond au thread qui récupère les données sur le socket. Il les copie ailleurs et elle sont traités une à une par un autre thread dans le bout de code que j'ai publié dans le premier message (switch(CslText[CslIndex])...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public void run() {
         byte[] in;
     
         while (KeepRunning) {
             try {
                 Thread.sleep(2); 
                 }
             catch (InterruptedException e) { }
             if ( (this != null) && (this.available() > 0) ) 
             {
                 in = this.receive();
                 if((Testeur.InterfaceSeq.Cslbegin+in.length)<1000)
                     {
                         Testeur.InterfaceSeq.Cslbegin=Testeur.InterfaceSeq.Cslend;
                     }
                     else
                     {
                         Testeur.InterfaceSeq.CslOldend=Testeur.InterfaceSeq.Cslend;
                         Testeur.InterfaceSeq.Cslbegin=0;
                     }
                     System.arraycopy(in, 0, Testeur.InterfaceSeq.CslText, Testeur.InterfaceSeq.Cslbegin, in.length);
                     Testeur.InterfaceSeq.Cslend=(Testeur.InterfaceSeq.Cslbegin+in.length);
                     Testeur.InterfaceSeq.newMsg=true;
                 }
    Avec les bouts publiés dans le premier message, il y a toute la chaîne de la réception sur le socket à mon traitement, le "problème" se situe obligatoirement dans cette partie.

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Bien entendu, quand on dit "fais voir le code" ça signifie "fais un petit programme très très court qui montre le problème avec la même méthode, et seulement ça." En gros, tu dis que tu as un problème : prouve-le. Donne-nous un programme facile qu'on peut faire tourner sur nos machines et qui a ce problème.
    En fait, il faut faire ça avant de demander de l'aide. Car cela aide à séparer les tâches et, éventuellement, à se rendre compte par soi-même qu'est-ce qui ne faisait pas ce que ça devait faire.

    Et je ne sais toujours pas comment tu lis tes caractères.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 22
    Par défaut
    Oui, très juste! J'ai oublié cette méthode:
    public synchronized byte[] receive()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     {
    	 byte[] retval = new byte[0];
     
    	 try {
    	 while(dis.available() == 0);  /* Wait for data */
    	 }
    	 catch (IOException e){}
    	 try {
    	 retval = new byte[dis.available()];
    	 }
    	 catch (IOException e){}
    	 try {
    	 dis.read(retval);
    	 }
    	 catch (IOException e){}
    	 return(retval);
     }
    Donc en fait si je résume mon chemin de donnée est :
    DataInputStream dis => dis.read(in) =>byte[] in => System.arraycopy de in[0] à in[in.length-1] vers byte[] CslText et ensuite je traite un à un les caractères de CslText.

    Évidemment je comprends tout à fait la logique dans le fait de demander un code minimal. Je le ferai et le posterai ici demain. Mais pour que vous puissiez l'exécuter sur vos machines il faut peut être que je remplace l'utilisation d'une socket réseau par qqch d'autre et prendre un fichier comme entrée.

    Ce qui me laisse sceptique, c'est que j'obtiens le comportement souhaité sauf dans UN cas bien particulier.

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 22
    Par défaut
    Merci de ton aide thelvin
    effectivement ce n'était pas fait de manière très propre. Le pire c'est que c'est pas la première fois que j'ai à remettre en cause le travail de mon prédécesseur.

    J'ai donc modifié tout ça refait des tests, mais voilà ... ça ne marche toujours pas. J'ai donc fais un code minimal tentant de reproduire le bug.
    Au début j'ai remplacé le socket par un fichier, avec le fichier ça fonctionne.
    J'ai donc retourné mettre un socket dans mon code minimal et là je retrouve bien mon problème.
    Je met en pièce jointe de ce post les 2 fichiers sources ainsi que le petit fichier texte avec lequel je teste il contient la séquence (LF,CR,LF) et on voit très bien que le premier est correctement lu, tandis que le second est ignoré.
    Voici mon retour console qui le montre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    3
    Value:58
    Value:32
    Value:10
    Caractère Imprimable
    				3
    Caractère Imprimable
    				4
    Caractère Imprimable
    				5
    2
    Value:13
    Value:70
    Line Feed
    				6
    Carriage Return
    1
    Value:105
    				7
    Caractère Imprimable
    Fichiers attachés Fichiers attachés

  9. #9
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Utiliser les threads pose bien plus de contraintes que ça.

    Pour commencer, tu devrais sans doute refaire ce programme, sans thread. Ils ne servent à rien, là, les threads.

    Pour information, on ne peut pas modifier des variables dans un thread et regarder si ces variables ont changé dans un autre thread, sans synchroniser l'écriture/lecture de ces variables. Les résultats sont imprévisibles.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  10. #10
    Membre actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 22
    Par défaut
    Ben les threads c'est vrai j'en ai 2, à la rigueur je peux me contenter d'un seul. Mais sans thread du tout je vois pas comment à moins de mettre un gros while(1) quelque part, mais l'occupation des ressources après... ça risque de faire peur.
    Je peux essayer de synchroniser ça sera toujours mieux, mais rien qu'avec ce que j'ai là, je peux en déduire que mon read() ne lit pas le LF après le CR, non ?
    Dans ce cas, ce sera de toute manière problématique.

  11. #11
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    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 482
    Par défaut
    bon, d'abord, vu le code, tu n'a pas besoin d'un datainputstream, cette classe ne sert qu'à réordonnancer les byte suivant l'endiance correcte. Comme tu traite des bytes, inutile.

    ensuite, prend ta méthode receive et affiche dans la console la valeur de chaque byte lu, pour t'assurer que les CRLF sont bien là. Si il n'y sont pas, c'est que ton périphérique qui envoye vers la socket les fait passer à la trappe, pas java.

  12. #12
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Citation Envoyé par Slartibartfast Voir le message
    Je peux essayer de synchroniser ça sera toujours mieux, mais rien qu'avec ce que j'ai là, je peux en déduire que mon read() ne lit pas le LF après le CR, non ?
    Non tu ne peux rien déduire du tout. Il y a un thread qui modifie des variables, un autre qui les lit, est-ce que ça se passe, avant, après, un petit mélange pendant, on ne sait pas. Les variables contiennent des choses plus ou moins aléatoires. On ne peut rien en déduire.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  13. #13
    Membre actif
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    22
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 22
    Par défaut
    ben j'ai justement fait ce que tchize_ suggère résultat à la place de 10-13-10 j'ai 10-13-70 donc le 2ème '10' n'est pas lu.
    Après, ça ne veut pas dire que ça soit la méthode read() qui est en cause, ça peut tout à fait être le périphérique, même si c'est ce que je redoute le plus. j'ai justement sorti wireshark pour essayer d'y voir plus clair.

    Edit: Voilà Wireshark a parlé. Cette saloperie de périphérique remplace automatiquement 0D0A par 0D.
    Excusez - moi d'avoir douté de la puissance de Java

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Awk - Traiter chaque ligne du fichier passwd
    Par tony montana dans le forum Linux
    Réponses: 7
    Dernier message: 25/03/2004, 09h40
  2. Réponses: 4
    Dernier message: 18/08/2003, 09h53
  3. Un langage pour lire, traiter et écrire de gros fichiers
    Par March' dans le forum Langages de programmation
    Réponses: 19
    Dernier message: 07/04/2003, 15h26
  4. Traiter les caractères spéciaux
    Par ricola dans le forum Langage
    Réponses: 2
    Dernier message: 20/02/2003, 09h23

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