Comme pour beaucoup de logithèques le challenge à relever pour Java était de mettre au point des principes utilisables sur des plate-formes de nature très différentes.
Les systèmes d’entrée/sortie (abréviation "E/S") disponibles en standard en Java sont essentiellement:
InputStream
et OutputStream
du package java.io
.
java.io
:
rarement utilisés dans du code applicatif car il n’y pas de notion de structure de données de taille fixe comme en langage C
-ce code sert plutôt à la réalisation d’utilitaires -
java.nio
)
Ce chapitre aborde les flots d’E/S ("stream") qui sont largement utilisés et ressemblent
aux E/S UNIX primordiales. Les principes de java.nio
seront abordés ultérieurement dans un autre chapitre.
Un flot n’est ouvert que dans un sens -ici en lecture- (l'écriture se fera par l’ouverture d’un autre flot: ce modèle ne connaît pas les E/S bidirectionnelles).
Chaque opération de read
"consomme" des données
Inversement chaque opération de write
dans un OutputStream
"poussera" des données.
Le même modèle peut s’appliquer à des ressources très différentes qui produisent des octets que le stream va consommer.
Ici les octets peuvent venir de différents dispositifs:
InputStream in ; // n'importe ... // par exemple : in = new FileInputStream(filename) ; new DataInputStream(new BufferedInputStream(in)) :
On peut ainsi créer des dispositifs d’E/S à la demande: par exemple un
ObjectInputStream
(pour lire directement des objets java) sur un flot
compressé, crypté, bufférisé sur une ligne de communication (flot TCP/IP sur connecteur réseau "socket").
Les flots fondamentaux lisent ou écrivent des octets. Diverses méthodes d’assez bas niveau permettent des opérations sur plusieurs octets.
java.io.InputStream int read() throws IOException // lit un octet comme un int // + autres read(°°°) de bas niveau java.io.OutputStream void write(int byte) throws IOException // écrit un octet avec un argument sous forme de int // + autres write(°°°) de bas niveau
Dans les deux classes on a:
void close() throws IOException
Comme le codage fondamental des caractères en Java est UTF16 (deux octets)
Les flots de base pour gérer le type char
sont différents de
InputStream, OutputStream
.
java.io.Reader int read() throws IOException // lit un "char" dans un "int" // + autres read(°°°) de bas niveau java.io.Writer void write(int character) throws IOException // écrit un "char" en passant par un "int" // + autres write(°°°) de bas niveau
et, bien sûr, d’autres méthodes comme close()
.
InputStream
|
Reader
| |
---|---|---|
tableau mémoire |
ByteArrayInputStream
|
CharArrayReader StringReader
|
"Pipe" |
PipedInputStream
|
PipedReader
|
fichier |
FileInputStream
|
FileReader (classe "de confort")
|
"fabriques": |
filtrées par InputStreamReader
| |
java.lang.Process getInputStream()
| ||
java.net.Socket getInputStream()
| ||
java.net.URL openStream()
| ||
… |
Chaque fois qu’un flot lit des données caractères venu du monde "extérieur" à Java (fichier, socket ,…)
il n’est pas garanti que le codage soit de l’UTF16!
On a besoin d’un InputStreamReader
pour opérer des conversions appropriées.
Les classes InputStreamReader
et OutputStreamWriter
permettent
de connecter des flots d’octets et des flots de caractères en opérant des conversions.
Conversions de caractères.
// se reformule avec un try(création AutoCloseable) try { InputStream fis = new FileInputStream("unfichier.txt") ; Reader ir = new InputStreamReader(fis,"ISO-8859-1") ; //..... } catch (FileNotFoundException exc) {//.... } catch (UnsupportedEncodingException exc) {//.... }
Le second argument est une chaîne désignant le type de codage( «ISO-8859-1»
ou «ISO-8859-15» pour la plupart des pays d’Europe de l’ouest, «Cp1252» sous MS-Windows
).
Les liste des codages se trouve dans la documentation docs/guide/internat/encoding.doc.html
-voir aussi l’utilitaire
native2ascii
ou la documentation de java.nio.charset
-.
![]() | |
Il existe un codage de nom |
Pour ces deux classes il existe un constructeur avec un seul argument: le mode de codage par défaut résultant de la configuration du système d’exploitation est alors retenu.
Les constructeurs de classes "filtre" ont toujours un autre flot en paramètre:
public BufferedInputStream(InputStream in) ... public DataInputStream(InputStream in)...
C’est en enchainant le passage des flots aux constructeurs qu’on combine les comportements.
BufferedInputStream bis = new BufferedInputStream( new FileInputStream (filename)) ; DataOutputStream dos = new DataOuputStream( new BufferedOutputStream ( new FileOutputStream (filename))) ;
Certaines classes filtres ont des méthodes spécifiques (comme writeInt
pour DataOutputStream
).
Noter l’utilisation de flush()
qui est transmis au BufferedOutputStream
dans l’enchainement des filtres.
Utilisation de filtres.
try { dos.writeInt(235); dos.writeDouble(Math.PI); dos.writeUTF("Une chaîne avec des caractères accentués") ; // chaîne écrite en UTF8 dos.flush() ; // pour le BufferedOutputStream // .... } finally { dos.close() ; // ferme toute la chaîne des flots // sauf si try initial avec AutoCloseable } catch(IOException exc) { // au rapport! }
import java.nio.file.* ; import java.nio.charset.* ; .... String home =System.getProperty("user.home") ; // si on a les droits!!! (pas garanti) //noter la désignation indépendante du Système d'exploitation Path file = Paths.get(home, "java", "todolist.txt"); // try avec AutoCloseable // noter l'utilisation des classes Files et StandardCharsets try (Reader output = Files.newBufferedReader(file, StandardCharsets.UTF_8)) { // code }
![]() | |
Voir également des utilitaires généraux dans |