Partie V Streams
Leçon 1 et 2 Leçon 3 Leçon 4 Leçon 5
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 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 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)
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.
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 |
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 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 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 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");
}
}
}
}