Des guillemets bouclés entraînant la définition de hasNextLine () par Java Scanner – pourquoi?

J’ai eu un problème pour que java.util.Scanner lise un fichier texte que j’ai sauvegardé dans le Bloc-notes, même si cela fonctionne très bien avec d’autres. En gros, quand il essaie de lire le fichier du problème, il apparaît complètement vide – hasNextLine () est false, le tampon est vide, etc. est une citation frisée n’importe où dans le fichier. Aucune exception n’est levée. Notez qu’un BufferedReader sur le même fichier n’a pas de problème.

try { int count = 0; Scanner scanner = new Scanner(new File("C:/myfile.txt")); while (scanner.hasNextLine()) { count++; scanner.nextLine(); } scanner.close(); System.out.print(count); count = 0; BufferedReader reader = new BufferedReader(new FileReader("C:/myfile.txt")); while (reader.readLine() != null) { count++; } reader.close(); System.out.print(count); } catch(IOException e) { e.printStackTrace(); } 

Le code ci-dessus, qui lit un fichier ne contenant qu’une citation frisée, affiche “01”. Les recherches sur Google m’ont amené à essayer ceci:

 Scanner scanner = new Scanner(new File("C:/myfile.txt"), "ISO-8859-1"); 

Cela le fait fonctionner (c.-à-d. Il affiche “11”). J’ai aussi remarqué que si j’allais dans le Bloc-notes et faisais un enregistrement sous …, l’encodage par défaut en bas est “ANSI”. Si je change cela en “UTF-8” et enregistre le fichier, le scanner (sans codage) fonctionne également. Si je dis au scanner “UTF-8”, alors cela ne fonctionne que si je sauvegarde au format UTF-8, mais “ISO-8859-1” semble le faire fonctionner même si je le sauvegarde au format “ANSI”.

Donc, je sais que cela a quelque chose à voir avec le codage de fichier, mais le problème est que je ne comprends rien au codage de fichier. Ma connaissance de ce que signifie “ISO-8859-1” est extrêmement vague; pourquoi cela fonctionne-t-il, quelle que soit la méthode utilisée pour enregistrer le fichier? Pourquoi BufferedReader fonctionne-t-il malgré tout?

MODIFIER:

Les liens / commentaires ci-dessous m’ont vraiment aidé à me diriger dans la bonne direction! Je pense l’avoir compris.

Tout d’abord, dans le Bloc-notes:

  • “ANSI” est le CP1252
  • “Unicode” est UTF-16LE
  • “UTF-8” est … bien, UTF-8

En hexadécimal, une apostrophe frisée est représentée par:

  • CP1252: 92
  • UTF-16LE: 1920
  • UTF-8: E2 80 99

Le codage par défaut utilisé par Java sur mon système, selon Charset.defaultCharset (), est UTF-8. Ainsi, lorsque j’ai enregistré le fichier au format UTF-8, le scanner a su à quoi s’attendre. Cependant, lorsque j’ai enregistré le fichier dans CP1252, il s’est étouffé une fois qu’il a atteint le chiffre “92”, car ce n’est pas un moyen correct de représenter un caractère dans cet encodage. Cela fonctionne bien tant qu’il n’y a pas de caractères tels dans le fichier – l’hexagone de “hello world” se trouve être le même dans les CP1252 et UTF-8 et ne pose pas de problème.

UTF-8 ne fonctionne pas avec un fichier UTF-16, car il ne sait pas quoi faire avec la marque d’ordre des octets (“FFFE”), quels que soient les caractères du fichier.

Par contre, lorsque je règle le scanner sur CP1252 ou ISO-8859-1, la tolérance est beaucoup plus grande. Cela n’interprète pas nécessairement les caractères correctement , mais rien ne l’empêche de reconnaître les lignes du fichier et de s’y déplacer en boucle.

En ce qui concerne la raison pour laquelle Scanner a un problème, mais pas FileReader / BufferedReader, je vais deviner que c’est parce que le scanner doit scinder le fichier, c’est-à-dire. interpréter les caractères de manière à ce qu’il puisse identifier les espaces blancs et d’autres motifs, de sorte qu’il s’étouffe quand il y a quelque chose de méconnaissable. Le lecteur n’a pas besoin de faire ça. Il suffit d’identifier les sauts de ligne.

Si vous ne spécifiez pas d’encodage lors de la création du scanner, il essaiera de deviner l’encodage basé sur une marque d’ordre d’octet (BOM), qui correspond aux premiers octets d’un fichier. S’il n’en a pas, il utilisera par défaut le système par défaut utilisé par le système d’exploitation. Puisque vous utilisez Windows, la valeur par défaut est cp-1252. Il semble que le bloc-notes enregistre votre fichier texte en utilisant ISO-8859-1, qui est similaire, mais pas identique à cp-1252. Voir ce lien pour plus de détails:

http://www.i18nqa.com/debug/table-iso8859-1-vs-windows-1252.html

Lorsque vous enregistrez le fichier au format UTF-8, il place probablement la nomenclature UTF-8 au début du fichier et le scanner peut l’acquérir.

Si vous voulez vous pencher davantage sur la nomenclature, consultez-la dans wikipedia – l’article est plutôt bon. Vous pouvez également télécharger PSPad et ouvrir le fichier texte en mode hexadécimal pour afficher les octets individuels. J’espère que cela pourra aider 🙂

La méthode hasNextLine Scanner hasNextLine simplement false si elle a rencontré une erreur de codage dans le fichier d’entrée. Sans aucune exception. Ceci est frustrant et n’est documenté nulle part, même dans la documentation de JDK 8 .

Si vous voulez juste lire un fichier ligne par ligne, utilisez ceci à la place:

 final BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream("inputfile.txt"), "inputencoding")); while (true) { Ssortingng line = input.readLine(); if (line == null) break; // process line } input.close(); 

Assurez-vous que le inputencoding ci-dessus est remplacé par le codage correct du fichier. Le plus probable est utf-8 ou ascii . Même si l’encodage ne correspond pas, il ne se terminera pas prématurément comme Scanner .

Il y a quelque temps, j’ai eu un problème similaire avec le fichier de configuration qui a été édité par l’utilisateur. Parce que je ne sais jamais quel type d’éditeur utilisera, j’essaie ceci:

 org.mozilla.universalchardet.UniversalDetector 

disponible à partir d’ici:

 https://code.google.com/p/juniversalchardet/ 

La détection du codage des caractères n’est pas simple et je ne peux donc pas être sûr que cette bibliothèque fonctionne à quelque condition que ce soit, mais pour moi, c’était suffisant. Jetez un coup d’œil, cela vous aidera peut-être à détecter votre encodage et à le régler plus tard sur Scanner .