Maison  >  Article  >  Java  >  Cours d'apprentissage sur les réflexions sur la programmation Java (5) Chapitre 18-Java IO System

Cours d'apprentissage sur les réflexions sur la programmation Java (5) Chapitre 18-Java IO System

php是最好的语言
php是最好的语言original
2018-08-09 14:45:091613parcourir

1 Classe File

  FileLe nom de la classe (File) est quelque peu trompeur ; On pourrait penser qu'il fait référence à un fichier, mais ce n'est pas le cas. Il peut représenter non seulement le nom d'un fichier spécifique , mais aussi le d'un groupe de fichiers dans un répertoire . >Nom. En fait, FilePath (chemin du fichier) est un meilleur nom pour cette classe.

   S'il fait référence à une collection de fichiers, on peut appeler la méthode

list() sur cette collection, qui renverra un tableau de chaînes.

2 Entrée et sortie (Saisir une sortie)

  Les bibliothèques de classes d'E/S des langages de programmation utilisent souvent le concept abstrait de

flux , qui représente Tout objet source de données capable de produire des données ou un objet de réception capable de recevoir des données. Les « flux » masquent les détails du traitement des données dans le périphérique d'E/S réel.

Nous utilisons rarement une seule classe pour créer un objet de flux, mais fournissons plutôt la fonctionnalité souhaitée en superposant plusieurs objets (c'est le modèle de conception du décorateur). En fait, la principale raison pour laquelle la bibliothèque « stream » en Java prête à confusion est que pour créer un seul flux de résultats, vous devez créer plusieurs objets.

  Dans Java 1.0, le concepteur de la bibliothèque de classes a d'abord défini que toutes les classes liées à

entrée devaient hériter de InputStream, tandis que 🎜>Sortie Toutes les classes liées à doivent hériter de OutputStream.

  read() dans InputStream ou Reader est utilisé pour lire un seul

octet ou tableau d'octets, et OutputStream ou Writer est utilisé pour écrire un seul octet ou un tableau d'octets .

2.1 Le type InputStream

  

est utilisé pour représenter des classes qui génèrent des données d'entrée à partir de différentes InputStream sources de données . Chaque source de données a une sous-classe InputStream correspondante . Ces sources de données incluent :

  • tableau d'octets. Un tableau de bbytes.

  • Objets chaîne. Un objet String.

  • fichier. Un fichier.

  • "Un tuyau" (Un tuyau), fonctionne comme un véritable tuyau, c'est-à-dire que l'entrée se fait à partir d'une extrémité et la sortie à l'autre extrémité.

  • Une séquence composée d'autres types de flux afin que nous puissions les rassembler en un seul flux. Une séquence d'autres flux.

  • Autres sources de données, telles que les connexions Internet, etc. Autres sources.

2.2 Type OutputStream

  

la classe détermine la cible où va la sortie : OutputStream

  • section word array

  • Fichier

  • Pipeline

3 Ajouter des propriétés et des interfaces utiles

et FilterInputStream sont utilisés pour fournir une FilterOutputStream interface de classe décorateur pour contrôler un flux d'entrée spécifique (InputStream) et Les deux classes de flux de sortie (OutputStream), leurs noms ne sont pas intuitifs. Ces deux classes sont nécessaires aux décorateurs (afin de fournir une interface commune à tous les objets à décorer).

4 Reader et Writer

  • et InputStreamOutputStream fournissent des E/S orientées octets sous la forme de Les fonctions

  • et ReaderWriter sont des fonctions d'E/S orientées caractères sous la forme de (compatible Unicode)

Les hiérarchies d'héritage

et Reader sont conçues principalement pour l'Writerinternationalisation . L’ancienne hiérarchie d’héritage des flux d’E/S ne prenait en charge que les 8 flux d’octets de bits et ne gérait pas correctement les caractères Unicode 16 bits . Puisque Unicode est utilisé pour l'internationalisation des caractères (le caractère propre de Java est également Unicode 16 bits), donc l'ajout de et Reader hiérarchie d'héritage consiste à garantir que tous WriterUnicode est pris en charge dans toutes les opérations d'E/S. De plus, la conception de la nouvelle bibliothèque de classes rend son fonctionnement plus rapide que l'ancienne bibliothèque de classes.

5 Classe autonome : RandomAccessFile

convient aux fichiers constitués d'enregistrements de taille connue, nous pouvons donc utiliser RandomAccessFile pour transférer des enregistrements de Déplacez-vous d'un endroit à un autre, puis lisez ou modifiez les enregistrements. seek()

RandomAccessFile a un comportement fondamentalement différent de celui des autres types d'E/S dans la mesure où nous pouvons avancer et reculer dans un fichier. Dans tous les cas, il est autonome et dérivé directement de Object.

essentiellement, RandomAccessFile fonctionne comme une combinaison de DataInputStream et DataOutputStream, avec quelques nouvelles méthodes ajoutées :

  • getFilePointer() Utilisé pour trouver l'emplacement actuel du fichier,

  • seek() utilisé pour se déplacer vers un nouvel emplacement dans le fichier,

  • length()Utilisé pour déterminer la taille maximale du fichier.

6 Utilisations typiques des flux d'E/S

Bien que les flux d'E/S puissent être combinés de différentes manières, nous ne pouvons utiliser que quelques combinaisons d'eux. Les exemples suivants peuvent être utilisés comme référence de base pour une utilisation typique des E/S.

6.1 Fichier d'entrée tamponné

6.2 Entrée depuis la mémoire

6.3 Entrée mémoire formatée

6.4 Sortie de fichier de base

6.5 Stockage et récupération de données

6.6 Lecture et écriture de fichiers à accès aléatoire (fichiers d'accès)

6.7 PipedStreams

7 E/S standard

Standard I Le terme /O fait référence au concept Unix de "un flux unique d'informations utilisé par un programme".

L'importance des E/S standard est que nous pouvons facilement connecter des programmes entre eux, et la sortie standard d'un programme peut devenir l'entrée standard d'un autre programme.

8 nouvelles E/S

L'augmentation de la vitesse vient de l'utilisation d'une structure plus proche de la façon dont le système d'exploitation effectue les E/S : Canaux et Tampons. Nous pouvons le considérer comme une mine de charbon, les canaux sont les gisements contenant les veines de charbon (données) et les tampons sont les camions qui sont expédiés vers les gisements. Les camions reviennent chargés de charbon et nous récupérons le charbon des camions. En d'autres termes, nous n'interagissons pas directement avec le canal, nous interagissons simplement avec le tampon et envoyons le tampon au canal. Un canal récupère les données d'un tampon ou envoie des données à un tampon.

Les seuls tampons qui interagissent directement avec les canaux sont ByteBuffer - c'est-à-dire des tampons qui peuvent stocker des octets bruts. Lorsque nous interrogeons la documentation du JDK pour java.nio.ByteBuffer, nous constatons qu'il s'agit d'une classe assez basique : elle crée un objet ByteBuffer en lui indiquant la quantité de stockage à allouer, et elle dispose également d'une sélection de méthodes qui renvoient les octets bruts. Générez et lisez des données à partir de types de données formels ou primitifs. Cependant, il n'existe aucun moyen de générer ou de lire des objets, pas même des objets chaîne. Cette gestion est de bas niveau, mais elle est parfaite car c'est le moyen de mappage le plus efficace dans la plupart des systèmes d'exploitation.

8.1 Channel FileChannel

FileChannel manipule le flux d'octets . Trois classes de l'ancienne bibliothèque d'E/S ont été modifiées pour générer FileChannel :

  • FileInputStream.getChannel()

  • FileOutputSteam.getChannel ()

  • RandomAccessFile.getChannel()

package net.mrliuli.io.nio;import java.nio.*;import java.nio.channels.*;import java.io.*;public class GetChannel {
    private static final int BSIZE = 1024;
    public static void main(String[] args) throws Exception {
        // Write a file:
        FileChannel fc = new FileOutputStream("data.txt").getChannel();
        fc.write(ByteBuffer.wrap("Some text ".getBytes()));
        /*
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        fc.read(buffer);                                            // NonReadableChannelException
        System.out.println((char)buffer.get());
        */
        fc.close();
        // Add to the end of the file:
        fc = new RandomAccessFile("data.txt", "rw").getChannel();   // Readable and Writable        
        fc.position(fc.size()); // Move to the end      
        fc.write(ByteBuffer.wrap("some more".getBytes()));
        fc.close();
        // Read the file:
        fc = new FileInputStream("data.txt").getChannel();
        ByteBuffer buff = ByteBuffer.allocate(BSIZE);       
        fc.read(buff);
        //fc.write(ByteBuffer.wrap("again".getBytes()));            //NonWritableChannelException
        buff.flip();
        while(buff.hasRemaining())
            System.out.print((char)buff.get()); // ByteBuffer.get() returns a byte
        System.out.println();
    }
}

8.2 Buffer ByteBuffer

Convertir les octets Méthode de stockage dans le buffer ByteBuffer :

  • Utilisez put() pour remplir directement un ou plusieurs octets, ou une valeur d'un type de données de base

  • Utilisez wrap() pour envelopper le tableau d'octets existant dans ByteBuffer.

8.3 read(), write(), flip(), write()

  Il y a un canal d'entrée in, un canal de sortie out et Un tampon buffer :

  • in.read(buffer); entre les octets de fc dans buffer À ce moment, buffer.flip(); Soyez prêt à ce que d'autres lisent les octets de . buffer

  • out.write(buffer) sort les octets de vers buffer Après l'opération out, les informations sont toujours dans le tampon write(). , doit appeler bufferbuffer.clear(); pour réorganiser tous les pointeurs internes afin que le tampon soit prêt à accepter des données lors d'une autre opération. read()

package net.mrliuli.io.nio;

import java.io.*;
import java.nio.*;
import java.nio.channels.*;public class ChannelCopy {    private static final int BSIZE = 1024;    public static void main(String[] args) throws Exception {        if(args.length != 2){
            System.out.println("arguments : sourcefile destfile");
            System.exit(1);
        }        // 打开一个FileChaanel用于读(输入)
        FileChannel in = new FileInputStream(args[0]).getChannel();        // 打开一个FileChannel用于写(输出)
        FileChannel out = new FileOutputStream(args[1]).getChannel();        // 一个缓冲器,分配了BSIZE个字节
        ByteBuffer buffer = ByteBuffer.allocate(BSIZE);        /*
         * return The number of bytes read, possibly zero, or <tt>-1</tt> if the channel has reached end-of-stream
         * FileChanel.read()
         * */

        // -1 一个分界符(源于Unix和C),表示到达了输入的末尾
        while(in.read(buffer) != -1){

            buffer.flip(); // Prepare for writing
            out.write(buffer);            // write()操作之后,信息仍在缓冲器中,clear()操作对所有的内部指针重新安排,以便缓冲器在另一个read()操作期间能够做好接受数据的准备。
            buffer.clear(); // Prepare for reading
        }

    }

}

8.4 转换数据

缓冲器容纳的是普通的字节,为了把它们转换成字符,我们要么在输入它们的时候对其进行编码(这样,它们输出时才具有意义),要么在将其从缓冲器输出时对它们进行解码。可以使用java.nio.charset.Charset类实现这些功能,该类提供子把数据编码成多种不同类型的字符集的工具。The buffer contains plain bytes, and to turn these into characters, we must either encode them as we put them in (so that they will be meaningful when they come out) or decode them as they come out of the buffer. This can be accomplished using the java.nio.charset.Charset class, which provides tools for encoding into many different types of character set.

8.5 视图缓冲器

  视图缓冲器(view buffer)可以让我们通过某个特定的基本数据类型的视窗查看其底层的ByteBuffer。ByteBuffer依然是实际存储数据的地方,“支持”着前面的视图,因此对视图的任何修改都会映射成为对ByteBuffer中数据的修改。

8.6 文件加锁

  文件加锁对其他的操作系统进程是可见的,因为Java的文件加锁直接映射到了本地操作系统的加锁工具。

exclusive lock 独占锁

Locking portions of a mapped file 对映射文件的部分加锁

cretical section 临界区

9 压缩(Compression)

10 对象序列化(Object serialization)

Java的对象序列化将那些实现了Serilizable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。这一过程甚至可通过网络朝廷这意味着序列化机制能自动弥补不同操作系统之间的差异。

就其本身来说,对象的序列化是非常有趣的,因为利用它可以实现轻量级持久性(ligthweight persistence)。持久性意味着一个对象的生存周期并不取决于程序是否正在执行,它可以生存于程序的调用之间。

  对象序列化的概念加入到语言中是为了支持两种主要特性:

  • 一是Java的远程方法调用(Remote Method Invocation, RMI),它使存活于其他计算机的对象使用起来就像是存活于本机上一样。当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。

  • 再者,对Java Beans来说,对象的序列化也是必需的。使用一个Bean时,一般情况下是在设计阶段对它的状态信息进行配置。这种状态信息必须保存下来,并在程序启动时进行后期恢复;这种具体工作就是由对象序列化完成的。

  序列化一个对象和反序列化

  • 首先要创建一个ObjectOutputStream对象,要通过构造函数含有一个 OutputStream 对象。

  • 然后,只需调用 void writeObject(Object obj),即可将对象obj序列化,即转换成字节序列输出到第一步所说的Outputstream

  • 反序列化,即将字节序列还原为一个对象,则只需调用ObjectInputStreamObject readObject(),输入到一个InputStream

例:

Worm.java

10.1 寻找类

  反序列,即将字节序列还原为对象时,必须保证Java虚拟机能够找到要还原的对象的相关.class文件,否则抛出java.lang.ClassNotFoundException异常。

10.2 序列化的控制

  如果只希望一个对象的某些信息序列化而某些信息不序列化,即进行序列化控制,可使用Externalizable接口。

10.2.1 Externalizable接口

  Externalizable接口继承自Serializable接口,有两个方法如下,这两个方法会在序列化和反序列化过程中被自动调用

  • void writeExternal(ObjectOutput obj),在该方法内部只对所需部分进行显式序列化

  • void readExternal(ObjectInput in)

10.2.2 Externalizable接口与Serializable接口区别

  • Externalizable只序列化writeExternal()中的部分,而Serializable自动地全部序列化。

  • Externalizable在反序列化时(即调用readObject()时),会首先调用所有普通的默认构造器,然后调用readExternal()

  • Serializable在反序列化时,对象完全以它存储的二进制位为基础来构造,而不用调用构造器

例:

Blips.javaBlip3.java

10.2.3 transient(瞬时)关键字

如果我们正操作的是一个Serializable对象,那么所有序列化操作都会自动进行。为了能够予以控制,可以用transient(瞬时)关键字逐个字段地关闭序列化,它的意思是“不用麻烦你保存或恢复数据——我会自己处理的”。

由于Externalizable对象在默认情况下不保存任何字段,所以transient关键字只能和Serializable对象一起使用。

10.3 序列化的持久性

我们可以通过一个字节数组来使用对象序列化,从而实现对任何可Serializable对象的“深度复制”(deep copy)——深度复制意味着我们复制的是整个对象网,而不仅仅是基本对象及其引用。

  • 一个对象被序列化在单一流中,就可以恢复出与我们写出时一样的对象网,并且没有任何意外重复复制出的对象。

  • 一个对象被序列化在不同流中,再从不同流恢复时,得到的对象地址不同。

例:

MyWorld.java

对象序列化的一个重要限制是它只是Java的解决方案:只有Java程序才能反序列化这种对象。一种更具互操作性的解决方案是将数据转换为XML格式,这可以使其被各种各样的平台语言使用。

相关文章:

Java编程思想学习课时(三)第15章-泛型

Java编程思想学习课时(四)第17章-容器深入探讨

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn