Download de presentatie
De presentatie wordt gedownload. Even geduld aub
1
Hoofdstuk 17: FILES EN STREAMS
2
H 17. FILES EN STREAMS 1. INLEIDING
Files kan je enkel gebruiken in applicaties, NIET in applets Korte termijn geheugen versus lange termijn geheugen: Korte termijn geheugen: Variabelen, arrays Ogeslagen in het interne geheugen De inhoud verdwijnt bij einde van de scope Lange termijn geheugen: Files en databanken Opgeslagen op secundaire geheugenmedia Persistente (“blijvende”) gegevens
3
H 17. FILES EN STREAMS 1. INLEIDING
Lange termijn opslag van grote hoeveelheden gegevens Persistente gegevens (blijven bestaan na beëindiging van een programma) Opgeslagen op secundaire geheugenmedia Magnetische schijven Optische schijven Magnetische tapes Sequentiële files en random access files
4
H 17. FILES EN STREAMS 1. INLEIDING
Sequentiële file Je doorloopt de gegevens in een sequentiële file van voor naar achter Random access file Je krijgt op willekeurige manier toegang tot de gegevens in een random access file
5
H 17. FILES EN STREAMS 1. INLEIDING
Java file verwerking is een onderdeel van Java stream verwerking. Een stream is een stroom van gegevens. Streams hebben niet alleen met files te maken, maar een stream is een manier om allerlei vormen van gegevenstransport in een computer te beschrijven: gegevens die via het toetsenbord binnenkomen, of via een netwerkkabel of gegevens die via twee programma’s worden uitgewisseld, kan je ook beschouwen als een stream. Mogelijkheden van streams: Bytes lezen uit en schrijven naar het geheugen Bytes lezen uit en schrijven naar files Bytes lezen en schrijven over netwerkverbindingen
6
H 17. FILES EN STREAMS 2. Data hierarchie
Bit is de kleinste data item in een computer Bit is 0 of 1 Bit is een samentrekking van “binary digit” Programmeurs werken met hogere niveau data items Decimal digits: (0-9) Letters: (A-Z en a-z) Speciale symbolen zoals %, &, *, (, ), -, +, “, :, ?, /, … Java gebruikt Unicode karakters, opgebouwd uit 2 bytes Een byte bevat 8 bits Velden (Java attribuutvariabelen) Opgebouwd uit karakters of bytes
7
H 17. FILES EN STREAMS 2. Data hierarchie
Data items in a computer vormen een hierarchie Bits -> karakters -> velden -> ... Records Samengesteld uit meerdere velden Geïmplementeerd als een class in Java File is a groep van gerelateerde records Elk record heeft een recordsleutel (record key) Een recordsleutel is een unieke identificatie voor elk record in de file Een recordsleutel vergemakkelijkt het opzoeken van een bepaald record uit een bestand Sequentiële file Records worden opgeslagen in volgorde van de recordsleutel
8
Fig. 17.1 Data hierarchy Randy Red 1 01001010 J u d y Name Color Sally
Black Tom Blue Judy Green Iris Orange File Record Field Byte (ASCII character J) Bit
9
H 17. FILES EN STREAMS 3. Files en streams
Java ziet elke file als een sequentiële stream van bytes 3 ... 1 2 4 5 8 9 n-1 end-of-file marker 6 7
10
H 17. FILES EN STREAMS 3. Files en streams
Elk besturingssysteem kan het einde van een file bepalen door: end-of-file merkteken het totaal aantal bytes van de file bij te houden Een java programma krijgt een signaal van het besturingssysteem wanneer het programma het einde van een stream bereikt door middel van een exceptie of door middel van een specifieke returnwaarde van een methode
11
H 17. FILES EN STREAMS 3. Files en streams
Een file wordt geassocieerd met een object Java associeert streams met devices: System.in: standaard input stream object, laat toe om bytes via het toetsenbord in te lezen System.out: standaard output stream object, laat toe om bytes weer te geven op het scherm System.err: standaard error stream object, laat toe om foutboodschappen weer te geven op het scherm Streams kan je omleiden door gebruik te maken van de methoden setIn, setOut en setErr van de klasse System Door System.in om te leiden, kan een programma bytes lezen van een andere bron zoals een file en door System.out en/of System.err om te leiden kan je bytes wegschrijven naar een file op schijf
12
H 17. FILES EN STREAMS 3. Files en streams
File verwerking gebeurt in Java met klassen van de package java.io FileInputStream om bytes te lezen uit een file FileOutputStream om bytes te schrijven naar een file FileReader om karakters uit een file te lezen FileWriter om karakters naar een file te schrijven
13
H 17. FILES EN STREAMS 3. Files en streams
Buffering Een buffer is een ruimte in het geheugen Verbetert de performantie van I/O Kopieert elke uitvoer naar een buffer. De volledige inhoud van de buffer wordt naar de schijf geschreven Eén grote toegang tot de schijf neemt minder tijd in beslag dan vele kleine BufferedOutputStream: file output met buffers BufferedInputStream: file input met buffers
14
H 17. FILES EN STREAMS 4. De klasse File
Levert bruikbare informatie over een file of een directory Opent of verwerkt de files NIET
15
Methoden van de klasse File
16
Voorbeeld 1: FileTest Grafische applicatie waarbij de gebruiker de naam van een file of directory in een instantie van JTextField typt en op enter drukt. Informatie over deze file of deze directory wordt opgehaald en getoond in een JTextArea.
17
Voorbeeld 1 Gegevens uit een file lezen:
Met FileReader kan je een file openen om de karakters te lezen, maar hiermee kan je geen regels tekst lezen Met BufferedReader kan je regels tekst lezen maar kan je geen file openen om te lezen Oplossing: Combineer FileReader en BufferedReader Dit heet wrapping van stream objecten: de services van de ene stream worden toegevoegd aan de andere stream.
18
Hier typ je de naam van de file of de directory
Bestaat die file of directory niet, dan krijg je daarvan melding
19
Informatie over een directory
Informatie over een file
20
Importeer de package java.io
// Fig. 17.4: FileTest.java // Demonstrating the File class. import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.*; 7 public class FileTest extends JFrame implements ActionListener { 10 private JTextField enterField; private JTextArea outputArea; 13 // set up GUI public FileTest() { super( "Testing class File" ); 18 enterField = new JTextField( "Enter file or directory name here"); enterField.addActionListener( this ); outputArea = new JTextArea(); 22 ScrollPane scrollPane = new ScrollPane(); scrollPane.add( outputArea ); 25 Importeer de package java.io
21
Creëert een nieuwe referentie naar File
Container container = getContentPane(); container.add( enterField, BorderLayout.NORTH ); container.add( scrollPane, BorderLayout.CENTER ); 29 setSize( 400, 400 ); setVisible( true ); 32 } // end constructor 34 // display information about file user specifies public void actionPerformed( ActionEvent actionEvent ) { File name = new File( actionEvent.getActionCommand() ); 39 // if name exists, output information about it if ( name.exists() ) { outputArea.setText( name.getName() + " exists\n" + ( name.isFile() ? "is a file\n" : "is not a file\n" ) + ( name.isDirectory() ? "is a directory\n" : "is not a directory\n" ) + ( name.isAbsolute() ? "is absolute path\n" : "is not absolute path\n" ) + "Last modified: " + name.lastModified() + "\nLength: " + name.length() + "\nPath: " + name.getPath() + "\nAbsolute path: " + name.getAbsolutePath() + "\nParent: " + name.getParent() ); 51 Creëert een nieuwe referentie naar File Body van de if geeft informatie over de file als deze file bestaat
22
Test of de ingegeven naam een file is
// output information if name is a file if ( name.isFile() ) { 54 // append contents of file to outputArea try { BufferedReader input = new BufferedReader( new FileReader( name ) ); StringBuffer buffer = new StringBuffer(); String text; outputArea.append( "\n\n" ); 62 while ( ( text = input.readLine() ) != null ) buffer.append( text + "\n" ); 65 outputArea.append( buffer.toString() ); } 68 // process file processing problems catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "FILE ERROR", "FILE ERROR", JOptionPane.ERROR_MESSAGE ); } 74 } // end if 76 Test of de ingegeven naam een file is Creëer een BufferedReader om de gegevens van de file te lezen Lees de tekst regel per regel tot het einde van de file en plaats de inhoud ervan in buffer
23
Maak een lijst van alle files in de directory
// output directory listing else if ( name.isDirectory() ) { String directory[] = name.list(); 80 outputArea.append( "\n\nDirectory contents:\n"); 82 for ( int i = 0; i < directory.length; i++ ) outputArea.append( directory[ i ] + "\n" ); } 86 } // end outer if 88 // not file or directory, output error message else { JOptionPane.showMessageDialog( this, actionEvent.getActionCommand() + " Does Not Exist", "ERROR", JOptionPane.ERROR_MESSAGE ); } 95 } // end method actionPerformed 97 public static void main( String args[] ) { FileTest application = new FileTest(); application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); } 103 104 } // end class FileTest Maak een lijst van alle files in de directory Als de file niet bestaat, druk dan een foutboodschap
25
H 17. FILES EN STREAMS 5. Creatie van een sequentiële file
De records worden de één na de andere opgeslagen (consecutief) Java legt geen structuur op aan een file De programmeur structureert zelf de file om tegemoet te komen aan de vereisten van de applicatie De gebruiker geeft de records in de juiste volgorde in (dwz in stijgende volgorde van de recordsleutel)
26
H 17. FILES EN STREAMS 5. Creatie van een sequentiële file
Basisbewerkingen: Openen van een file om in te schrijven Schrijven van een record naar een file Sluiten van een file Opvangen van de mogelijke excepties: IOException
27
H 17. FILES EN STREAMS 5. Creatie van een sequentiële file
Openen van een file om in te schrijven Voorbeeld: File filenaam(“c:\\oef\\test.dat”); Hiermee wordt de file NIET geopend ObjectOutputStream output; output = new ObjectOutputStream (new FileOutputStream(filenaam)); Met een FileOutputStream object kan je byte arrays en individuele bytes schrijven naar een file. Om objecten te schrijven hebben we wrapping met ObjectOutputStream nodig. Exception handling moet toegepast worden om problemen op te vangen bij het openen van de file.
28
H 17. FILES EN STREAMS 5. Creatie van een sequentiële file
Schrijven van een record naar een file Voorbeeld: output.writeObject(record); output.flush(); De methode flush() schrijft de gegevens van de buffer in het geheugen naar de file Sluiten van een file output.close(); Exception handling moet toegepast worden voor het geval een file niet kan gesloten worden.
29
Voorbeeld 2: Creatie van sequentiële file
Dit programma maakt een sequentiële file aan met instanties van AccountRecord. Voor elke klant wordt een instantie van AccountRecord naar de file geschreven. De attributen van AccountRecord zijn: account, firstName, lastName en balance De methoden van AccountRecord zijn: constructor, accessors en mutators
30
Voorbeeld 2 We maken twee domeinklassen, namelijk BankUI en AccountRecord die we in de volgende voorbeelden zullen hergebruiken. Daarom nemen we ze op in een package.
31
Domeinklasse BankUI Een instantie van BankUI zullen we gebruiken als userinterface Bevat 2 instanties van JButton, een array van instanties van JLabel en een array van instanties van JTextField Het aantal elementen van de arrays wordt in de constructor ingesteld. Er is geen default constructor. De methoden getFieldValues, setFieldValues en clearFields beheren de tekst van de instanties van JTextField. De methoden getFields, getDoTask1Button en getDoTask2Button geven de individuele GUI component weer zodat een programma er bijvoorbeeld ActionListener kan aan toevoegen.
32
Compileer deze klasse in een package voor hergebruik
// Fig. 17.5: BankUI.java // A reusable GUI for the examples in this chapter. package com.deitel.jhtp5.ch17; 4 import java.awt.*; import javax.swing.*; 7 public class BankUI extends JPanel { 9 // label text for GUI protected final static String names[] = { "Account number", "First name", "Last name", "Balance", "Transaction Amount" }; 13 // GUI components; protected for future subclass access protected JLabel labels[]; protected JTextField fields[]; protected JButton doTask1, doTask2; protected JPanel innerPanelCenter, innerPanelSouth; 19 protected int size; // number of text fields in GUI 21 // constants representing text fields in GUI public static final int ACCOUNT = 0, FIRSTNAME = 1, LASTNAME = 2, BALANCE = 3, TRANSACTION = 4; 25 Compileer deze klasse in een package voor hergebruik Userinterface voor alle voorbeelden uit dit hoofdstuk Deze knoppen zullen de acties uitvoeren in de voorbeelden
33
26 // Set up GUI. Constructor argument size determines the number of
// rows of GUI components. public BankUI( int mySize ) { size = mySize; labels = new JLabel[ size ]; fields = new JTextField[ size ]; 33 // create labels for ( int count = 0; count < labels.length; count++ ) labels[ count ] = new JLabel( names[ count ] ); 37 // create text fields for ( int count = 0; count < fields.length; count++ ) fields[ count ] = new JTextField(); 41 // create panel to lay out labels and fields innerPanelCenter = new JPanel(); innerPanelCenter.setLayout( new GridLayout( size, 2 ) ); 45 // attach labels and fields to innerPanelCenter for ( int count = 0; count < size; count++ ) { innerPanelCenter.add( labels[ count ] ); innerPanelCenter.add( fields[ count ] ); } 51
34
Levert de actieknoppen af
// create generic buttons; no labels or event handlers doTask1 = new JButton(); doTask2 = new JButton(); 55 // create panel to lay out buttons and attach buttons innerPanelSouth = new JPanel(); innerPanelSouth.add( doTask1 ); innerPanelSouth.add( doTask2 ); 60 // set layout of this container and attach panels to it setLayout( new BorderLayout() ); add( innerPanelCenter, BorderLayout.CENTER ); add( innerPanelSouth, BorderLayout.SOUTH ); 65 validate(); // validate layout 67 } // end constructor 69 // return reference to generic task button doTask1 public JButton getDoTask1Button() { return doTask1; } 75 // return reference to generic task button doTask2 public JButton getDoTask2Button() { return doTask2; } Levert de actieknoppen af
35
81 // return reference to fields array of JTextFields public JTextField[] getFields() { return fields; } 87 // clear content of text fields public void clearFields() { for ( int count = 0; count < size; count++ ) fields[ count ].setText( "" ); } 94 // set text field values; throw IllegalArgumentException if // incorrect number of Strings in argument public void setFieldValues( String strings[] ) throws IllegalArgumentException { if ( strings.length != size ) throw new IllegalArgumentException( "There must be " + size + " Strings in the array" ); 103 for ( int count = 0; count < size; count++ ) fields[ count ].setText( strings[ count ] ); }
36
107 // get array of Strings with current text field contents public String[] getFieldValues() { String values[] = new String[ size ]; 112 for ( int count = 0; count < size; count++ ) values[ count ] = fields[ count ].getText(); 115 return values; } 118 119 } // end class BankUI
37
Domeinklasse AccountRecord
Implementeert de interface Serializable zodat de instanties van AccountRecord kunnen gebruikt worden met ObjectInputStream en ObjectOutputStream. ObjectOutputStream maakt het mogelijk om objecten te serializeren dwz converteren naar een stroom van bytes. ObjectInputStream maakt het mogelijk om gegevens te deserializeren dwz converteren van een serie bytes naar het oorspronkelijke object. Serializable is een tagging interface, ze bevat geen methoden. Een klasse die deze interface implementeert, is getagged om een Serializable object te zijn.
38
Domeinklasse AccountRecord
ObjectOutputStream schrijft enkel serialized objecten weg. In een klasse die Serializable implementeert, moeten alle instantievariabelen Serializable zijn of moeten de instantievariabelen transient zijn om aan te duiden dat die variabelen niet Serializable zijn en dat ze dus genegeerd moeten worden bij het serializable proces Alle variabelen van primitieve datatypen zijn bij default serializable. Voor referentievariabelen moet de klasse en mogelijk ook de superklasse nagekeken worden om zeker te zijn dat het type Serializable is.
39
Domeinklasse AccountRecord
Attributen: account firstName lastName balance Methoden: constructoren accessors en mutators
40
Compileer deze klasse in een package voor hergebruik
// Fig. 17.6: AccountRecord.java // A class that represents one record of information. package com.deitel.jhtp5.ch17; 4 import java.io.Serializable; 6 public class AccountRecord implements Serializable { private int account; private String firstName; private String lastName; private double balance; 12 // no-argument constructor calls other constructor with default values public AccountRecord() { this( 0, "", "", 0.0 ); } 18 // initialize a record public AccountRecord( int acct, String first, String last, double bal) { setAccount( acct ); setFirstName( first ); setLastName( last ); setBalance( bal ); } 27 Compileer deze klasse in een package voor hergebruik Implementeert Serializable zodat instanties van AccountRecord gebruikt kunnen worden met input en output streams
41
// set account number public void setAccount( int acct ) { account = acct; } 33 // get account number public int getAccount() { return account; } 39 // set first name public void setFirstName( String first ) { firstName = first; } 45 // get first name public String getFirstName() { return firstName; } 51
42
// set last name public void setLastName( String last ) { lastName = last; } 57 // get last name public String getLastName() { return lastName; } 63 // set balance public void setBalance( double bal ) { balance = bal; } 69 // get balance public double getBalance() { return balance; } 75 76 } // end class AccountRecord
43
Voorbeeld 2: Creatie van sequentiële file
We tonen een scherm met labels en tekstvelden om de records in te vullen en twee knoppen “Save into file” en “Enter”. Slechts één van beide knoppen is geactiveerd. Eerst wordt een bestand gekozen waarin de records worden weggeschreven. Hiervoor maken we gebruik van een instantie van JFileChooser met als selectiemode FILES_ONLY. We gebruiken de methode showSaveDialog van JFileChooser om de dialoogbox Save te tonen. Dit is een modal dialoogbox, dwz de gebruiker moet eerst deze dialoogbox sluiten vooraleer hij een andere actie kan ondernemen. De methode getSelectedFile levert de waarde af van de geselecteerde file van het type File. Die bevat informatie over de file zoals de naam en de plaats, maar NIET de inhoud van de file. Om de file te openen gebruiken we FileOutputStream. De file wordt op deze manier geopend voor uitvoer en de eventueel aanwezige inhoud gaat op die manier verloren.
44
Voorbeeld 2 Willen we een file openen voor uitbreiding (append), dan maken we gebruik van de constructor met twee argumenten. De bestaande inhoud van de file gaat dan NIET verloren, maar wordt uitgebreid Voorbeeld: new FileOutputStream(filenaam, true); Om objecten te schrijven naar de file, wrappen we de file in een ObjectOutputStream De recordvelden worden ingevuld met de correcte gegevens en als men op de “Enter”-knop drukt, wordt het record weggeschreven naar de file. De records worden weggeschreven in stijgende volgorde van de recordsleutel (Account Number).
45
Voorbeeld 2 Het object wegschrijven naar de file gebeurt met de methode writeObject. Nadien wordt de methode flush gebruikt om de gegevens uit de buffer in het geheugen dadelijk weg te schrijven naar de file. Wanneer je wrapped files gebruikt, moet de buitenste stream gebruikt worden om het bestand te sluiten.
46
Het programma toont deze grafische interface
Je kan enkel op de knop Save into File... klikken En dan krijg je de volgende dialoogbox Hier geef je de naam van de file die je wenst aan te maken
47
Je kan nu de gegevens van de records invoeren.
Wanneer je op de Enter-knop klikt, worden de gegevens weggeschreven naar de file
48
1 // Fig. 17.7: CreateSequentialFile.java
// Writing objects sequentially to a file with class ObjectOutputStream. import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; 7 import com.deitel.jhtp5.ch17.BankUI; import com.deitel.jhtp5.ch17.AccountRecord; 10 11 public class CreateSequentialFile extends JFrame { private ObjectOutputStream output; private BankUI userInterface; private JButton enterButton, openButton; 15 // set up GUI public CreateSequentialFile() { super( "Creating a Sequential File of Objects" ); 20 // create instance of reusable user interface userInterface = new BankUI( 4 ); // four textfields getContentPane().add( userInterface, BorderLayout.CENTER ); 24 // configure button doTask1 for use in this program openButton = userInterface.getDoTask1Button(); openButton.setText( "Save into File ..." ); Importeer de grafische interface, een instantie van de klasse BankUI en het record, een instantie van de klasse AccountRecord Creëer de grafische interface en haal een referentie naar de eerste actie knop op
49
Haal een referentie naar de tweede actie knop op
28 // register listener to call openFile when button pressed openButton.addActionListener( 31 // anonymous inner class to handle openButton event new ActionListener() { 34 // call openFile when button pressed public void actionPerformed( ActionEvent event ) { openFile(); } 40 } // end anonymous inner class 42 ); // end call to addActionListener 44 // configure button doTask2 for use in this program enterButton = userInterface.getDoTask2Button(); enterButton.setText( "Enter" ); enterButton.setEnabled( false ); // disable button 49 // register listener to call addRecord when button pressed enterButton.addActionListener( 52 Haal een referentie naar de tweede actie knop op
50
53 // anonymous inner class to handle enterButton event
new ActionListener() { 55 // call addRecord when button pressed public void actionPerformed( ActionEvent event ) { addRecord(); } 61 } // end anonymous inner class 63 ); // end call to addActionListener 65 // register window listener to handle window closing event addWindowListener( 68 // anonymous inner class to handle windowClosing event new WindowAdapter() { 71 // add current record in GUI to file, then close file public void windowClosing( WindowEvent event ) { if ( output != null ) addRecord(); 77 closeFile(); }
51
Instantieer een JFileChooser en ken de referentie toe aan fileChooser
80 } // end anonymous inner class 82 ); // end call to addWindowListener 84 setSize( 300, 200 ); setVisible( true ); 87 } // end CreateSequentialFile constructor 89 // allow user to specify file name private void openFile() { // display file dialog, so user can choose file to open JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY ); 96 int result = fileChooser.showSaveDialog( this ); 98 // if user clicked Cancel button on dialog, return if ( result == JFileChooser.CANCEL_OPTION ) return; 102 File fileName = fileChooser.getSelectedFile(); // get selected file 104 Instantieer een JFileChooser en ken de referentie toe aan fileChooser De constante FILES_ONLY geeft aan dat alleen files kunnen geselecteerd worden Methode showSaveDialog zorgt ervoor dat de JFileChooser genaamd Save verschijnt Haal de geselecteerde file op
52
Open de geselecteerde file
// display error if invalid if ( fileName == null || fileName.getName().equals( "" ) ) JOptionPane.showMessageDialog( this, "Invalid File Name", "Invalid File Name", JOptionPane.ERROR_MESSAGE ); 109 else { 111 // open file try { output = new ObjectOutputStream( new FileOutputStream( fileName ) ); 116 openButton.setEnabled( false ); enterButton.setEnabled( true ); } 120 // process exceptions from opening file catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error Opening File", "Error", JOptionPane.ERROR_MESSAGE ); } 126 } // end else 128 } // end method openFile 130 Open de geselecteerde file
53
Methode closeFile sluit de huidige file
// close file and terminate application private void closeFile() { // close file try { output.close(); System.exit( 0 ); } 139 // process exceptions from closing file catch( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error closing file", "Error", JOptionPane.ERROR_MESSAGE ); System.exit( 1 ); } 146 } // end method closeFile 148 // add record to file public void addRecord() { int accountNumber = 0; AccountRecord record; String fieldValues[] = userInterface.getFieldValues(); 155 Methode closeFile sluit de huidige file Haal de gegevens op uit de tekstvelden
54
Creëer een nieuw record
// if account field value is not empty if ( ! fieldValues[ BankUI.ACCOUNT ].equals( "" ) ) { 158 // output values to file try { accountNumber = Integer.parseInt( fieldValues[ BankUI.ACCOUNT ] ); 163 if ( accountNumber > 0 ) { 165 // create new record record = new AccountRecord( accountNumber, fieldValues[ BankUI.FIRSTNAME ], fieldValues[ BankUI.LASTNAME ], Double.parseDouble( fieldValues[ BankUI.BALANCE ] ) ); 171 // output record and flush buffer output.writeObject( record ); output.flush(); } 176 else { JOptionPane.showMessageDialog( this, "Account number must be greater than 0", "Bad account number", JOptionPane.ERROR_MESSAGE ); } 182 Creëer een nieuw record Schrijf het record onmiddellijk weg naar de file
55
// clear textfields userInterface.clearFields(); 185 } // end try 187 // process invalid account number or balance format catch ( NumberFormatException formatException ) { JOptionPane.showMessageDialog( this, "Bad account number or balance", "Invalid Number Format", JOptionPane.ERROR_MESSAGE ); } 194 // process exceptions from file output catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error writing to file", "IO Exception", JOptionPane.ERROR_MESSAGE ); closeFile(); } 201 } // end if 203 } // end method addRecord 205
56
206 public static void main( String args[] ) 207 {
{ new CreateSequentialFile(); } 210 211 } // end class CreateSequentialFile Grafische interface BankUI
57
Selecteer een plaats voor de file
Files en directories worden hier getoond Klik Save om de naan van de file door te geven aan het programma
58
H 17. FILES EN STREAMS 6. Gegevens lezen uit een sequentiële file
Gegevens opgeslagen in files worden opgehaald om te verwerken wanneer nodig Toegang tot een sequentiële file: De gegevens moeten gelezen worden in hetzelfde formaat als toen ze weggeschreven werden. Een sequentiële file is enkel sequentieel toegankelijk. File R1 R2 R3 … Rn
59
H 17. FILES EN STREAMS 6. Gegevens lezen uit een sequentiële file
Basisbewerkingen: Openen van een file om te lezen Lezen van een record Sluiten van een file Opvangen van de mogelijke excepties: IOException Voorbeeld: File filenaam(“c:\\oef\\test.dat”); ObjectInputStream input = new ObjectInputStream (new FileInputStream(filenaam));
60
H 17. FILES EN STREAMS 6. Gegevens lezen uit een sequentiële file
Lezen van een record uit de file Voorbeeld: record = (AccountRecord) input.readObject(); Het gelezen record wordt geconverteerd naar het gepaste recordtype met een expliciete cast. Sluiten van de file input.close();
61
Voorbeeld 3: sequentiële file lezen
De records uit de sequentiële file uit voorbeeld 2 lezen en op het scherm tonen. Maak gebruik van ObjectInputStream gewrapped rond een FileInputStream om de gegevens uit de file te kunnen lezen in hetzelfde formaat als de gegevens werden weggeschreven.
62
Voorbeeld 3 De methode showOpenDialog van de klasse JFileChooser wordt gebruikt om een file te selecteren en te openen voor invoer. Telkens de gebruiker op de knop “Next Record” klikt, leest het programma het volgende record uit de file. We gebruiken de methode readObject om een record te lezen uit de file. Het afgeleverde object wordt gecast naar het type AccountRecord.
63
Fig. 17.8 Voorbeeldgegevens voor het programma uit voorbeeld 3
64
Het programma toont deze grafische interface
Je kan enkel op de knop Open File... klikken En dan krijg je de volgende dialoogbox Hier klik je de naam van de file aan die je wenst te openen Nu worden de gegevens van de records weergegeven. Klik je op Next Record dan krijg je de gegevens van het volgende record te zien
65
Creëer de grafische interface
// Fig. 17.9: ReadSequentialFile.java // This program reads a file of objects sequentially // and displays each record. import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; 8 import com.deitel.jhtp5.ch17.*; 10 11 public class ReadSequentialFile extends JFrame { private ObjectInputStream input; private BankUI userInterface; private JButton nextButton, openButton; 15 // Constructor -- initialize the Frame public ReadSequentialFile() { super( "Reading a Sequential File of Objects" ); 20 // create instance of reusable user interface userInterface = new BankUI( 4 ); // four textfields getContentPane().add( userInterface, BorderLayout.CENTER ); 24 Creëer de grafische interface
66
Haal een referentie op naar de eerste actie knop
// get reference to generic task button doTask1 from BankUI openButton = userInterface.getDoTask1Button(); openButton.setText( "Open File" ); 28 // register listener to call openFile when button pressed openButton.addActionListener( 31 // anonymous inner class to handle openButton event new ActionListener() { 34 // close file and terminate application public void actionPerformed( ActionEvent event ) { openFile(); } 40 } // end anonymous inner class 42 ); // end call to addActionListener 44 // register window listener for window closing event addWindowListener( 47 // anonymous inner class to handle windowClosing event new WindowAdapter() { 50 Haal een referentie op naar de eerste actie knop
67
Haal een referentie op naar de tweede actie knop
// close file and terminate application public void windowClosing( WindowEvent event ) { if ( input != null ) closeFile(); 56 System.exit( 0 ); } 59 } // end anonymous inner class 61 ); // end call to addWindowListener 63 // get reference to generic task button doTask2 from BankUI nextButton = userInterface.getDoTask2Button(); nextButton.setText( "Next Record" ); nextButton.setEnabled( false ); 68 // register listener to call readRecord when button pressed nextButton.addActionListener( 71 // anonymous inner class to handle nextRecord event new ActionListener() { 74 Haal een referentie op naar de tweede actie knop
68
Instantieer een JFileChooser en ken de referentie toe aan fileChooser
// call readRecord when user clicks nextRecord public void actionPerformed( ActionEvent event ) { readRecord(); } 80 } // end anonymous inner class 82 ); // end call to addActionListener 84 pack(); setSize( 300, 200 ); setVisible( true ); 88 } // end ReadSequentialFile constructor 90 // enable user to select file to open private void openFile() { // display file dialog so user can select file to open JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY ); 97 int result = fileChooser.showOpenDialog( this ); 99 Instantieer een JFileChooser en ken de referentie toe aan fileChooser De constante FILES_ONLY geeft aan dat alleen files kunnen geslecteerd worden De methode showOpenDialog zorgt ervoor dat JFileChooser genaamd Open verschijnt
69
Wordt afgeleverd wanneer de gebruiker op de Cancel button klikt
// if user clicked Cancel button on dialog, return if ( result == JFileChooser.CANCEL_OPTION ) return; 103 // obtain selected file File fileName = fileChooser.getSelectedFile(); 106 // display error if file name invalid if ( fileName == null || fileName.getName().equals( "" ) ) JOptionPane.showMessageDialog( this, "Invalid File Name", "Invalid File Name", JOptionPane.ERROR_MESSAGE ); 111 else { 113 // open file try { input = new ObjectInputStream( new FileInputStream( fileName ) ); 118 openButton.setEnabled( false ); nextButton.setEnabled( true ); } 122 // process exceptions opening file catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error Opening File", "Error", JOptionPane.ERROR_MESSAGE ); } Wordt afgeleverd wanneer de gebruiker op de Cancel button klikt Haal de geselecteerde file op Creëer de geselecteerde file
70
De methode readObject leest een Object uit de ObjectInputStream
128 } // end else 130 } // end method openFile 132 // read record from file public void readRecord() { AccountRecord record; 137 // input the values from the file try { record = ( AccountRecord ) input.readObject(); 141 // create array of Strings to display in GUI String values[] = { String.valueOf( record.getAccount() ), record.getFirstName(), record.getLastName(), String.valueOf( record.getBalance() ) }; 146 // display record contents userInterface.setFieldValues( values ); } 150 // display message when end-of-file reached catch ( EOFException endOfFileException ) { nextButton.setEnabled( false ); 154 De methode readObject leest een Object uit de ObjectInputStream
71
Methode closeFile sluit de file
JOptionPane.showMessageDialog( this, "No more records in file", "End of File", JOptionPane.ERROR_MESSAGE ); } 158 // display error message if class is not found catch ( ClassNotFoundException classNotFoundException ) { JOptionPane.showMessageDialog( this, "Unable to create object", "Class Not Found", JOptionPane.ERROR_MESSAGE ); } 164 // display error message if cannot read due to problem with file catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error during read from file", "Read Error", JOptionPane.ERROR_MESSAGE ); } 171 } // end method readRecord 173 // close file and terminate application private void closeFile() { // close file and exit try { input.close(); System.exit( 0 ); } Methode closeFile sluit de file
72
182 // process exception while closing file catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error closing file", "Error", JOptionPane.ERROR_MESSAGE ); 187 System.exit( 1 ); } 190 } // end method closeFile 192 public static void main( String args[] ) { new ReadSequentialFile(); } 197 198 } // end class ReadSequentialFile
74
H 17. FILES EN STREAMS 7. Een sequentiële file updaten
Het is moeilijk om een sequentiële file te updaten Het hele bestand moet herschreven worden om één veld te wijzigen. Deze werkwijze is enkel aanvaardbaar wanneer vele records te samen worden geupdated.
75
H 17. FILES EN STREAMS 8. Random access files
“Instant-access” applicaties Een record moet onmiddellijk gelokaliseerd worden Transactie verwerkende systemen vereisen een snelle toegang tot de gegevens in een file random access files Toegang tot individuele records is direct en snel Gebruik een vaste lengte voor elk record De relatieve positie van elk record kan gemakkelijk berekend worden ten opzichte van het begin van de file in functie van de recordgrootte en de recordsleutel
76
100 bytes 200 300 400 500 byte offsets
77
Sommige records hebben een inhoud (bestaande records) en andere records zijn leeg (niet-bestaande records) Tussenvoegen van records in een file is mogelijk zonder andere gegevens in de file te vernietigen Gegevens kunnen gewijzigd of verwijderd worden zonder de gehele file te herschrijven
78
De gegevens in een random access file zijn sequentieel toegankelijk en direct toegankelijk
Sequentiële toegangsfunctie: File R1 R2 R3 … Rn Directe toegangsfunctie: File R1 R2 R3 … Rn
79
H 17. FILES EN STREAMS 17.9 Creatie van een random access file
Instanties van de klasse RandomAccessFile hebben alle mogelijkheden van de klassen FileInputStream, FileOutputStream, DataInputStream en DataOutputstream Bij een random access file worden de gegevens gelezen of geschreven te beginnen bij een plaats in de file, aangegeven door de file-position pointer Alle gegevens worden behandeld als primitieve types (met vaste byte grootte) In de meeste programma’s worden objecten naar de file weggeschreven.
80
Voorbeeld: Een transactie verwerkend programma dat tot 100 records met een vaste lengte kan bijhouden voor een bedrijf met 100 klanten. Het programma is in staat om een record te updaten, een nieuw record toe te voegen en een record te verwijderen. We maken een domeinklasse RandomAccessAccountRecord
81
Domeinklasse RandomAccessAccountRecord
subklasse van AccountRecord Extra attribuut: SIZE, de grootte van één record uitgedrukt in bytes Extra methoden: read: één record lezen uit een random access file write: één record wegschrijven naar een random access file
82
Domeinklasse RandomAccessAccountRecord
In de methode read gebruiken we methoden van de klasse RandomAccessFile: readInt, readDouble en readChar om de primitieve typen te lezen uit een random access file In de methode write gebruiken we methoden van de klasse RandomAccessFile: writeInt, writeChars en writeDouble om primitieve datatypen weg te schrijven naar een random access file Voor de voornaam (firstName) en de familienaam (lastName) worden exact 15 karakters gelezen en geschreven. Deze namen worden indien nodig aangevuld met blanco’s. Zo krijgt een record een vaste lengte.
83
Subklasse van AccountRecord
// Fig : RandomAccessAccountRecord.java // Subclass of AccountRecord for random access file programs. package com.deitel.jhtp5.ch17; 4 import java.io.*; 6 public class RandomAccessAccountRecord extends AccountRecord { 8 public static final int SIZE = 72; // bytes in one record 10 // no-argument constructor calls other constructor with default values public RandomAccessAccountRecord() { this( 0, "", "", 0.0 ); } 16 // initialize a RandomAccessAccountRecord public RandomAccessAccountRecord( int account, String firstName, String lastName, double balance ) { super( account, firstName, lastName, balance ); } 23 Subklasse van AccountRecord
84
Methode readInt leest één geheel getal
// read a record from specified RandomAccessFile public void read( RandomAccessFile file ) throws IOException { setAccount( file.readInt() ); setFirstName( readName( file ) ); setLastName( readName( file ) ); setBalance( file.readDouble() ); } 32 // ensure that name is proper length private String readName( RandomAccessFile file ) throws IOException { char name[] = new char[ 15 ], temp; 37 for ( int count = 0; count < name.length; count++ ) { temp = file.readChar(); name[ count ] = temp; } 42 return new String( name ).replace( '\0', ' ' ); } 45 Methode read leest één record uit een instantie van de klasse RandomAccessFile Methode readInt leest één geheel getal Methode readDouble leest één gebroken getal met dubbele precisie Methode readChar leest één karakter
85
Methode writeInt schrijft één geheel getal weg
// write a record to specified RandomAccessFile public void write( RandomAccessFile file ) throws IOException { file.writeInt( getAccount() ); writeName( file, getFirstName() ); writeName( file, getLastName() ); file.writeDouble( getBalance() ); } 54 // write a name to file; maximum of 15 characters private void writeName( RandomAccessFile file, String name ) throws IOException { StringBuffer buffer = null; 60 if ( name != null ) buffer = new StringBuffer( name ); else buffer = new StringBuffer( 15 ); 65 buffer.setLength( 15 ); file.writeChars( buffer.toString() ); } 69 70 } // end class RandomAccessAccountRecord Methode write schrijft één record weg naar een instantie van de klasse RandomAccessFile Methode writeInt schrijft één geheel getal weg Methode writeDouble schrijft één gebroken getal met dubbele precisie weg Methode writeName schrijft een string weg naar een file Methode writeChars schrijft een string weg
86
Creatie van een random access file
Er wordt een direct bestand gecreëerd hierbij wordt de constructor aangeroepen met 2 parameters namelijk de naam van de file en de open mode (r=read, rw=read en write) 100 blanco records worden weggeschreven naar de random access file De random access file wordt gesloten.
87
Hier typ je de naam van de file
Wanneer je op de knop Save klikt, wordt een file gecreëerd
88
1 // Fig. 17.13: CreateRandomFile.java
// Creates random access file by writing 100 empty records to disk. import java.io.*; import javax.swing.*; 5 import com.deitel.jhtp5.ch17.RandomAccessAccountRecord; 7 public class CreateRandomFile { 9 private static final int NUMBER_RECORDS = 100; 11 // enable user to select file to open private void createFile() { // display dialog so user can choose file JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY ); 18 int result = fileChooser.showSaveDialog( null ); 20 // if user clicked Cancel button on dialog, return if ( result == JFileChooser.CANCEL_OPTION ) return; 24 // obtain selected file File fileName = fileChooser.getSelectedFile();
89
Creëert een directe file, een instantie van RandomAccessFile
27 // display error if file name invalid if ( fileName == null || fileName.getName().equals( "" ) ) JOptionPane.showMessageDialog( null, "Invalid File Name", "Invalid File Name", JOptionPane.ERROR_MESSAGE ); 32 else { 34 // open file try { RandomAccessFile file = new RandomAccessFile( fileName, "rw" ); 39 RandomAccessAccountRecord blankRecord = new RandomAccessAccountRecord(); 42 // write 100 blank records for ( int count = 0; count < NUMBER_RECORDS; count++ ) blankRecord.write( file ); 46 file.close(); // close file 48 // display message that file was created JOptionPane.showMessageDialog( null, "Created file " + fileName, "Status", JOptionPane.INFORMATION_MESSAGE ); Creëert een directe file, een instantie van RandomAccessFile Schrijft 100 lege records weg
90
52 System.exit( 0 ); // terminate program 54 } // end try 56 // process exceptions during open, write or close file operations catch ( IOException ioException ) { JOptionPane.showMessageDialog( null, "Error processing file", "Error processing file", JOptionPane.ERROR_MESSAGE ); 61 System.exit( 1 ); } 64 } // end else 66 } // end method createFile 68 public static void main( String args[] ) { CreateRandomFile application = new CreateRandomFile(); application.createFile(); } 74 75 } // end class CreateRandomFile
92
De methode seek van de klasse RandomAccessFile
H 17. FILES EN STREAMS Gegevens direct wegschrijven naar een random access file De methode seek van de klasse RandomAccessFile Plaatst de file-position pointer op de exacte plaats in de file waar het record moet opgeslagen worden
93
Voorbeeld: Schrijf een aantal records naar een random access file
De file wordt geopend in de mode “rw” Gebruik de methode seek om de file-pointer pointer te positioneren Gebruik de methode write om een record weg te schrijven naar de file We maken de veronderstelling dat de gebruiker GEEN dubbele recordsleutels ingeeft en zinvolle gegevens invoert
94
Er zijn 2 knoppen: Open en Enter
Slechts één van beide knoppen is geactiveerd. Wanneer de gebruiker op Open klikt, kan hij een file kiezen die geopend wordt Wanneer de gebruiker waarden invoert in de tekstvelden en vervolgens op de knop Enter klikt, worden de ingevoerde waarden opgeslagen in een instantie van de klasse RandomAccessAccountRecord door gebuik van de methode write
95
Hier klik je de naam van de file aan die je wenst te openen
Het programma toont deze grafische interface. Je kan enkel op de knop Open… klikken. En dan krijg je de volgende dialoogbox Hier klik je de naam van de file aan die je wenst te openen Wanneer je een Account number invoert en op de knop Enter klikt, worden de gegevens van dat record gelezen uit het bestand.
96
1 // Fig. 17.14: WriteRandomFile.java
// This program uses textfields to get information from the user at the // keyboard and writes the information to a random-access file. import java.awt.*; import java.awt.event.*; import java.io.*; import javax.swing.*; 8 import com.deitel.jhtp5.ch17.*; 10 11 public class WriteRandomFile extends JFrame { private RandomAccessFile output; private BankUI userInterface; private JButton enterButton, openButton; 15 private static final int NUMBER_RECORDS = 100; 17 // set up GUI public WriteRandomFile() { super( "Write to random access file" ); 22 // create instance of reusable user interface BankUI userInterface = new BankUI( 4 ); // four textfields getContentPane().add( userInterface, BorderLayout.CENTER );
97
27 // get reference to generic task button doTask1 in BankUI openButton = userInterface.getDoTask1Button(); openButton.setText( "Open..." ); 31 // register listener to call openFile when button pressed openButton.addActionListener( 34 // anonymous inner class to handle openButton event new ActionListener() { 37 // allow user to select file to open public void actionPerformed( ActionEvent event ) { openFile(); } 43 } // end anonymous inner class 45 ); // end call to addActionListener 47 // register window listener for window closing event addWindowListener( 50
98
51 // anonymous inner class to handle windowClosing event
new WindowAdapter() { 53 // add record in GUI, then close file public void windowClosing( WindowEvent event ) { if ( output != null ) addRecord(); 59 closeFile(); } 62 } // end anonymous inner class 64 ); // end call to addWindowListener 66 // get reference to generic task button doTask2 in BankUI enterButton = userInterface.getDoTask2Button(); enterButton.setText( "Enter" ); enterButton.setEnabled( false ); 71 // register listener to call addRecord when button pressed enterButton.addActionListener( 74
99
75 // anonymous inner class to handle enterButton event
new ActionListener() { 77 // add record to file public void actionPerformed( ActionEvent event ) { addRecord(); } 83 } // end anonymous inner class 85 ); // end call to addActionListener 87 setSize( 300, 150 ); setVisible( true ); } 91 // enable user to choose file to open private void openFile() { // display file dialog so user can select file JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY ); 98 int result = fileChooser.showOpenDialog( this ); 100
100
Creëert een instantie van de klasse RandomAccessFile
// if user clicked Cancel button on dialog, return if ( result == JFileChooser.CANCEL_OPTION ) return; 104 // obtain selected fil File fileName = fileChooser.getSelectedFile(); 107 // display error if file name invalid if ( fileName == null || fileName.getName().equals( "" ) ) JOptionPane.showMessageDialog( this, "Invalid File Name", "Invalid File Name", JOptionPane.ERROR_MESSAGE ); 112 else { 114 // open file try { output = new RandomAccessFile( fileName, "rw" ); enterButton.setEnabled( true ); openButton.setEnabled( false ); } 121 // process exception while opening file catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "File does not exist", "Invalid File Name", JOptionPane.ERROR_MESSAGE ); } Creëert een instantie van de klasse RandomAccessFile
101
127 } // end else 129 } // end method openFile 131 // close file and terminate application private void closeFile() { // close file and exit try { if ( output != null ) output.close(); 139 System.exit( 0 ); } 142 // process exception while closing file catch( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error closing file", "Error", JOptionPane.ERROR_MESSAGE ); 147 System.exit( 1 ); } 150 } // end method closeFile 152
102
Zet de file-position pointer op de juiste plaats
// add one record to file private void addRecord() { String fields[] = userInterface.getFieldValues(); 157 // ensure account field has a value if ( ! fields[ BankUI.ACCOUNT ].equals( "" ) ) { 160 // output values to file try { int accountNumber = Integer.parseInt( fields[ ACCOUNT ] ); 165 if ( accountNumber > 0 && accountNumber <= NUMBER_RECORDS ) { RandomAccessAccountRecord record new RandomAccessAccountRecord(); 169 record.setAccount( accountNumber ); record.setFirstName( fields[ BankUI.FIRSTNAME ] ); record.setLastName( fields[ BankUI.LASTNAME ] ); record.setBalance( Double.parseDouble( fields[ BankUI.BALANCE ] ) ); 175 output.seek( ( accountNumber - 1 ) * RandomAccessAccountRecord.SIZE ); record.write( output ); } Zet de file-position pointer op de juiste plaats
103
180 else { JOptionPane.showMessageDialog( this, "Account must be between 1 and 100", "Invalid account number", JOptionPane.ERROR_MESSAGE ); } 186 userInterface.clearFields(); // clear TextFields 188 } // end try 190 // process improper account number or balance format catch ( NumberFormatException formatException ) { JOptionPane.showMessageDialog( this, "Bad account number or balance", "Invalid Number Format", JOptionPane.ERROR_MESSAGE ); } 197 // process exceptions while writing to file catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error writing to the file", "IO Exception", JOptionPane.ERROR_MESSAGE ); closeFile(); }
104
205 } // end if 207 } // end method addRecord 209 public static void main( String args[] ) { new WriteRandomFile(); } 214 215 } // end class WriteRandomFile
106
De random access file openen in de open mode “r” (alleen lezen)
H 17. FILES EN STREAMS Gegevens sequentieel lezen uit een random access file De random access file openen in de open mode “r” (alleen lezen) Alle “bestaande records” uit de random access file worden gelezen (sequentiële toegangsfunctie) in volgorde van de recordsleutel
107
Voorbeeld Het programma toont twee knoppen “Open File for Reading” en “Next”. Slechts één van beide knoppen is geactiveerd. Met de knop “Open File for Reading” selecteer je een file om te openen Met de knop “Next” wordt het volgende record uit de file gelezen en de inhoud ervan op het scherm getoond. De records worden in stijgende volgorde van de recordsleutel getoond.
108
Het programma toont deze grafische interface.
Je kan enkel op de knop Open File for Reading … klikken. En dan krijg je de volgende dialoogbox Hier klik je de naam van de file aan die je wenst te openen. De gegevens van het eerste record uit de file worden getoond. Als je op de knop Next klikt, krijg je de gegevens van het volgende record op het scherm.
109
1 // Fig. 17.15: ReadRandomFile.java
// This program reads a random-access file sequentially and // displays the contents one record at a time in text fields. import java.awt.*; import java.awt.event.*; import java.io.*; import java.text.DecimalFormat; import javax.swing.*; 9 10 import com.deitel.jhtp5.ch17.*; 11 12 public class ReadRandomFile extends JFrame { private BankUI userInterface; private RandomAccessFile input; private JButton nextButton, openButton; 16 private static DecimalFormat twoDigits = new DecimalFormat( "0.00" ); 18 // set up GUI public ReadRandomFile() { super( "Read Client File" ); 23 // create reusable user interface instance userInterface = new BankUI( 4 ); // four textfields getContentPane().add( userInterface );
110
27 // configure generic doTask1 button from BankUI openButton = userInterface.getDoTask1Button(); openButton.setText( "Open File for Reading..." ); 31 // register listener to call openFile when button pressed openButton.addActionListener( 34 // anonymous inner class to handle openButton event new ActionListener() { 37 // enable user to select file to open public void actionPerformed( ActionEvent event ) { openFile(); } 43 } // end anonymous inner class 45 ); // end call to addActionListener 47 // configure generic doTask2 button from BankUI nextButton = userInterface.getDoTask2Button(); nextButton.setText( "Next" ); nextButton.setEnabled( false );
111
52 // register listener to call readRecord when button pressed nextButton.addActionListener( 55 // anonymous inner class to handle nextButton event new ActionListener() { 58 // read a record when user clicks nextButton public void actionPerformed( ActionEvent event ) { readRecord(); } 64 } // end anonymous inner class 66 ); // end call to addActionListener 68 // register listener for window closing event addWindowListener( 71 // anonymous inner class to handle windowClosing event new WindowAdapter() { 74
112
75 // close file and terminate application
public void windowClosing( WindowEvent event ) { closeFile(); } 80 } // end anonymous inner class 82 ); // end call to addWindowListener 84 setSize( 300, 150 ); setVisible( true ); 87 } // end constructor 89 // enable user to select file to open private void openFile() { // display file dialog so user can select file JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY ); 96 int result = fileChooser.showOpenDialog( this ); 98
113
Opent een random access file, een instantie van RandomAccessFile
// if user clicked Cancel button on dialog, return if ( result == JFileChooser.CANCEL_OPTION ) return; 102 // obtain selected file File fileName = fileChooser.getSelectedFile(); 105 // display error is file name invalid if ( fileName == null || fileName.getName().equals( "" ) ) JOptionPane.showMessageDialog( this, "Invalid File Name", "Invalid File Name", JOptionPane.ERROR_MESSAGE ); 110 else { 112 // open file try { input = new RandomAccessFile( fileName, "r" ); nextButton.setEnabled( true ); openButton.setEnabled( false ); } 119 // catch exception while opening file catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "File does not exist", "Invalid File Name", JOptionPane.ERROR_MESSAGE ); } Opent een random access file, een instantie van RandomAccessFile
114
Leest tot een geldig record wordt gevonden
125 } // end else 127 } // end method openFile 129 // read one record private void readRecord() { RandomAccessAccountRecord record = new RandomAccessAccountRecord(); 134 // read a record and display try { 137 do { record.read( input ); } while ( record.getAccount() == 0 ); 141 String values[] = { String.valueOf( record.getAccount() ), record.getFirstName(), record.getLastName(), String.valueOf( record.getBalance() ) }; userInterface.setFieldValues( values ); } 147 Leest tot een geldig record wordt gevonden
115
Als de end-of-file marker bereikt is, zijn er geen records meer
// close file when end-of-file reached catch ( EOFException eofException ) { JOptionPane.showMessageDialog( this, "No more records", "End-of-file reached", JOptionPane.INFORMATION_MESSAGE ); closeFile(); } 154 // process exceptions from problem with file catch ( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error Reading File", "Error", JOptionPane.ERROR_MESSAGE ); 159 System.exit( 1 ); } 162 } // end method readRecord 164 // close file and terminate application private void closeFile() { // close file and exit try { if ( input != null ) input.close(); 172 System.exit( 0 ); } Als de end-of-file marker bereikt is, zijn er geen records meer
116
175 // process exception closing file catch( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error closing file", "Error", JOptionPane.ERROR_MESSAGE ); 180 System.exit( 1 ); } 183 } // end method closeFile 185 public static void main( String args[] ) { new ReadRandomFile(); } 190 191 } // end class ReadRandomFile
118
17.12 Case Study Een transactie verwerkend programma
Gebruikt een random access file Wijzigen, toevoegen en verwijderen van accounts
119
Het programma toont deze grafische interface
Eerst wordt een file geselecteerd om te openen. Vervolgens kunnen de bewerkingen toevoegen, wijzigen en verwijderen van een record plaatsvinden.
120
Voer account number in en druk de Entertoets om het record te lezen uit het bestand en de gegevens ervan te tonen Deze knop krijgt een label afhankelijk van de bewerking die uitgevoerd wordt.
121
Aangepaste waarde nadat de gebruiker op de knop Update geklikt heeft.
Voer een Transaction Amount in
122
Een nieuw record aan de random access file toevoegen
123
Verwijderen van een record
124
1 // Fig. 17.21: TransactionProcessor.java
// A transaction processing program using random-access files. import java.awt.*; import java.awt.event.*; import java.io.*; import java.text.DecimalFormat; import javax.swing.*; 8 import com.deitel.jhtp5.ch17.*; 10 11 public class TransactionProcessor extends JFrame { 12 private BankUI userInterface; private JMenuItem newItem, updateItem, deleteItem, openItem, exitItem; private JTextField fields[]; private JTextField accountField, transactionField; private JButton actionButton, cancelButton; private FileEditor dataFile; private RandomAccessAccountRecord record; 20 public TransactionProcessor() { super( "Transaction Processor" ); 24
125
25 // set up desktop, menu bar and File menu
userInterface = new BankUI( 5 ); getContentPane().add( userInterface ); userInterface.setVisible( false ); 29 // set up the action button actionButton = userInterface.getDoTask1Button(); actionButton.setText( "Save Changes" ); actionButton.setEnabled( false ); 34 // register action button listener actionButton.addActionListener( 37 new ActionListener() { // anonymous inner class 39 public void actionPerformed( ActionEvent event ) { String action = event.getActionCommand(); performAction( action ); 44 } // end method actionPerformed 46 } // end anonymous inner class 48 ); // end call to addActionListener 50
126
51 // set up the cancel button
cancelButton = userInterface.getDoTask2Button(); cancelButton.setText( "Cancel" ); cancelButton.setEnabled( false ); 55 // register cancel button listener cancelButton.addActionListener( 58 new ActionListener() { // anonymous inner class 60 // clear the fields public void actionPerformed( ActionEvent event ) { userInterface.clearFields(); } 66 } // end anonymous inner class 68 ); // end call to addActionListener 70 // set up the listener for the account field fields = userInterface.getFields(); accountField = fields[ BankUI.ACCOUNT ]; accountField.addActionListener( 75
127
76 new ActionListener() { // anonymous inner class
77 public void actionPerformed( ActionEvent event ) { displayRecord( "0" ); } 82 } // end anonymous inner class 84 ); // end call to addActionListener 86 // create reference to the transaction field transactionField = fields[ BankUI.TRANSACTION ]; 89 // register transaction field listener transactionField.addActionListener( 92 new ActionListener() { // anonymous inner class 94 // update the GUI fields public void actionPerformed( ActionEvent event ) { displayRecord( transactionField.getText() ); } 100 } // end anonymous inner class 102
128
103 ); // end call to addActionListener
104 JMenuBar menuBar = new JMenuBar(); // set up the menu setJMenuBar( menuBar ); 107 JMenu fileMenu = new JMenu( "File" ); menuBar.add( fileMenu ); 110 // set up menu item for adding a record newItem = new JMenuItem( "New Record" ); newItem.setEnabled( false ); 114 // register new item listener newItem.addActionListener( 117 new ActionListener() { // anonymous inner class 119 public void actionPerformed( ActionEvent event ) { 122 // set up the GUI fields for editing fields[ BankUI.ACCOUNT ].setEnabled( true ); fields[ BankUI.FIRSTNAME ].setEnabled( true ); fields[ BankUI.LASTNAME ].setEnabled( true ); fields[ BankUI.BALANCE ].setEnabled( true ); fields[ BankUI.TRANSACTION ].setEnabled( false );
129
129 actionButton.setEnabled( true ); actionButton.setText( "Create" ); cancelButton.setEnabled( true ); 133 userInterface.clearFields(); // reset the textfields 135 } // end method actionPerformed 137 } // end anonymous inner class 139 ); // end call to addActionListener 141 // set up menu item for updating a record updateItem = new JMenuItem( "Update Record" ); updateItem.setEnabled( false ); 145 // register update item listener updateItem.addActionListener( 148 new ActionListener() { // anonymous inner class 150 public void actionPerformed( ActionEvent event ) {
130
153 // set up the GUI fields for editing
fields[ BankUI.ACCOUNT ].setEnabled( true ); fields[ BankUI.FIRSTNAME ].setEnabled( false ); fields[ BankUI.LASTNAME ].setEnabled( false ); fields[ BankUI.BALANCE ].setEnabled( false ); fields[ BankUI.TRANSACTION ].setEnabled( true ); 159 actionButton.setEnabled( true ); actionButton.setText( "Update" ); cancelButton.setEnabled( true ); 163 userInterface.clearFields(); // reset the textfields 165 } // end method actionPerformed 167 } // end anonymous inner class 169 ); // end call to addActionListener 171 // set up menu item for deleting a record deleteItem = new JMenuItem( "Delete Record" ); deleteItem.setEnabled( false ); 175 // register delete item listener deleteItem.addActionListener( 178
131
179 new ActionListener() { // anonymous inner class
180 public void actionPerformed( ActionEvent event ) { // set up the GUI fields for editing fields[ BankUI.ACCOUNT ].setEnabled( true ); fields[ BankUI.FIRSTNAME ].setEnabled( false ); fields[ BankUI.LASTNAME ].setEnabled( false ); fields[ BankUI.BALANCE ].setEnabled( false ); fields[ BankUI.TRANSACTION ].setEnabled( false ); 189 actionButton.setEnabled( true ); actionButton.setText( "Delete" ); cancelButton.setEnabled( true ); 193 userInterface.clearFields(); // reset the textfields 195 } // end method actionPerformed 197 } // end anonymous inner class 199 ); // end call to addActionListener 201 // set up menu item for opening file openItem = new JMenuItem( "New/Open File" ); 204
132
205 // register open item listener
openItem.addActionListener( 207 new ActionListener() { // anonymous inner class 209 public void actionPerformed( ActionEvent event ) { // try to open the file if ( !openFile() ) return; 215 // set up the menu items newItem.setEnabled( true ); updateItem.setEnabled( true ); deleteItem.setEnabled( true ); openItem.setEnabled( false ); 221 // set the interface userInterface.setVisible( true ); fields[ BankUI.ACCOUNT ].setEnabled( false ); fields[ BankUI.FIRSTNAME ].setEnabled( false ); fields[ BankUI.LASTNAME ].setEnabled( false ); fields[ BankUI.BALANCE ].setEnabled( false ); fields[ BankUI.TRANSACTION ].setEnabled( false ); 229 } // end method actionPerformed 231
133
232 } // end anonymous inner class
233 ); // end call to addActionListener 235 // set up menu item for exiting program exitItem = new JMenuItem( "Exit" ); 238 // register exit item listener exitItem.addActionListener( 241 new ActionListener() { // anonyomus inner class 243 public void actionPerformed( ActionEvent event ) { try { dataFile.closeFile(); // close the file } 249 catch ( IOException ioException ) { JOptionPane.showMessageDialog( TransactionProcessor.this, "Error closing file", "IO Error", JOptionPane.ERROR_MESSAGE ); } 255 finally { System.exit( 0 ); // exit the program }
134
259 } // end method actionPerformed 261 } // end anonymous inner class 263 ); // end call to addActionListener 265 // attach menu items to File menu fileMenu.add( openItem ); fileMenu.add( newItem ); fileMenu.add( updateItem ); fileMenu.add( deleteItem ); fileMenu.addSeparator(); fileMenu.add( exitItem ); 273 setSize( 400, 250 ); setVisible( true ); 276 } // end constructor 278 public static void main( String args[] ) { new TransactionProcessor(); } 283
135
Creëer een instantie van FileEditor met de naam van de file
// get the file name and open the file private boolean openFile() { // display dialog so user can select file JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY ); 290 int result = fileChooser.showOpenDialog( this ); 292 // if user clicked Cancel button on dialog, return if ( result == JFileChooser.CANCEL_OPTION ) return false; 296 // obtain selected file File fileName = fileChooser.getSelectedFile(); 299 // display error if file name invalid if ( fileName == null || fileName.getName().equals( "" ) ) { JOptionPane.showMessageDialog( this, "Invalid File Name", "Bad File Name", JOptionPane.ERROR_MESSAGE ); return false; } 306 try { // call the helper method to open the file dataFile = new FileEditor( fileName ); } Creëer een instantie van FileEditor met de naam van de file
136
Wordt opgeroepen wanneer er op de eerste button wordt geklikt
311 catch( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error Opening File", "IO Error", JOptionPane.ERROR_MESSAGE ); return false; } 317 return true; 319 } // end method openFile 321 // create, update or delete the record private void performAction( String action ) { try { 326 // get the textfield values String[] values = userInterface.getFieldValues(); 329 int accountNumber = Integer.parseInt( values[ BankUI.ACCOUNT ] ); String firstName = values[ BankUI.FIRSTNAME ]; String lastName = values[ BankUI.LASTNAME ]; double balance = Double.parseDouble( values[ BankUI.BALANCE ] ); 334 if ( action.equals( "Create" ) ) dataFile.newRecord( accountNumber, // create a new record firstName, lastName, balance ); Wordt opgeroepen wanneer er op de eerste button wordt geklikt Creërt een nieuw record
137
Wijzigt een record Verwijdert een record 338
else if ( action.equals( "Update" ) ) dataFile.updateRecord( accountNumber, // update record firstName, lastName, balance ); 342 else if ( action.equals( "Delete" ) ) dataFile.deleteRecord( accountNumber ); // delete record 345 else JOptionPane.showMessageDialog( this, "Invalid Action", "Error executing action", JOptionPane.ERROR_MESSAGE ); 349 } // end try 351 catch( NumberFormatException format ) { JOptionPane.showMessageDialog( this, "Bad Input", "Number Format Error", JOptionPane.ERROR_MESSAGE ); } 356 catch( IllegalArgumentException badAccount ) { JOptionPane.showMessageDialog( this, badAccount.getMessage(), "Bad Account Number", JOptionPane.ERROR_MESSAGE ); } catch( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error writing to the file", "IO Error", JOptionPane.ERROR_MESSAGE ); } Wijzigt een record Verwijdert een record
138
Toont een record in de tekstvelden
365 } // end method performAction 367 // input a record in the textfields and update the balance private void displayRecord( String transaction ) { try { // get the account number int accountNumber = Integer.parseInt( userInterface.getFieldValues()[ BankUI.ACCOUNT ] ); 375 // get the associated record RandomAccessAccountRecord record = dataFile.getRecord( accountNumber ); 379 if ( record.getAccount() == 0 ) JOptionPane.showMessageDialog( this, "Record does not exist", "Bad Account Number", JOptionPane.ERROR_MESSAGE ); 383 // get the transaction double change = Double.parseDouble( transaction ); 386 // create a string array to send to the textfields String[] values = { String.valueOf( record.getAccount() ), record.getFirstName(), record.getLastName(), String.valueOf( record.getBalance() + change ), "Charge(+) or payment (-)" }; Toont een record in de tekstvelden
139
392 userInterface.setFieldValues( values ); 394 } // end try 396 catch( NumberFormatException format ) { JOptionPane.showMessageDialog( this, "Bad Input", "Number Format Error", JOptionPane.ERROR_MESSAGE ); } 401 catch ( IllegalArgumentException badAccount ) { JOptionPane.showMessageDialog( this, badAccount.getMessage(), "Bad Account Number", JOptionPane.ERROR_MESSAGE ); } 406 catch( IOException ioException ) { JOptionPane.showMessageDialog( this, "Error reading the file", "IO Error", JOptionPane.ERROR_MESSAGE ); } 411 } // end method displayRecord 413 414 } // end class TransactionProcessor
140
Domeinklasse FileEditor
Instanties van de klasse FileEditor verrichten de gepaste bewerkingen op de geselecteerde file
141
Creëert een random access file met gegeven naam
// Fig : FileEditor.java // This class declares methods that manipulate bank account // records in a random access file. import java.io.*; 5 import com.deitel.jhtp5.ch17.RandomAccessAccountRecord; 7 public class FileEditor { 9 RandomAccessFile file; // reference to the file 11 // open the file public FileEditor( File fileName ) throws IOException { file = new RandomAccessFile( fileName, "rw" ); } 17 // close the file public void closeFile() throws IOException { if ( file != null ) file.close(); } 24 Creëert een random access file met gegeven naam Sluit de random access file
142
Leest een record uit de file
// get a record from the file public RandomAccessAccountRecord getRecord( int accountNumber ) throws IllegalArgumentException, NumberFormatException, IOException { RandomAccessAccountRecord record = new RandomAccessAccountRecord(); 30 if ( accountNumber < 1 || accountNumber > 100 ) throw new IllegalArgumentException( "Out of range" ); 33 // seek appropriate record in file file.seek( ( accountNumber - 1 ) * RandomAccessAccountRecord.SIZE ); 36 record.read( file ); 38 return record; 40 } // end method getRecord 42 // update record in file public void updateRecord( int accountNumber, String firstName, String lastName, double balance ) throws IllegalArgumentException, IOException { RandomAccessAccountRecord record = getRecord( accountNumber ); if ( accountNumber == 0 ) throw new IllegalArgumentException( "Account does not exist" ); 51 Leest een record uit de file Positioneer de file-position pointer Lees een record Wijzig een record
143
Positioneer de file-position pointer
// seek appropriate record in file file.seek( ( accountNumber - 1 ) * RandomAccessAccountRecord.SIZE ); 54 record = new RandomAccessAccountRecord( accountNumber, firstName, lastName, balance ); 57 record.write( file ); // write updated record to file 59 } // end method updateRecord 61 // add record to file public void newRecord( int accountNumber, String firstName, String lastName, double balance ) throws IllegalArgumentException, IOException { RandomAccessAccountRecord record = getRecord( accountNumber ); 68 if ( record.getAccount() != 0 ) throw new IllegalArgumentException( "Account already exists" ); 71 // seek appropriate record in file file.seek( ( accountNumber - 1 ) * RandomAccessAccountRecord.SIZE ); 74 record = new RandomAccessAccountRecord( accountNumber, firstName, lastName, balance ); Positioneer de file-position pointer Overschrijf het record Creëer een nieuw record Positioneer de file-position pointer
144
Schrijf het nieuwe record weg naar de file
77 record.write( file ); // write record to file 79 } // end method newRecord 81 // delete record from file public void deleteRecord( int accountNumber ) throws IllegalArgumentException, IOException { RandomAccessAccountRecord record = getRecord( accountNumber ); 87 if ( record.getAccount() == 0 ) throw new IllegalArgumentException( "Account does not exist" ); 90 // seek appropriate record in file file.seek( ( accountNumber - 1 ) * RandomAccessAccountRecord.SIZE ); 93 // create a blank record to write to the file record = new RandomAccessAccountRecord(); record.write( file ); 97 } // end method deleteRecord 99 100 } // end class EditFile Schrijf het nieuwe record weg naar de file Verwijder een record Positioneer de file-position pointer Verwijder een record door het oude record te overschrijven met een leeg record
145
17.13 Nieuwe I/O APIs voor Java
Buffers Om de snelheid van I/O bewerkingen te verhogen Eigenschappen van een buffer: Capacity: hoeveelheid gegevens die je in een buffer kan opslaan Limit: huidig einde van de buffer, limit<=capacity Position: wijst naar het volgende element van de buffer dat wordt gelezen of weggeschreven Mark: herkenningsplaats in de buffer, waar het programma later kan naar terugkeren, mark<=position Put and get bewerkingen om gegevens te schrijven naar en te lezen uit buffers Overige bewerkingen: clear, flip, rewind, reset
146
17.13 Nieuwe I/O APIs voor Java
Channels Verbinding met een I/O device Werkt efficiënt samen met buffers ReadableByteChannel interface Methode read WriteableByteChannel interface Methode write Scattering reads en gathering writes Class FileChannel stelt een channel voor verbonden met een file
147
17.13 Nieuwe I/O APIs voor Java
File Locks Beperkt de toegang tot een deel van een file FileChannel, position, size Exclusive of shared Charsets Package java.nio.charset Class Charset Methoden decode, encode Class CharsetDecoder, CharsetEncoder
148
Voorbeeld Gegevens lezen en schrijven in een FileChannel door gebruik te maken van buffers.
149
Import de java.nio en java.nio.channels packages
// Fig. 17.23: FileChannelTest.java // Demonstrates FileChannel and ByteBuffer. import java.io.*; import java.nio.*; import java.nio.channels.*; 6 public class FileChannelTest { private FileChannel fileChannel; 9 // no-arg constructor public FileChannelTest() { // create random access file and get file channel try { RandomAccessFile file = new RandomAccessFile( "Test", "rw" ); fileChannel = file.getChannel(); } catch ( IOException ioException ) { ioException.printStackTrace(); } 21 } // end constructor FileChannelTest 23 Import de java.nio en java.nio.channels packages Haalt een channel op door de methode getChannel aan te roepen
150
Alloceert een buffer van 14 bytes
// write to writeChannel public void writeToFile() throws IOException { // create buffer for writing ByteBuffer buffer = ByteBuffer.allocate( 14 ); 29 // write an int, a char and a double to buffer buffer.putInt( 100 ); buffer.putChar( 'A' ); buffer.putDouble( ); 34 // flip buffer and write buffer to fileChannel buffer.flip(); fileChannel.write( buffer ); } 39 // read from readChannel public void readFromFile() throws IOException { String content = ""; 44 // create buffer for read ByteBuffer buffer = ByteBuffer.allocate( 14 ); 47 Alloceert een buffer van 14 bytes Vul de buffer met een geheel getal, een karakter en een gebroken getal met dubbele precisie Flipt de buffer om hem voor te bereiden om weg te schrijven Schrijft de buffer naar een FileChannel Alloceer een buffer van 14 bytes
151
Positioneer de FileChannel bij het begin en vul de buffer met bytes
// read buffer from fileChannel fileChannel.position( 0 ); fileChannel.read( buffer ); 51 // flip buffer for reading buffer.flip(); 54 // obtain content content += buffer.getInt() + ", " + buffer.getChar() + ", " + buffer.getDouble(); 58 System.out.println( "File contains: " + content ); 60 // close fileChannel fileChannel.close(); 63 } // end method readFromFile 65 public static void main( String[] args ) { FileChannelTest application = new FileChannelTest(); 69 Positioneer de FileChannel bij het begin en vul de buffer met bytes Flip de buffer om hem voor te bereiden om te lezen Vul de buffer met een geheel getal, een karakter en een gebroken getal met dubbele precisie Sluit de FileChannel
152
70 // write to file and then read from file
try { application.writeToFile(); application.readFromFile(); } catch ( IOException ioException ) { ioException.printStackTrace(); } } 79 80 } // end class FileChannelTest
Verwante presentaties
© 2024 SlidePlayer.nl Inc.
All rights reserved.