Title: Fichier et Stream d
1Fichier et Stream dEntrée-Sortie
- IFT1025, Programmation 2
- Jian-Yun Nie
2Concepts
- Notion de fichier et de stream
- Opérations ouverture, lecture/écriture,
fermeture - Format texte vs. binaire
- Accès séquentiel vs. aléatoire
- Organisation des indexes
3Fichier
- Unité de stockage des données, sur disque dur,
- stockage permanent (vs. en mémoire vive)
- Un fichier contient un ensemble denregistrements
- Traitement
CPU
fichier
Mémoire vive
tampon
4Fichier en Java
- Stream une suite de données (octets ou
caractères)
5Opérations typiques
- Lecture
- Ouvrir un stream
- Lire tant quil y a des données
- Fermer le stream
- Écriture
- Ouvrir un stream (ou créer un fichier)
- Écrire des données tant quil y en a
- Fermer le stream
Établir un canal de communication
Relâcher les ressources allouées
Écrire ce quil est dans le tampon, et Relâcher
les ressources allouées
6Exemple TP1
- public static void traiter_fichier()
- String ligne
- try // catch EOFException
- ligne input.readLine()
- while (ligne ! null)
- System.out.println(ligne)
- ligne input.readLine()
-
-
- public static void fermer_fichier()
- try
- input.close()
- System.exit(0)
-
- catch (IOException e)
- System.err.println("Impossible de fermer les
fichiers.\n" e.toString())
- public static void main(String args)
- ouvrir_fichier("liste_mots")
-
- traiter_fichier()
- fermer_fichier()
-
- public static void ouvrir_fichier(String nom)
- try
- input new BufferedReader(
- new FileReader(nom))
-
- catch (IOException e)
- System.err.println("Impossible d'ouvrir le
fichier d'entree.\n" e.toString()) - System.exit(1)
-
7Un autre exemple
- public void readFile()
- FileReader fileReader null
- try
- fileReader new FileReader("input.txt")
- int c fileReader.read()
- while (c ! -1)
- char d ((char)c)
- c fileReader.read()
-
- catch (FileNotFoundException e)
- System.out.println("File was not found")
- catch (IOException e)
- System.out.println("Error reading from
file") -
- if (fileReader ! null)
- try fileReader.close()
- catch (IOException e) / ignore /
-
-
8Deux unité de base
- Caractère (2 octets16 bits) ou octet (8 bits)
- Deux hiérarchies de classe similaires (mais en
parallèle)
9Hiérarchies
- En haut des hiérarchies pour stream de
caractères 2 classes abstraites - Reader
- java.lang.Object
- java.io.Reader
- Writer
- java.lang.Object
- java.io.Writer
- Implantent une partie des méthodes pour lire et
écrire des caractère de 16 bits (2 octets)
10Hiérarchie de Stream de caractère
- Les sous-classe de Reader
- simple pré-traitement
- Chaque sous-classe ajoute des méthodes
11Hiérarchie de Stream de caractère
- Les sous-classe de Writer
12Hiérarchies Byte Stream
System.in
13Hiérarchie de Byte Stream
System.out
System.err
14Différence caractère vs byte
- Reader
- int read()
- int read(char cbuf)
- int read(char cbuf, int offset, int length)
- InputStream
- int read()
- int read(byte cbuf)
- int read(byte cbuf, int offset, int length)
15Utilisation de différentes classes
- En mémoire
- CharArrayReader, CharArrayWriter
- ByteArrayInputStream, ByteArrayOutputStream
- Lire/écrire dans un tableau de bytes
- StringReader, StringWriter, StringBufferInputStrea
m - Lire/écrire dans un String
- Pipe
- PipedReader, PipedWriter
- PipedInputStream, PipedOutputStream
- Relier la sortie dun Stream comme une entrée
dun autre stream (pipeline)
16Utilisation
- Fichier ()
- FileReader, FileWriter
- FileInputStream, FileOutputStream
- Lire/écrire dans un fichier
- Sérialisation
- ObjectInputStream, ObjectOutputStream
- Conversion de données ()
- DataInputStream, DataOutputStream
- Reconnaître les types de données primitifs
- Impression ()
- PrintWriter, PrintStream
- Méthodes conviviales pour limpression
17Utilisation
- Buffer (Tampon)
- BufferedReader, BufferedWriter
- BufferedInputStream, BufferedOutputStream
- Créer un tampon accès plus efficace
- Filtering
- FilterReader, FilterWriter
- FilterInputStream, FilterOutputStream
- Accepte un Stream, le filtre et ensuite passer à
un autre Stream - Convertir entre byte et caractère
- InputStreamReader, OutputStreamWriter
- Lire des bytes en caractère, ou écrire des
caractère en byte
18Exemple
- Utiliser FileReader et FileWriter
- Méthodes simples disponible
- int read(), int read(CharBuffer ), write(int),
.. - Exemple copier un fichier caractère par
caractère (comme un int) - import java.io.
- public class Copy
- public static void main(String args) throws
IOException - File inputFile new File("farrago.txt")
- File outputFile new File("outagain.txt")
- FileReader in new FileReader(inputFile)
- FileWriter out new FileWriter(outputFile
) - int c
- while ((c in.read()) ! -1)
out.write(c) - in.close()
- out.close()
Fin de fichier -1
19Augmenter les possibilités wrap
- Créer un stream en se basant sur un autre
- FileReader in new FileReader(new
File("farrago.txt")) - Avantage
- Obtenir plus de méthodes
- Dans File les méthodes pour gérer les fichier
(delete(), getPath(), ) mais pas de méthode pour
la lecture - Dans FileReader les méthodes de base pour la
lecture - Un autre exemple
- DataOutputStream out new DataOutputStream(
- new FileOutputStream("invoice1.txt"))
- FileOutptuStream écrire des bytes
- DataOutputStream les méthodes pour les types de
données de base - write(int), writeBoolean(boolean),
writeChar(int), writeDouble(double),
writeFloat(float),
20Pourquoi faire du wrapping?
- Les streams enrichis ont besoin dun stream plus
primitif dans son constructeur - E.g. DataInputStream(InputStream in)
DataOutputStream(OutputStream out) - Impossible de créer un stream directement dun
nom de fichier comme - new DataOutputStream(sortie)
- Besoin de faire du wrapping
- New DataOutputStream(new FileOutputStream("sortie"
)) - Les streams de base soccupe des E/S de base, et
les streams enrichies ajoutent dautres
possibilités - Wrapping réutiliser les méthodes de base, et
ajouter dautre méthodes
21Hiérarchies
22Sink stream
Sink Type Character Streams Byte Streams
Memory CharArrayReader, CharArrayWriter StringReader,StringWriter ByteArrayInputStream,ByteArrayOutputStream StringBufferInputStream
Pipe PipedReader,PipedWriter PipedInputStream,PipedOutputStream
File FileReader,FileWriter FileInputStream,FileOutputStream
23Wrap dans quelle classe ?
- Dépend des méthodes dont on a besoin
- Quelques exemples
- Lire ligne par ligne
- Besoin de String readLine() (null à la fin du
fichier) - BufferedReader (sous classe de Reader)
- Traitement
- Lire une ligne (String)
- Traiter cette ligne avec un Parsing (comme TP1)
- Constructeur BufferedReader(Reader)
- new BufferedReader(new FileReader("fichier"))
(FileReader est sous-classe de Reader classe
abstraite) - Écrire ligne par ligne
- BufferedWriter (sous-classe de Writer)
- write(String) écrire un String
- newLine() insérer un changement de ligne
- Traitement
- Organiser une ligne comme String
- Écrire la ligne
24Wrap dans quelle classe ?
- Besoin utiliser les méthodes comme dans
System.out - write(int),
- print(), println()
- Stream à utiliser PrintWriter
- Constructeurs
- PrintWriter(OutputStream out)
- PrintWriter(Writer out)
- new PrintWriter(new FileOutputStream("fichier"))
- new PrintWriter(new FileWriter("fichier"))
25Wrap dans quelle classe ?
- Besoin écrire les données des types primitifs
- writeChar(Char), writeFloat(float),
- Stream à utiliser DataOutputStream
- Constructeur
- DataOutputStream(OutputStream out)
- new DataOutputStream(new FileOutputStream("fichier
"))
26Interface JFileChooser
- JFileChooser chooser new JFileChooser()
- FileReader in null
- if (chooser.showOpenDialog(null)
JFileChooser.APPROVE_OPTION) -
- File selectedFile chooser.getSelectedFile()
- reader new FileReader(selectedFile)
- . . .
-
27Attention au format
- Stocker les données dans un fichier
- Mais aussi pouvoir les ressortir
- E.g. stocker le nom et la date de naissance
- GéraldTremblay19500101SusanneRoy19800406
- Au moment de stocker, déterminer un format pour
pouvoir les relire - Façon simple
- Gérald Tremblay 19500101 Susanne Roy 19800406
- Lire prénom (jusquà lespace), nom, date de
naissance (il faut ensuite la décomposer)
28Format
- Stocker en binaire ou en caractère?
- Caractère lisible (e.g. avec more, vi, etc.)
- Binaire transformer en code binaire
- int 4 octets
- Long 8 octets
- char 2 octet
-
- Valeur 12345 (entier)
- En caractère 12345 (10 octets)
- En binaire 0 0 48 57 (4 octets) 4825657
- Binaire plus économique en espace
- Binaire espace fixe (facilite la lecture)
29Exemple en binaire
- Pour un compte bancaire
- No. de compte entier
- Montant double
- Pour écrire un enregistrement (pour un compte)
- writeInt(int)
- writeDouble(double)
- Classe DataOutputStream
- Pour lire un enregistrement
- readInt()
- readDouble()
- Classe DataInputStream
- Penser aux écritures et aux lectures en même temps
30DataInputStream et DataOutputStream
- Lire et écrire des données des types de base
- readBoolean(), readInt(), readFloat, readChar(),
readLine() readUTF(), - writeBoolean(boolean), writeInt(int),
writeFloat(float), writeChar(char),
writeChars(String), writeUTF(String), - readUTF et writeUTF
- Entier en binaire correspondant à la longueur du
String String - Exemple liste_mots
- _at_sur prep sing sur
rel_at_(laquelle pron_rel fem sing
_at_systeme n masc sing outil _at_ non
adv non rel_at_echeance
n fem sing temps_at_entite - Références
- http//java.sun.com/j2se/1.5.0/docs/api/java/io/Da
taOutputStream.html - http//java.sun.com/j2se/1.5.0/docs/api/java/io/Da
taInputStream.html
31Sérialiser
- Convertir un objet (avec une structure) en une
suite de données dans un fichier - Reconvertir du fichier en un objet
- Utilisation avec ObjectOutputStream
- Employee staff new Employee3
- ObjectOutputStream out new ObjectOutputStream(ne
w - FileOutputStream("test2.dat"))
- out.writeObject(staff)
- out.close()
32Sérialiser
- Utilité de sérialisation
- Stocker un objet dans un fichier
- Créer une copie dobjet en mémoire
- Transmettre un objet à distance
- Devient une transmission de String
33Sérialiser
- Pour pouvoir sérialiser un objet
- sa classe doit implanter linterface Serializable
- Interface Serializable
- Pas de méthode exigée
- Mais on peut réimplanter readObject() et
writeObject() si on ne se contente pas de la
version par défaut defaultReadObject(),
defaultWriteObject() - private void writeObject(java.io.ObjectOutputStrea
m out) - throws IOException
- private void readObject(java.io.ObjectInputStream
in) - throws IOException, ClassNotFoundException
- Beaucoup de classes existantes sont sérialisables
(e.g. ArrayList) -
34Sérialiser une classe sérialisable
- try
- OutputStream file new FileOutputStream(
"quarks.ser" ) - OutputStream buffer new
BufferedOutputStream( file ) - output new ObjectOutputStream( buffer )
- output.writeObject(quarks)
-
- catch(IOException ex)
- fLogger.log(Level.SEVERE, "Cannot perform
output.", ex) -
- finally
- try
- if (output ! null)
- //flush and close "output" and its
underlying streams - output.close()
-
-
- catch (IOException ex )
- fLogger.log(Level.SEVERE, "Cannot close
output stream.", ex)
- import java.io.
- import java.util.
- import java.util.logging.
- public class ExerciseSerializable
- public static void main(String aArguments)
- //create a Serializable List
- List quarks new ArrayList()
- quarks.add("up")
- quarks.add("down")
- quarks.add("strange")
- quarks.add("charm")
- quarks.add("top")
- quarks.add("bottom")
-
ArrayList est sérialisable
35Définir une clase sérialisable
- class Employee implements Serializable
- public Employee(String n, double s, Date d)
- name n
- salary s
- hireDate d
-
- public Employee()
- public void raiseSalary(double byPercent)
- salary 1 byPercent / 100
-
- public int hireYear()
- return hireDate.getYear()
-
- public void print()
- System.out.println(name " " salary
- class Manager extends Employee
- public Manager(String n, double s, Date d,
Employee e) - super(n, s, d)
- secretary e
-
- public Manager()
- public void raiseSalary(double byPercent)
- // add 1/2 bonus for every year of service
- Date today new Date()
- double bonus 0.5 (today.getYear() -
hireYear()) - super.raiseSalary(byPercent bonus)
-
- public void print()
- super.print()
- System.out.print("Secretary ")
- if (secretary ! null) secretary.print()
36Utiliser une classe sérialisable
- ObjectOutputStream out new
- ObjectOutputStream(new
- FileOutputStream("test2.dat"))
- out.writeObject(staff)
- out.close()
- ObjectInputStream in new
- ObjectInputStream(
- new FileInputStream ("test2.dat"))
- Employee newStaff
- (Employee)in.readObject()
- for (int i 0 i lt newStaff.length
i) - newStaffi.raiseSalary(100)
- for (int i 0 i lt newStaff.length
i) - newStaffi.print()
-
- catch(Exception e)
- import java.io.
- import java.util.
- class ObjectRefTest
- public static void main(String args)
- try
-
- Employee staff new Employee3
- Employee harry new Employee
- ("Harry Hacker", 35000,
- new Date(1989,10,1))
- staff0 harry
- staff1 new Manager("Carl Cracker",
- 75000,
- new Date(1987,12,15), harry)
- staff2 new Manager("Tony Tester",
- 38000,
- new Date(1990,3,15), harry)
37Sortie de sérialisation
- vi test2.dat
- í_at_Eur_at_KLEmployeeü6QÅlt91gtQÇB_at__at_xp_at__at_
_at_Csr_at_HEmployeeBÅlt89gtVlt99gtqB_at_CD_at_FsalaryL
_at_HhireDatet_at_PLjava/util/DateL_at_Dnamet_at_RLja
va/lang/Stringxp_at_áW_at__at__at__at__at_sr_at_Njava.util.Dat
ehjlt81gtAKYtYC_at__at_xpwH_at__at_7Ylt8cgt4lt80gtxt_at_LHa
rry Hackersr_at_GManagerUlt9dgtlt93gtþlt8fgtÍqB_at_AL
_at_secretaryt_at_LEmployeexq_at__at_B_at_òOlt80gt_at__at__at__at_sq
_at__at_FwH_at__at_7L_at_tlt80gtxt_at_LCarl
Crackerq_at__at_Esq_at__at__at_â lt8egt_at__at__at__at__at_sq_at__at_Fw
H_at__at_7)Nlt92gt_at_xt_at_KTony Testerq_at__at_ E - Lisible par désérialisation (readObject())
- Harry Hacker 70000.0 1989
- Carl Cracker -555750.0 1988
- Secretary Harry Hacker 70000.0 1989
- Tony Tester -281960.0 1990
- Secretary Harry Hacker 70000.0 1989
38Accès séquentiel vs. aléatoire
- Séquentiel Première donnée, suivante,
- Approprié pour traiter toutes les données
- Aléatoire (random) positionner à un endroit,
lire les données à partir de cette position - Approprié pour sélectionner certaines données à
traiter - Question importante
- Comment déterminer la position correcte ?
39RandomAccessFile
- Un Stream en format binaire
- Écrire et lire (selon louverture)
- Possibilité de positionner avec seek(long)
- Exemple
- file new RandomAccessFile(filename, "rw")
- file.seek(100)
- int accountNumber file.readInt()
- double balance file.readDouble()
- Référence
- http//java.sun.com/j2se/1.4.2/docs/api/java/io/Ra
ndomAccessFile.html
40RandomAccessFile
- Ouverture
- file new RandomAccessFile(filename, "rw")
- Modes
- r lecture seulement
- rw lecture et ecriture
Mode
41RandomAccessFile
- Lecture ou écriture
- Sans seek
- Position au début du fichier
- Écrire et lire à partir de cette position comme
un accès séquentiel - seek(long)
- Positionner à la position (no. de bytes à partir
du début) - Lire ou écrire à partir de cette position
42Position
- Comment déterminer la bonne position?
- Solution simple
- Chaque enregistrement taille fixe
- Pour un enregistrement déterminer son numéro
- seek(tailleno)
- Solution plus complexe
- Organiser un indexe
- Utiliser une table de hashage
43Taille fixe pour un enregistrement
- 008 public class BankData
- 009
- 024 public void open(String filename)
- 025 throws IOException
- 026
- 027 if (file ! null) file.close()
- 028 file new RandomAccessFile(filename,
"rw") - 029
- 035 public int size()
- 036 throws IOException
- 037
- 038 return (int) (file.length() /
RECORD_SIZE) - 039
- 071 public int find(int accountNumber)
- 072 throws IOException
- 073
- 074 for (int i 0 i lt size() i)
- 075
- 056 public BankAccount read(int n)
- 057 throws IOException
- 058
- 059 file.seek(n RECORD_SIZE)
- 060 int accountNumber file.readInt()
- 061 double balance file.readDouble()
- 062 return new BankAccount(accountNumber,
balance) - 063
- 089 public void write(int n, BankAccount
account) - 090 throws IOException
- 091
- 092 file.seek(n RECORD_SIZE)
- 093 file.writeInt(account.getAccountNumber(
)) - 094 file.writeDouble(account.getBalance())
- 095
- 096
- 097 private RandomAccessFile file
- 098
44Accès dans RandomAccessFile
- Exploiter seek pour déterminer la position pour
lire ou écrire un enregistrement - Séquentiel lire chaque enregistrement à partir
du début - Direct déterminer une position selon une clé, et
lire/écrire lenregistrement - Position no. de compte taille
- clé no. de compte
- Position est déterminer selon une conversion avec
une clé (e.g. code permanent GILB76022304) - Non numérique
- Non compact valeur non continue
45Cas 1 Recherche binaire
- Les enregistrements sont stockés dans lordre
croissant des clés - Accès binaire (O(log(n))
- Chercher(clé, début, fin)
- Lire le milieu
- Si clé_milieu clé, trouvé
- Si clé_milieu lt clé,
- Si (milieu début) lt 2, introuvable
- Sinon cherche(clé, début, milieur-1)
- Si clé_milieu gt clé,
- Si (fin milieu) lt 2, introuvable
- Sinon cherche(clé, milieu1, fin)
46Recherche binaire
1 3 6 8 10 16 20
Fichier
47Cas 2 table de hashage
- Table de hashage déterminer une position pour
chaque clé - Fonction de hashage clé entier
- Contraintes
- Le plus compacte possible (pas beaucoup de
positions vides) - Le moins de conflit possible (2 clés même
position)
48Exemple simple
- Transformer un code permanent en un entier
- VALB23027502 code
- 4 premiers caractères A-Z (1-26)4
- 2 chiffres 01-31 1-31
- 2 chiffres 01-12, 5-62 1-24
- 2 chiffres 50-40 (1950-2040) 0-90
- 2 chiffres 01-99 1-99
- Fonction1(clé) concatener les codes
- Compacte ? 00 et 27, 00 et 32
non utilisés - Fonction2(clé) code(L1)code(L4)code(jour)
- code(mois)code(année)code(derniers_ch)
- Conflit? VALB23027502 VALB23017504
49Approche générale
- Valeur non conflictuelle (mais relativement
compact) - Déterminer la taille approximative du fichier
souhaitée (taille) - Valeur primaire
- Primaire est un nombre proche de la taille
- E.g. lt10 000 enregistrements 10007, 10009,
10037, 12007, - Prévoir plus large
- Prévoir un mécanisme pour résoudre le conflit
- Aller à la suivante
- Rehashage appliquer une autre fonction de
hashage
50Cas 3 indexe
- Maintenir une structure dindexe (clé lettre
nombre)
0
20
21 pos
90
Cléa21
a
b
c
z
0 pos
10
20
90