Title: Fichier et Stream dEntreSortie
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
4java.io.File
- Interagit avec le système de fichier
- A un nom
- Un chemin
- Des permissions (écriture, lecture)
- Un temps d'acces
- Traitement particulier pour des répertoires
- listFiles
5Fichier en Java
- Stream une suite de données (octets ou
caractères)
6Opé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
7Exemple
- 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)
-
8Un 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 /
-
-
9Deux unité de base
- Caractère (2 octets16 bits) ou octet (8 bits)
- Deux hiérarchies de classe similaires (mais en
parallèle)
10Hié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)
11Hiérarchie de Stream de caractère
- Les sous-classe de Reader
- simple pré-traitement
- Chaque sous-classe ajoute des méthodes
12Hiérarchie de Stream de caractère
- Les sous-classe de Writer
13Hiérarchies Byte Stream
System.in
14Hiérarchie de Byte Stream
System.out
System.err
15Diffé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)
16Utilisation 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)
17Utilisation
- 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
18Utilisation
- 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
19Exemple
- 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
20Augmenter 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),
21Pourquoi 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
22Hiérarchies
23Sink stream
24Wrap 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
25Wrap 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"))
26Wrap 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
"))
27Interface JFileChooser
- JFileChooser chooser new JFileChooser()
- FileReader in null
- if (chooser.showOpenDialog(null)
JFileChooser.APPROVE_OPTION) -
- File selectedFile chooser.getSelectedFile()
- reader new FileReader(selectedFile)
- . . .
-
28Attention 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)
29Format
- 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)
30Exemple 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
31DataInputStream 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
32Sé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()
33Sé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
34Sé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) -
35Sé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
36Dé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()
37Utiliser 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)
38Sortie 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
39Accè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 ?
40RandomAccessFile
- 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
41RandomAccessFile
- Ouverture
- file new RandomAccessFile(filename, "rw")
- Modes
- r lecture seulement
- rw lecture et ecriture
Mode
42RandomAccessFile
- 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
43Position
- 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
44Taille 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
45Accè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
46Cas 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)
47Recherche binaire
Fichier
48Cas 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)
49Exemple 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
50Approche 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
51Cas 3 indexe
- Maintenir une structure dindexe (clé lettre
nombre)
Cléa21
52Trois streams standards
- Stdout System.out
- Stdin System.in
- Stderr System.err