Préface
Dans l'article précédent, nous avons introduit le type de fichier de fichiers de disque abstrait. Il est uniquement utilisé pour décrire abstraitement un fichier de disque ou un répertoire, mais n'a pas la possibilité d'accéder et de modifier le contenu d'un fichier.
Java IO Stream est une conception utilisée pour lire et écrire des contenus de fichiers. Il peut compléter le transfert de données du contenu des fichiers de disque de sortie vers la mémoire ou les données de mémoire de sortie en fichiers de disque.
Le design des flux Java IO n'est pas parfait. Il a conçu un grand nombre de classes, ce qui a accru notre compréhension des flux IO, mais il n'y a que deux grandes catégories: l'une est des flux d'octets pour les fichiers binaires, et l'autre est des flux de caractères pour les fichiers texte. Dans cet article, nous apprendrons d'abord les principes et les scénarios d'utilisation des types connexes de flux d'octets. Les types de flux spécifiques principalement impliqués sont les suivants:
Entrée de flux d'octets de classe de base / OutputStream
InputStream et OutputStream sont les classes de base pour la lecture des flux d'octets et l'écriture de flux d'octets respectivement. Tous les flux liés aux octets doivent hériter de l'un d'eux. En tant que classe abstraite, ils définissent également les opérations de lecture et d'écriture les plus élémentaires. Jetons un coup d'œil:
Prenez InputStream comme exemple:
Public Abstract int Read () lève IOException;
Il s'agit d'une méthode abstraite et ne fournit pas d'implémentation par défaut, exigeant que les sous-classes doivent être implémentées. Le but de cette méthode est de renvoyer l'octet suivant du fichier actuel pour vous.
Bien sûr, vous constaterez également que la valeur de retour de cette méthode est reçue en utilisant le type entier "int", alors pourquoi ne pas utiliser "Byte"?
Tout d'abord, la valeur renvoyée par la méthode de lecture doit être un binaire à huit bits, et l'intervalle de valeur qui peut être pris par un binaire huit bits est: "0000 0000, 1111 1111", c'est-à-dire la plage [-128, 127].
La méthode de lecture spécifie également que lorsque le fichier est lu à la fin, c'est-à-dire que le fichier n'a pas d'octet suivant pour la lecture, la valeur -1 sera renvoyée. Donc, si l'octet est utilisé comme type de valeur de retour, alors lorsque la méthode renvoie un -1, devrions-nous déterminer s'il s'agit du contenu de données dans le fichier ou la fin du flux?
Le type int occupe quatre octets, et les trois octets dans le bit élevé sont tous 0. Nous n'utilisons que son octet de bit le plus bas. Lors de la rencontre de la fin du drapeau du flux, il renvoie -1 (32 1s) représenté par quatre octets, ce qui est naturellement différent de la valeur -1 (24 0 + 8 1s) représentant les données.
Ensuite, c'est également une méthode de lecture, mais InputStream fournit une implémentation par défaut:
public int Read (byte b []) lève ioException {return read (b, 0, b.length);} public int lien (byte b [], int off, int len) lance ioException {// afin de ne pas faire la longueur trop longue, vous pouvez afficher le code source JDK par vous-même}Ces deux méthodes sont essentiellement les mêmes. La première méthode est une forme spéciale de la deuxième méthode, qui permet de passer un tableau d'octets et nécessite que le programme remplisse les octets lus dans le fichier à partir de la position d'index de tableau 0 pour remplir le nombre d'octets dans la longueur du tableau.
La deuxième méthode est un peu plus large, ce qui vous permet de spécifier la position de départ et le nombre total d'octets.
Il existe plusieurs autres méthodes dans InputStream, qui ne sont essentiellement pas implémentées en détail. Jetons un coup d'œil brièvement.
La méthode Mark marquera un drapeau à la position de lecture du flux actuel, et la méthode de réinitialisation réinitialise le pointeur de lecture vers l'indicateur.
En fait, il est impossible de réinitialiser la lecture pour la lecture des fichiers, mais généralement tous les octets entre la position du drapeau et le point de réinitialisation sont temporairement enregistrés. Lorsque la méthode de réinitialisation est appelée, il est en fait une lecture répétée de l'ensemble d'octets temporaires enregistré, donc Readlimit est utilisé pour limiter la capacité de cache maximale.
La méthode MarkSupportée est utilisée pour déterminer si le flux actuel prend en charge cette opération de lecture "Fallback".
OutputStream et InputStream sont similaires, sauf que l'un est écrit et l'autre est lu. Nous ne le répéterons pas ici.
Fichier octet Stream FileInput / OutputStream
Nous nous concentrons toujours sur FileInputStream, et FileOutputStream est similaire.
Tout d'abord, FileInputStream a les constructeurs suivants pour instancier un objet:
public FileInputStream (nom de chaîne) lève FileToTFoundException {this (name! = null? Nouveau fichier (nom): null);} public fileInputStream (fichier file) lève filenotfoundException {String name = (file! = null? file.getPath (): null); SecurityManager Security = System.getSecurityManager (); if (Security! = null) {Security.CheckRead (name); } if (name == null) {throw new NullPointerException (); } if (file.isinvalid ()) {lancer un nouveau filenotfoundException ("chemin de fichier invalide"); } fd = new FileDescriptor (); fd.attach (ceci); path = name; ouvert (nom);}Ces deux constructeurs sont essentiellement les mêmes, le premier est la forme spéciale de la seconde. En fait, ne regardez pas cette dernière méthode, dont la plupart ne font que la vérification de la sécurité. Le noyau est une méthode ouverte, qui est utilisée pour ouvrir un fichier.
Principalement ces deux constructeurs, si le fichier n'existe pas ou si le chemin et le nom du fichier sont illégaux, un filenotfoundException sera lancé.
N'oubliez pas que nous avons dit qu'il existe une méthode abstraite lue dans la classe de base InputStream qui nécessite que toutes les sous-classes soient implémentées, et FileInputStream est implémenté à l'aide d'une méthode locale:
public int read () lève ioException {return read0 ();} private native int read0 () lève ioException;Nous n'avons aucun moyen d'explorer la mise en œuvre spécifique de Read0 pour le moment, mais vous devez être clair que la fonction de cette méthode de lecture est utilisée pour retourner l'octet suivant dans le flux et retour à -1. Cela signifie qu'il est lu à la fin du fichier et qu'il n'y a pas d'octets à lire.
De plus, il existe d'autres méthodes liées à la lecture dans FileInputStream, mais la plupart d'entre elles sont implémentées à l'aide de méthodes locales. Jetons un coup d'œil ici:
Les méthodes internes de FileInputStream sont essentiellement comme celle-ci, et il y en a des avancées et complexes que nous ne pouvons pas utiliser pour le moment. Nous l'apprendrons plus tard. Jetons un bref aperçu d'un exemple de lecture de fichiers:
public static void main (String [] args) lève ioException {fileInputStream input = new FileInputStream ("c: //users//yanga//desktop//test.txt"); octet [] tampon = nouveau octet [1024]; int len = input.read (tampon); String str = new String (tampon); System.out.println (STR); System.out.println (len); input.close ();}Le résultat de sortie est très simple. Il imprimera le contenu de notre fichier de test et le nombre réel d'octets lus, mais les étudiants prudents le découvriront, comment pouvez-vous vous assurer que le contenu du fichier de test ne dépassera pas 1024 octets?
Afin de lire pleinement le contenu du fichier, une solution consiste à définir le tampon suffisamment grand pour s'attendre à stocker tous les contenus du fichier autant que possible.
Cette méthode est évidemment indésirable car il nous est impossible de réaliser la taille réelle du fichier à lire. C'est une très mauvaise solution pour simplement créer un tableau d'octets surdimensionné.
La deuxième façon est d'utiliser notre flux de tableau d'octets dynamique, qui peut ajuster dynamiquement la taille du réseau d'octets interne pour garantir une capacité appropriée, que nous introduirons en détail plus tard.
En ce qui concerne FileOutputStream, une autre chose à souligner est son constructeur, qui a les deux constructeurs suivants:
FileOutputStream public (nom de chaîne, booléen append) public FileOutputStream (fichier de fichier, booléen append)
L'append de paramètre indique si le fonctionnement d'écriture de ce flux est écrasé ou annexé, True signifie annexé, faux moyens écrasés.
BytearrayInput / OutputStream
Le soi-disant "flux de tableau d'octets" est un flux qui fonctionne autour d'un tableau d'octets. Il ne lit pas et n'écrit pas de flux sur des fichiers comme d'autres flux.
Bien que le flux de tableau d'octets ne soit pas un flux basé sur des fichiers, il s'agit toujours d'un flux très important, car le tableau d'octets encapsulé à l'intérieur n'est pas fixe, mais dynamiquement extensible, et est souvent basé sur certains scénarios, ce qui est très approprié.
ByteArrayInputStream est un flux de tableaux d'octets de lecture qui peuvent être instanciés par le constructeur suivant:
octet protégé buf []; protégé int pos; int protégée int; public bytearrayInputStream (octet buf []) {this.buf = buf; this.pos = 0; this.count = buf.length;} public bytearrayInputStream (byte buf [], int offset, intyl)BUF est un réseau d'octets encapsulé à l'intérieur de ByteArrayInputStream. Toutes les opérations de lecture de ByteArrayInputStream tournent autour de lui.
Par conséquent, lors de l'instanciation d'un objet ByteArrayInputStream, au moins un tableau d'octet cible est passé.
L'attribut POS est utilisé pour enregistrer la position de la lecture actuelle du flux et le nombre enregistre la dernière position du dernier indice d'octet valide du tableau d'octets cible.
Après avoir compris cela, il n'est pas difficile de lire différentes façons de le lire:
// Lire le prochain octet public synchronisé int lien () {return (pos <count)? (buf [pos ++] & 0xff): -1;} // lire les octets Len et les mettre dans le tableau d'octets b public synchronisé int linde (byte b [], int off, int len) {// même, le corps de la méthode est plus long, tout le monde vérifie son propre jdk}De plus, ByTearrayInputStream implémente également très simplement l'opération "Repeat Read".
public void Mark (int ReadaHeadliMit) {Mark = pos;} public synchronisé void reset () {pos = mark;}Étant donné que ByteArrayInputStream est basé sur des tableaux d'octets, toutes les opérations de lecture répétées sont plus faciles à mettre en œuvre, et il suffit d'implémenter en fonction des index.
ByteArrayOutputStream est un flux de tableau d'octets écrit. De nombreuses implémentations ont toujours leurs propres caractéristiques. Jetons un coup d'œil ensemble.
Premièrement, ces deux propriétés sont nécessaires:
octet protégé buf []; // Le nombre représente ici le nombre d'octets valides dans le nombre int protégé BUF;
Constructeur:
public byTearrayOutputStream () {this (32);} public bytearrayoutputStream (int size) {if (size <0) {lance un nouveau IllégalArgumentException ("Taille initiale négative:" + taille); } buf = nouveau octet [taille];}La tâche principale du constructeur est d'initialiser le tableau de tableau d'octets interne, vous permettant de passer en taille pour limiter explicitement la taille du tableau d'octets initialisé, sinon la longueur par défaut sera de 32.
Écrivez du contenu à bytearrayoutputStream de l'extérieur:
public synchronisé void write (int b) {asurecapacité (count + 1); buf [count] = (byte) b; Count + = 1;} public synchronisé void write (byte b [], int off, int len) {if ((off <0) || (off> b.length) || (len <0) || ((off + len) - b.length> 0)) {lance new indexoutofboundSexception (); } assurecapacité (count + len); System.ArrayCopy (B, OFF, BUF, COUNT, LEN); compter + = len;}Voyant cela, la première étape de toutes les opérations d'écriture est d'appeler la méthode d'assurance, le but est de s'assurer que le tableau d'octets dans le flux actuel peut s'adapter à cette opération d'écriture.
Cette méthode est également très intéressante. Si vous constatez que le BUF interne ne peut pas prendre en charge cette opération d'écriture après le calcul, la méthode de croissance sera appelée à l'expansion. Le principe d'expansion de la capacité est similaire à celui de l'arrayList, étendu à deux fois la capacité d'origine.
De plus, ByteArrayoutputStream a également une méthode WriteTo:
Le public synchronisé void writeTo (OutputStream out) lève ioException {out.write (buf, 0, count);}Écrivez notre tableau d'octets encapsulé en interne dans un flux de sortie.
Certaines des méthodes restantes sont également très couramment utilisées:
Notez que bien que ces deux flux soient appelés "flux", ils n'allouent essentiellement pas certaines ressources comme de vrais flux, nous n'avons donc pas besoin d'appeler sa méthode étroite, et il est inutile de l'appeler (le responsable a dit, n'a aucun effet).
Les cas de test ne seront pas publiés. Je téléchargerai tous les cas de code utilisés dans cet article plus tard. Vous pouvez choisir de les télécharger par vous-même.
Afin de contrôler la longueur, l'apprentissage restant sera placé dans le prochain article.
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.