Java en 5 leçons

Partie V Streams

Leçon 1 et 2 Leçon 3 Leçon 4 Leçon 5

eric@netline.be

Classiquement, le traitement opéré par un ordinateur sur des données se résume à recevoir ces données via un port d'entrée comme le clavier et les transmettre à un port de sortie comme l'écran. L'ordinateur gère des flux de données qu'on appelle généralement en anglais des "streams". Un "input stream" recueille les données en provenance du monde extérieur vers l'ordinateur tandis qu'un "output stream" dirige les données vers des périphériques de sortie comme un écran ou un fichier.

Les streams à la sauce Java sont très généraux, un stream ne définit pas spécifiquement à quel périphérique il est attaché. En Java, les streams sont bien sûr représentés par des classes définies dans le package java.io :

Nos cinq leçons Java seront bien insuffisantes pour traiter la totalité de ces streams mais nous nous attarderons néanmoins sur les plus importants.

Input et Output sont dans un bateau

Vous l'aurez deviné, des classes spécifiques comme FileInputStream et ByteArrayOutputStream héritent des propriétés et méthodes des classes de base InputStream et OutputStream qui sont des classes abstraites qui ne peuvent pas être utilisées directement

La classe InputStream

La classe InputStream dispose d'un jeu de méthodes pour les streams en entrée.

Méthode

Description

read()

lit des données du stream

long skip(long n)

saute un certain nombre d'octets du stream

int available()

renvoie le nombre d'octets directement disponibles dans le stram

void mark(int readlimit)

marque une position dans le stream

void reset()

retourne à une position marquée dans le stream

boolean markSupported()

renvoie une valeur booléenne si le stream accepte les méthodes mark et reset

void close()

ferme le stream

La méthode read se décline en trois versions selon les paramètres utilisés

int read() lit un seul octet en entrée en renvoyant -1 lorsqu'il n'y a plus de données à lire
int read(byte b[]) lit plusieurs octests sous forme de tableau en renvoyant le nombre d'octets qui viennent d'être lus
int read(byte b[], int off, int len) lit plusieurs octets à partir de la position off sur une longueur len

 

La classe OutputStream

La contrepartie d'InputStream pour les opérations d'écriture s'appelle OutputStream et dispose des méthodes suivantes

Méthode

Description

write()

écriture vers le stream

flush()

Force tout output bufférisé en écriture

close()

ferme le stream

Comme le read() d'InputStream, le write() d'OutputStream fait appel à trois constructeurs

void write(int b)
void write(byte b[]) 
void write(byte b[], int off, int len)

System.in et System.out

Pour gérer les périphériques standard d'entrée et sortie, Java définit en standard deux objets de base system.in et system.out. L'objet system.in object (instancié à partir d'InputStream ) permet la saisie de caractères tapés tandis que l'objet system.out les dirigent vers.

 

PrintStream

System.out est dérivé d'une classe PrintStream spécialement conçue pour l'impression de valeurs sous forme de texte et dont voici les méthodes

Méthode

Description

write()

écriture vers le stream

flush()

flush du stream

checkError()

flush du stream plus renvoi de messages d'erreurs

print()

imprime les données sous forme de texte

println()

imprime une ligne de texte suivi d'un saut de ligne

close()

ferme le stream

 

FileInputStream

Pour des accès fichiers simples, faites appel à FileInputStream dérivée elle-même d' InputStream. Pour créer un objet dans la classe FileInputStream vous aurez accès aux constructeurs:

FileInputStream(String name) 
FileInputStream(File file)
FileInputStream(FileDescriptor fdObj)


Voici par exemple une petite application java qui lit son propre fichier source, le place dans un string avant de l'afficher à l'écran.

import java.io.*;
class autoApp
{
    public static void main(String args[])
    {
        byte buffer[] = new byte[1024];
        try
        {
            FileInputStream fileIn =  new FileInputStream("autoapp.java");
            int bytes = fileIn.read(buffer, 0, 1024);
            String str = new String(buffer, 0, 0, bytes);
            System.out.println(str);
        }
        catch (Exception e)
        {
            String err = e.toString();
            System.out.println(err);
        }
    }
}

 

FileOutputStream

FileOutputStream a ses constructeurs dont vous pouvez aisément deviner les noms

FileOutputStream(String name)
FileOutputStream(File file)
FileOutputStream(FileDescriptor fdObj)

L'application que voici attend une ligne de caractères au clavier qu'elle va écrire dans le fichier autoapp.txt

import java.io.*;
class autoApp2
{
    public static void main(String args[])
    {
        byte buffer[] = new byte[80];
        try
        {
            System.out.println ("\nEntrez une ligne de caractères à sauver sur disque");
            int bytes = System.in.read(buffer);
            FileOutputStream fileOut = new FileOutputStream("autoapp.txt");
            fileOut.write(buffer, 0, bytes);
        }
        catch (Exception e)
        {
            String err = e.toString();
            System.out.println(err);
        }
    }
}

ou encore un exemple de fichier qui fait une copie de lui-même

Vous pouvez aisément passer de la classe File aux classes FileInputStream et FileOutputStream et vice versa

import java.io.*;

class fichier

{

public static void main(String args[])

{

byte buffer[] = new byte[1024];

try

{

FileInputStream fis = new FileInputStream(inputFile);

FileOutputStream fos = new FileOutputStream(outputFile);

int c;

fis.read(buffer,0,1024);

fos.write(buffer,0,1024);

while ((c = fis.read()) != -1)

{

fos.write(c);

}

fis.close();

fos.close();

}

catch (FileNotFoundException e)

{

System.err.println("FileTest: " + e);

}

catch (IOException e)

{

System.err.println("FileTest: " + e);

}

}

}

 

La classe File

La classe File est beaucoup plus complexe et puissante. Elle vous permettra de connaître tout d'un fichier, sa da te de création ou de modification, le créer, le renommer, le supprimer ou créer de nouveaux répertoires. Ses constructeurs sont

File(String path)
File(String path, String name)
File(File dir, String name)

Vous pouvez donc créer un objet de type File à partir de son nom complet comme suit File(c:\program\java\monfichier.java) ou bien en donnant répertoire et nom de fichier séparément File(c:\program\java, monfichier.java)

Méthode

Description

getName()

obtention d'un nom de fichier

getPath()

obtention du chemin d'accès du fichier

getAbsolutePath()

obtention du chemin d'accès absolu

getParent()

répertoire parent du fichier

exists()

renvoie true si le fichier existe

canWrite()

renvoie true si le fichier est accessible en écriture

canRead()

renvoie true si le fichier est accessible en lecture

isFile()

renvoie true si le fichier est valide

isDirectory()

renvoie true si le répertoire est valide

isAbsolute()

renvoie true si le fichier est absolu

lastModified()

renvoie la date de dernière modification

length()

retourne la longueur du fichier

mkdir()

crée un répertoire

renameTo()

renomme un fichier

mkdirs()

crée un arbre de répertoire

list()

obtient la liste des fichiers d'un répertoire

delete()

supprime un fichier

hashCode()

calcule un hashcode pour un fichier

equals()

compare deux objets de type File

toString()

crée une string contenant le répertoire d'un fichier

 

La classe RandomAccessFile

La classe RandomAccessFile est encore plus intéressante à retenir puisqu'elle permet de faire à peu près tout avec un fichier. Le constructeur RandomAccessFile(String name, String mode) s'emploie avec une chaîne de caractères contenant le nom de fichier suivi du mode d'accès "r" pour lecture ou "rw" pour lecture et écriture. Le constructeur

RandomAccessFile(File file, String mode) fait de même à partir de l'objet File et d'un mode r ou rw. Une fois ainsi créé, un fichier RandomAccess s'attaque avec les méthodes suivantes

Méthode

Description

close()

ferme le fichier

getFD()

obtient un objet FileDescriptor pour le fichier

getFilePointer()

obtient la position du pointeur sur le fichier

length()

retourne la longueur du fichier

read()

lecture de données

readBoolean()

lit un boolean

readByte()

lit un octet

readChar()

lit un char

readDouble()

lit un double (virgule flottante)

readFloat()

lit un float

readFully()

lit des données dans un tableau en remplissant celui-ci

readInt()

lit un entier

readLine()

lit une ligne

readLong()

lit un long

readShort()

lit un short integer

readUnsignedByte()

lit un octet non signé

readUnsignedShort()

lit un short integer non signé

readUTF()

lit une chaîne de type UTF

seek()

positionne le pointeur dans un fichier

skipBytes()

saute un nombre donné d'octets

write()

écrit vers le fichier

writeBoolean()

écrit un booelan

writeByte()

écrit un octet

writeBytes()

écrit une chaîne sous forme d'octets

writeChar()

écrit un char

writeChars()

écrit une chaîne sous forme de char

writeDouble()

écrit un double

writeFloat()

écrit un float

writeInt()

écrit un int

writeLong()

écrit un long

writeShort()

écrit un short int

writeUTF()

écrit une chaîne de type UTF

Voici comment combiner un peu tout cela:


import java.io.*;

class fichrandom

{

public static void main(String args[])

{

try

{

RandomAccessFile file = new RandomAccessFile("fichrandom.java","r");

long filePointer = 0;

long longueur = file.length();

while (filePointer < longueur)

{

String s = file.readLine();

System.out.println(s);

filePointer = file.getFilePointer();

}

file.close();

}

catch (Exception e)

{

String err = e.toString();

System.out.println(err);

}

}

}

Si vous savez maintenant utiliser des streams pour les fichiers, pourquoi ne pas les utiliser pour des applications réseau en utilisant des sockets ? Quid de vous connecter sur le serveur www.best.be sur le port 7 pour voir si le service echo vous répond bien ?

import java.io.*;
import java.net.*;

public class EchoTest {
    public static void main(String[] args) {
        Socket echoSocket = null;
        DataOutputStream os = null;
        DataInputStream is = null;
        DataInputStream stdIn = new DataInputStream(System.in);

        try {
            echoSocket = new Socket("www.best.be", 7);
            os = new DataOutputStream(echoSocket.getOutputStream());
            is = new DataInputStream(echoSocket.getInputStream());
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: best");
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for the connection to: best");
        }

        if (echoSocket != null && os != null && is != null) {
            try {
                String userInput;

                while ((userInput = stdIn.readLine()) != null) {
                    os.writeBytes(userInput);
                    os.writeByte('\n');
                    System.out.println("echo: " + is.readLine());
                }
                os.close();
                is.close();
                echoSocket.close();
            } catch (IOException e) {
                System.err.println("I/O failed on the connection to: best");
            }
        }
    }
}