Préface
Dans l'article précédent, nous avons introduit le contenu pertinent dans le cadre de streaming de byte de fichier de Java, tandis que notre article se concentrera sur le contenu pertinent du streaming de caractères de fichiers.
Tout d'abord, il doit être clair que les fichiers de traitement de flux d'octets sont basés sur des octets, tandis que les fichiers de traitement de flux de caractères sont basés sur les caractères en tant qu'unités de base.
Mais en fait, l'essence du fonctionnement du flux de caractères est l'encapsulation des deux processus de "Fonctionnement du flux d'octets" + "codage". Pensez-vous que oui? Que vous écriviez un caractère dans un fichier, vous devez coder les caractères en binaire, puis les écrire dans le fichier en octets en tant qu'unité de base, ou que vous lisez un caractère en mémoire, vous devez le lire en octets comme unité de base, puis le transcoder en caractères.
Il est important de comprendre cela, qui déterminera votre compréhension globale des flux de personnages. Jetons un coup d'œil à la conception des API connexes ensemble.
Lecteur / écrivain de classe de base
Avant d'apprendre officiellement la classe de base de flux de personnage, nous devons savoir comment un personnage est représenté dans Java.
Tout d'abord, le codage de caractères par défaut en Java est: UTF-8, et nous savons que les caractères codés UTF-8 sont stockés en utilisant 1 à 4 octets, et les caractères les plus couramment utilisés, moins les octets sont utilisés.
Le type de char est défini comme deux tailles d'octets, c'est-à-dire que, pour les caractères ordinaires, un char peut stocker un personnage, mais pour certains jeux de caractères complémentaires, deux caractères sont souvent utilisés pour représenter un caractère.
Lecteur est la classe de base pour la lecture des flux de caractères, et il fournit les opérations de lecture les plus élémentaires. Jetons un coup d'œil ensemble.
Jetons un coup d'œil à son constructeur d'abord:
Lock d'objet protégé; Reader protégé () {this.lock = this;} Protected Reader (objet Lock) {if (Lock == NULL) {Throw New NullPointerException (); } this.lock = lock;}Le lecteur est une classe abstraite, il ne fait donc aucun doute que ces constructeurs sont appelés aux sous-classes et sont utilisés pour initialiser les objets de verrouillage de verrouillage, que nous expliquerons en détail plus tard.
public int read () lève ioException {char cb [] = new char [1]; if (read (cb, 0, 1) == -1) return -1; else return cb [0];} public int Read (char cbuf []) lève ioException {return read (cbuf, 0, cbuf.length);} abstract public int lic (char cbuf [], int off, int len)L'opération de lecture de personnage de base est tout ici. La première méthode est utilisée pour lire un personnage. S'il a été lu à la fin du fichier, il retournera -1. La même chose est reçue avec INT comme type de valeur de retour, pourquoi ne pas utiliser Char? La raison en est la même, tout en raison de l'incertitude de l'interprétation de la valeur -1.
La deuxième méthode est similaire à la troisième méthode, lisant les caractères d'une longueur spécifiée du fichier et les plaçant dans le tableau cible. La troisième méthode est une méthode abstraite, qui doit être implémentée par les sous-classes, tandis que la deuxième méthode est basée sur elle.
Il existe d'autres méthodes similaires:
Ces méthodes sont en fait bien connues et sont généralement similaires à notre entrée, et elles n'ont aucune implémentation de base. Je n'entrerai pas dans les détails ici, vous pouvez à peu près savoir ce qu'il y a à l'intérieur.
L'écrivain est un flux de caractères écrit, qui est utilisé pour écrire un ou plusieurs caractères dans un fichier. Bien sûr, la méthode d'écriture spécifique est toujours une méthode abstraite et doit être implémentée par des sous-classes, nous ne le répéterons donc pas ici.
Adaptateur inpuststramreader / outputStreamwriter
Les flux de personnages adaptateurs héritent du lecteur ou de l'écrivain de classe de base, qui sont des membres très importants du système de flux de caractères. La fonction principale est de convertir un flux d'octets en flux de caractères. Prenons d'abord l'adaptateur de lecture comme exemple.
Tout d'abord, ses principaux membres:
Final Streamdecoder SD privé;
StreamDeccoder est un décodeur utilisé pour convertir diverses opérations d'octets en opérations correspondantes de caractères. Nous le mentionnerons en continu dans l'introduction ultérieure, et nous ne l'expliquerons pas uniformément ici.
Ensuite, il y a le constructeur:
public inputStreamReader (inputStream in) {super (in); try {sd = streamdecoder.ForInputStreamReader (in, this, (string) null); } Catch (UnportEnCoDingException e) {Throw New Error (E); }} public inputStreamReader (inputStream in, String CharsetName) lève unportdencodingException {super (in); if (charSetName == null) lancez new nullpointerException ("charSetName"); sd = streamdecoder.ForInputStreamReader (in, this, charsetName);}Le but de ces deux constructeurs est d'initialiser ce décodeur. La méthode ForInputStreamReader est appelée, mais les paramètres sont différents. Jetons un coup d'œil à la mise en œuvre de cette méthode:
Il s'agit d'un modèle d'usine statique typique. Il n'y a rien à dire sur les trois paramètres, var0 et var1, représentant respectivement l'instance de flux d'octets et l'instance d'adaptateur.
Le paramètre var2 représente en fait un nom de codage de caractères. S'il est nul, le codage des caractères par défaut du système sera utilisé: UTF-8.
Enfin, nous pouvons obtenir une instance du décodeur.
Presque toutes les méthodes introduites ensuite sont mises en œuvre en s'appuyant sur ce décodeur.
public String getEncoding () {return sd.getEncoding ();} public int Read () lève ioException {return sd.read ();} public int read (char cbuf [], int offset, int legth) {return sd.read (cbuf, offset, longueur);} public Void Close () throws ioexception {sd.close ();}Le code d'implémentation des méthodes connexes dans le décodeur est encore relativement complexe. Nous ne procéderons pas à des recherches approfondies ici, mais l'idée générale de mise en œuvre est: le processus de «lecture du flux d'octets + décodage».
Bien sûr, il doit y avoir une instance de streaming opposée dans OutputStreamWriter pour les caractères d'encodage.
En dehors de cela, les autres opérations ne sont pas différents, ni écrits dans le fichier via un tableau de caractères, écrits dans le fichier via une chaîne ou écrits dans le fichier via les 16 bits inférieurs d'int.
File de flux de caractères Fileaders / écrivain
Le flux de caractères d'un fichier peut être considéré comme très simple. Il n'y a pas d'autre méthode sauf le constructeur, et cela dépend entièrement du flux de byte de fichier.
Prenons un exemple FileReader.
FileReader hérite de InputStreamReader, et n'a que les trois constructeurs suivants: public fileReader (String FileName) lève FileNotFoundException {super (new FileInputStream (FileName));} public fileReader (fichier file) lance filenotfoundException {super (newInutStream (file)) FileInputStream (FD));}En théorie, tous les flux de caractères doivent être basés sur notre adaptateur, car il ne fournit que la conversion de caractère à octet, que vous écriviez ou que vous liiez, il en est inséparable.
Notre fichier Fileader n'étend aucune de ses propres méthodes. La méthode de fonctionnement de caractère pré-mise en œuvre dans la classe Parent InputStreamReader lui suffit. Il n'a qu'à passer dans une instance de flux d'octet correspondant.
Il en va de même pour FileWriter, je n'entrerai pas dans les détails ici.
Stream de personnage Stream ChararRayReader / écrivain
Les tableaux de caractères et les flux de réseaux d'octets sont similaires, à la fois pour résoudre la situation où il y a une taille de fichier incertaine et nécessite la lecture d'une grande quantité de contenu.
Puisqu'ils fournissent un mécanisme d'extension dynamique en interne, ils peuvent non seulement accueillir les fichiers cibles, mais également contrôler la taille du tableau afin de ne pas allouer trop de mémoire et de gaspiller beaucoup d'espace mémoire.
Prenez ChararRayReader comme exemple
protégé char buf []; public chararrayreader (char buf []) {this.buf = buf; this.pos = 0; this.count = buf.length;} public chararrayreader (char buf [], into offset, int le long) {// ..}La tâche principale du constructeur consiste à initialiser un tableau de caractères dans l'attribut BUF interne. Toutes les opérations de lecture suivantes sur l'instance de flux de tableau de caractères seront basées sur le tableau de caractères BUF.
En ce qui concerne les autres méthodes de CharArayReader et Chararraywriter, je ne les répéterai pas ici, qui sont fondamentalement similaires au flux de tableaux d'octets dans l'article précédent.
De plus, il existe également un leader StringReader et StringWriter. En fait, c'est essentiellement la même chose qu'un flux de tableaux de personnage. Après tout, l'essence de String est un tableau char.
BufferedReader / écrivain
De même, BufferedReader / Writer est un flux tampon et est également un flux de décorateur, utilisé pour fournir des fonctions tampon. Généralement similaire à notre flux de tampon d'octets, présentons-le brièvement ici.
lecteur privé dans; private char cb []; private static int defaultCharbucheSize = 8192; public buttereDeader (lecteur dans, int sz) {..} public buttereDaDer (lecteur dans) {this (in, defaultCharbuchesize);}CB est un tableau de caractères qui cache certains caractères lus dans le flux de fichiers. Vous pouvez initialiser la longueur de ce tableau dans le constructeur, sinon la valeur par défaut de 8192 sera utilisée.
public int read () lève ioException {..} public int lien (char cbuf [], int off, int len) {...}En ce qui concerne la lecture, cela dépend de la méthode de lecture de l'attribut membre.
Par conséquent, presque tous les flux de caractères ne peuvent pas être séparés d'une instance de flux d'octets.
Je ne le répéterai pas ici sur BufferedWriter. C'est fondamentalement similaire, sauf que l'un est en train de lire et que l'autre écrit, et il tourne autour du tableau de caractères interne.
Flux d'impression standard
Il existe deux principaux types de flux d'impression, PrintStream et Printwriter. Le premier est un flux d'octets et le second est un flux de personnage.
Ces deux flux sont considérés comme intégrant des flux dans leurs catégories respectives. Il existe de riches méthodes d'encapsulation internes, mais la mise en œuvre est également un peu compliquée. Regardons d'abord le flux d'octets imprimé:
Il y a plusieurs constructeurs principaux:
De toute évidence, les constructeurs simples s'appuieront sur des constructeurs complexes, qui est déjà considéré comme une "ancienne routine" pour la conception JDK. Ce qui le distingue des autres flux d'octets, c'est que PrintStream fournit un indicateur automatique de drapeau qui spécifie s'il faut rafraîchir automatiquement le cache.
Ensuite, la méthode d'écriture de PrintStream:
De plus, PrintStream résume également un grand nombre de méthodes d'impression et écrit différents types de contenu dans des fichiers, tels que:
Bien sûr, ces méthodes n'écrivent pas vraiment le binaire numérique dans un fichier, mais écrivez simplement leurs chaînes correspondantes à un fichier, par exemple:
imprimer (123);
Le fichier final n'est pas l'instruction binaire correspondant à 123, mais juste la chaîne 123, qui est le flux d'impression.
Le flux de caractères tamponné utilisé par PrintStream implémente toutes les opérations d'impression. Si une actualisation automatique est spécifiée, le tampon sera automatiquement actualisé lors de la rencontre du symbole newline "/ n".
Ainsi, PrintStream intègre toutes les méthodes de sortie dans les flux d'octets et les flux de caractères, où la méthode d'écriture est utilisée pour les opérations de flux d'octets et la méthode d'impression est utilisée pour les opérations de flux de caractères, qui doivent être clarifiées.
Quant à Printwriter, il s'agit d'un flux de personnages complet qui fonctionne complètement contre les personnages. Qu'il s'agisse de la méthode d'écriture ou de la méthode d'impression, c'est une opération de flux de caractères.
Pour résumer, nous avons passé trois articles à expliquer le flux d'octets et les opérations de flux de personnages en Java. Le streaming d'octets complète la transmission de données entre le disque et la mémoire en fonction des octets. Le plus typique est le flux de caractères de fichier, et ses implémentations sont toutes des méthodes locales. Avec les capacités de transfert de base des octets, nous pouvons également améliorer l'efficacité grâce à la mise en mémoire tampon.
L'implémentation la plus élémentaire des flux de caractères est InputStreamReader et OutputStreamWriter. En théorie, ils peuvent déjà effectuer des opérations de base de flux de personnages de base, mais ils ne sont limités qu'aux opérations les plus basiques. Ce qui est nécessaire pour construire leurs instances est "une instance de flux d'octet" + "un format de codage".
Par conséquent, la relation entre un flux de caractères et un flux d'octets est comme l'équation ci-dessus. L'étape nécessaire pour écrire un caractère dans un fichier de disque est de coder le caractère dans le format de codage spécifié, puis d'utiliser le flux d'octet pour écrire le binaire de caractères codé dans le fichier. L'opération de lecture est le contraire.
Tous les codes, images et fichiers de l'article sont stockés dans le cloud sur mon github:
(https://github.com/singleyam/overview_java)
Vous pouvez également choisir de télécharger localement.
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.