j7.pdf
AP Computer Science Ii Java Cs404 with Morrison at North Carolina School of Science and Mathematics
About this note
By: José Luis Salazar Espitia
Created: 2010-10-02
File Size: 28 page(s)
Views: 2
Created: 2010-10-02
File Size: 28 page(s)
Views: 2
About StudyBlue
STUDYBLUE makes things that make you better at school.
Things like online flashcards with photos and audio.
Things like personalized quizzes and friendly reminders about when (and what) to study next.
Think of it as a digital backpack™: access to all of your study materials online and on your phone.
STUDYBLUE exists to make studying efficient and effective for every student, for free. Join us.
“I have used this website for three exams, and I see a huge difference in my test results.”
Naj
Naj
Sign up (free) to study this.
Contents 1 Introduction 1 2 The File Class and Paths 2 2.1 Constructors and Methods . . . . . . . . . . . . . . . . . . . . . . 4 3 A Case Study: Copying a File 5 3.1 A Programming Idiom . . . . . . . . . . . . . . . . . . . . . . . . 7 3.2 Bu ered FileIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 4 Case Study: Creating a Simple Text Editor 11 4.1 Creating a Framework . . . . . . . . . . . . . . . . . . . . . . . . 11 4.2 Getting Going on the run method and Creating Menus . . . . . . 12 4.3 Adding Listeners . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 4.4 A Little Private Business . . . . . . . . . . . . . . . . . . . . . . 16 4.5 Quitting and Closing . . . . . . . . . . . . . . . . . . . . . . . . . 17 4.6 Opening a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 4.7 The Save and Save As Menu Items . . . . . . . . . . . . . . . . . 20 4.8 A Useful Enhancement and Making New live . . . . . . . . . . . . 20 5 Serialization and Saving Objects in Files 26 5.1 Serializing Objects . . . . . . . . . . . . . . . . . . . . . . . . . . 26 5.2 Deserializing Objects . . . . . . . . . . . . . . . . . . . . . . . . . 27 5.3 What if my class contains nonserializables state variables? . . . . 27 1 Introduction A fundamental operation of computer applications is that of reading from and writing to les. This allows us to create permanent records of our activity on the disk and to reopen it later for further editing or use. We will concern ourselves chie y with two major types of les: text les and les that serialize, or pack away, objects which can later be deserialized, or unpacked. We will begin with text les, and do a case study of creating a simple text editor that opens text les for editing in a simple GUI. Along the way we shall 1 meet a new and very useful widget, the JFileChooser. Common to both of these streams is the File class; we shall begin our expo- sition with that. 2 The File Class and Paths The File class belongs to the package java.io; it is used to represent locations in your le system. The File class does not play a role in the actual reading or writing of data to a le. Instances of the le class can point at les or directories stored on your system. There are other objects that handle le IO. Let us explore this class and see what it does. Open a DrJava interactive session, and the Java API guide. Let us begin by looking at the Field Summary in the guide. It features four elds. Really, they harbor two pieces of data, the path separator and the separator character. This character can be yielded up as a character or a string. Hence the existence of four methods. Notice that these methods are static, so we can call them by class name. > import java.io.File; > File.pathSeparator ":" > File.pathSeparatorChar ?:? > File.separator "/" > File.separatorChar ?/? > The purpose of the separator character is to separate les in a path. This character is a \ on Windoze systems, and it is a / on a UNIX system. The notion of path is common to all operating systems. Recall a path consists of a sequence of directories followed by a directory or le. The separator character can be expanded to \and then into." Only the last item in a path can be a regular le; all others must be directories. For example the path animals/mammals/tapir.html speci es a le tapir.html that lives inside of directory mammals, which in turn lives inside of directory animals. In Windoze, this path is speci ed by animals\mammals\tapir.html. 2 The separator character receives its name because it separates items in a le path. Common to the command line interfaces of Windoze and UNIX is the notion of search path. In UNIX if you enter the command ls, it not in your cwd. Therefore UNIX checks your search path, which is a list of paths to directories for the presence of ls. It checks this list in order; if it nds the command, it executes it. Since ls lives in /bin, the directory /bin must be in your path for ls to run. Fortunately, this is done for you by default. Windoze also has a search path mechanism that works in an identical way. Let us show the path on both systems. First on UNIX, we see the path by entering echo $PATH at the command prompt. $ echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games $ In Windoze, bring up a console window by going to the run menu item in the Start menu, and type cmd into the text slot. Then, in this little black window, type PATH at the prompt. Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. C:\Documents and Settings\John Morrison>PATH PATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem In both systems, there is an environment variable containing the search path. In UNIX this is $PATH, in Windoze it is PATH. You will also notice that the search path is a list of absolute paths. Absolute paths in Windoze begin with a drive letter such as C:. Observe that the directory /bin is listed on the path of this machine, so ls there is found and run. If you type an command that does not live in your path, you will get an error message, as seen here. $ ontv bash: ontv: command not found $ We sent UNIX on a wild goose chase and we get rewarded with a nastygram. If you are running a MAC you will see the same things. In Windoze, you will see this, informing us it has been sent on a similarly futile wild goose chase. C:\Documents and Settings\John Morrison>ontv 3 ?ontv? is not recognized as an internal or external command, operable program or batch file. We see that the path separator, which is : in UNIX and ; in Windoze, separates paths in the search path. 2.1 Constructors and Methods We shall most commonly use the constructor public File(String pathname) to create instances of File objects. Such an object may point at a directory or a regular le. This is not surprising to UNIX users, since they know that directories are just special les that contain an index to their contents. You may use an absolute path name, or a relative path name. A relative path name will be relative to the cwd of the java program when it is running on the user?s machine. The exists() method can be used to see if a given le already exists on the user?s system. Here we show a brief example. > f = new File("."); > f.exists() true > g = new File("someFileThatDoesNotExist") > g.exists() false > We begin by making f point at the Java program?s cwd. Naturally, this must exist. We then deliberately chose a le that does not exist in the program?s cwd, and we see that exists() discerns its nonexistence. This method can be very useful for performing le IO; you can use it to avoid clobbering an existing (valuable) le on the (hapless) user?s system. The canRead(), canWrite(), and canExecute() methods are self-explanatory. They come in handy: you can check to see if you have permission for gaining access to a le prior to charging forth. This can save the throwing of an excep- tion. The methods getPath() and getAbsolutePath() will return the string rep- resentation of the path to a le from the program?s cwd. You should make a directory, place a few unvaluable les in it, and experi- ment with the methods in the API. You can remove les, make new directories, 4 and do all manner of le management with this class. Do the simple exercises below in a program or in an interactive DrJava session. Programming Exercises 1. Make a new File object and use it to determine the absolute path of your cwd. 2. Perform ls -l on your cwd. Try resetting permission bits on one of your les by creating a le object. Verify what you did using ls -l, and by using methods from the File class. 3. Make a File object in the interactive prompt and change its cwd to various places. Check for existence and nonexistence of various les. See if you can determine what permissions you have for the les. Can you check if a le is a directory? 3 A Case Study: Copying a File During this section you will see how to read from and write to a text le. We shall emulate the action of the cp command in UNIX. The usage for our program will be $ java Copy donorFile recipientFile and its action will be to copy the contents of the donor le into the recipient le. It will clobber any recipient le that already exists, just as the UNIX cp command does. You may enter this command in the DrJava interactions pane to execute it as well as at the command prompt. Let us begin by creating the class Copy. We will make our method be a static method inside of this class. Here is the start. public class Copy { public static void copy(String donor, String recipient) { } } This le compiles happily. Now, inside of the main method, add this code. donorFile = new File(donor); recipientFile = new File(recipient); 5 Also, add this import statement at the top of the program import java.io.File; to avoid angry yellow. The resulting code will compile happily. Our File objects just point to paths in the le system, which might or might not exist. Next, let us open the donor le for reading and the recipient le for writing. To do so, we use a FileReader as follows. FileReader fr = new FileReader(donorFile); and a FileWriter as follows. FileWriter fw = new FileWriter(donorFile); Take a trip to the API guide for the FileReader class. We are using the constructors FileReader(File file) and FileWriter(File file) to create the code above. Next, we will read each line from the donor le, then write them to the recipient le. Adding in the appropriate exception handling yields the following class import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.FileNotFoundException; import java.io.IOException; public class Copy { public static void copy(File donorFile, File recipientFile) throws IOException { FileReader fr = new FileReader(donorFile); FileWriter fw = new FileWriter(recipientFile); } 6 public static void main(String[] args) { try { copy(new File(args[0]), new File(args[1])); } catch(FileNotFoundException ex) { System.err.println(args[0] + " not found."); } catch(IOException ex) { System.err.println("IOException!"); } } } 3.1 A Programming Idiom We now need to read the contents of the donor le. We shall read it, a line at at time, and in turn write each line to the donor. You might think, \How do I iterate through a le? It was so easy in Python with a for loop!" Here is an idiom that does exactly that. int ch; while( (ch != fr.read()) != -1) { //Process each character of the file. } What we are doing here is to write each character of the donor to the recipient in the loop. We next close each le so they are properly save and so system resource are liberated. int ch; while( (ch = fr.readLine()) != -1) { fr.write(ch); } fw.close(); fr.close(); Putting it all together we get this class. 7 import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.FileNotFoundException; import java.io.IOException; public class Copy { public static void copy(File donorFile, File recipientFile) throws IOException { FileReader fr = new FileReader(donorFile); FileWriter fw = new FileWriter(recipientFile); int ch; while( (ch = fr.read()) != -1 ) { fw.write(ch); } fw.close(); fr.close(); } public static void main(String[] args) { try { copy(new File(args[0]), new File(args[1])); } catch(FileNotFoundException ex) { System.err.println(args[0] + " not found.") ; } catch(IOException ex) { System.err.println("IOException!"); } } } To use this le in DrJava, just use the following command > java Copy donorFile recipientFile Likewise at the UNIX prompt, we can use the same command as follows. $ java Copy donorFile recipientFile 8 3.2 Bu ered FileIO Our rst version of the copy command used unbu ered IO; each fetch of a character from the donor le makes yet another expensive request to the kernel (operating system). This is a process akin to making a twelve{egg omelet by buying one egg from the local market at a time, making twelve trips. Why not grab a couple dozen eggs at a time and keep them in the ?fridge? Typically a computer?s hard drive is formatted into units called blocks. It is very economical to read from or write to a le a block at a time. LINUX Machines at this time typically have a block size of 4K bytes. Likewise, Windoze machines are formatted into blocks that may be 512 bytes, 1K bytes or 4K bytes, depending on the version of the operating system you are running. Java has a facility for taking advantage of this situation; it is packaged in the two classes java.io.BufferedReader and java.io.BufferedWriter. These access les a chunk at a time. The chunk is stored in RAM in a bu er, where your program gains quick access to it. No request need be made to the OS for each character or line. Costly calls to the kernel are only made when a chunk of the le is read or written. An additional bene t is that you don?t have to worry about the block size. For most text leIO, we recommend you use these classes. Creating a bu ered link to a le is simple. Here we create a bu ered reader and a bu ered writer. BufferedReader br = new BufferedReader(new FileReader(someFile)); BufferedWriter br = new BufferedWriter(new FileWriter(someFile)); The object someFile must be of File type. The methods in the two classes exhibit considerable parallelism. Here we compare a few in a table. BufferedReader BufferedWriter Explanation close() close() This closes the stream. read() write() This processes one character to or from the stream. readLine() write(String s) These processes one line to or from the stream. Be aware that readLine() does not read any end-of-line character. As a re- sult, you will need an end-of-line character if you want it in write We will now add bu ering to our copy program. We will revise our program- ming idiom we are using to read from the donor le so we can use readLine(). Note that readLine() returns null when it encounters the end of the le. This method iterates through the le a line at a time. The looping procedure will look like this. 9 String line; while( (line = br.readLine()) != null ) { bw.write(line + "\n"); } We now revise our class as follows. import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.IOException; public class Copy { public static void copy(File donorFile, File recipientFile) throws IOException { BufferedReader br = new BufferedReader(new FileReader(donorFile)); BufferedWriter bw = new BufferedWriter(new FileWriter(recipientFile)); String line; while( (line = br.readLine()) != null ) { bw.write(line + "\n"); } bw.close(); br.close(); } public static void main(String[] args) { try { copy(new File(args[0]), new File(args[1])); } catch(FileNotFoundException ex) { System.err.println(args[0] + " not found."); } catch(IOException ex) { System.err.println("IOException!"); } } } 10 Programming Exercises 1. Use the API guide to nd a test for determining if a le is a regular le or if it is a directory. 2. Modify the Copy class so that the le is copied if the recipient is a regular le or does not exist, and it places a copy of the le in the recipient, if the recipient is a directory. 3. Modify the Copy class so that if we run it with three or more arguments it does the following. It checks if the last argument is a directory. If not, it issues an error message and quits. If the last argument is a directory, it checks to see if all arguments but the last are regular les. If they are, it copies them all inside of the directory that is the last argument. If not, an error message is printed and nothing happens. 4 Case Study: Creating a Simple Text Editor Now we will combine GUI widgets with leIO to create a simple text editor with capabilities similar to those of Notepad, which is a standard element of Windoze. We will code our program in class SimpleTextEditor. What must our class know? It must know what le it is currently editing. It will need a region in which to edit; for this, we will use the class JEditorPane. Since text documents are often large, we will need to be able to scroll; this will occur within a JScrollPane. Along the way, we shall introduce the WindowListener interface and its friends WindowAdapter and WindowEvent so we can control the action of our editor when the user closes it by hitting its go-away box. Go into the API guide and explore these three related items. Since you have seen other listeners, adapters and events, this should have a very familiar feel. 4.1 Creating a Framework Let us begin by blocking in the major elements. We will place our JEditorPane inside a JScrollPane. This will give horizontal and vertical scrollbars where needed. To do this, we insert two lines of code, one to instantiate the JEditorPane, the next to place the editor pane into the JScrollPane. pain = new JEditorPane(); jsp = new JScrollPane(pain); The rest of the code should be familiar. Compile and run; you will see an empty frame with the title \Simple Text Editor." 11 import javax.swing.JFrame; import javax.swing.JEditorPane; import javax.swing.JScrollPane; public class SimpleTextEditor extends JFrame implements Runnable { File currentFile; JEditorPane pain; JScrollPane jsp; public SimpleTextEditor() { super("Simple Text Editor"); currentFile = null; //this inheres in unsaved situations. pain = new JEditorPane(); jsp = new JScrollPane(pain); } public void run() { setSize(500,500); setVisible(true); } public static void main(String[] args) { SimpleTextEditor ste = new SimpleTextEditor(); javax.swing.SwingUtilities.invokeLater(ste); } } 4.2 Getting Going on the run method and Creating Menus Let us now attend to some basic business. We shall go to work on the run() method; make sure you keep setVisible(true) at the end of this method as you work. Add the line getContentPane().add(jsp); to get the scrollpane inside of the frame. Experiment with this. Put in a line of text wider than the window and watch a scrollbar appear on the bottom. Now place many lines in the editor pane, and watch a vericial scrollbar appear on the side. These scrollbars appear automatically as needed. This behavior is attributable to the class JScrollPane. Next, let us put in a File menu. We will need to create and insert a menu bar for the menu to reside in. JMenuBar mbar = new JMenuBar(); 12 setJMenuBar(mbar); JMenu fileMenu = new JMenu("File"); mbar.add(fileMenu); Now compile ane run. You will see a le menu in your window. Next, we add the customary menu items for a text editor. JMenuItem newFile = new JMenuItem("New"); JMenuItem open = new JMenuItem("Open"); JMenuItem save = new JMenuItem("Save"); JMenuItem saveAs = new JMenuItem("Save As..."); JMenuItem quit = new JMenuItem("Quit"); fileMenu.add(newFile); fileMenu.add(open); fileMenu.add(save); fileMenu.add(saveAs); fileMenu.add(quit); Compile and run; if you click on the le menu, you will see all of our menu items. None is now live. 4.3 Adding Listeners We shall begin by attaching a window listener to our application to control the behavior of the go{away box. For now, we will just print a message to stdout. Later we will cause the application to ask the user if he would like to save the le he is now editing before quitting. Now add this code to the constructor. addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { System.out.println("closed for business"); } }); You will need some new import statements, for WindowAdpater and for WindowEvent. Here they are. import java.awt.WindowEvent; import java.awt.WindowAdapter; What is an Adapter? Just as with other event-handling tools, are three types that come into play. One is an event class, WindowEvent, another is an 13 interface, WindowListener. The third, an adapter class, is just a class that implements an interface with empty methods. It is a convenience class; if you have not blown your inheritance, you can extend an adapter class and you do not have to worry about having all of the required methods for the interface. A MouseAdapter class exists for mouse events. You should look through the API guide; you can see a number of useful adapter classes that can sometimes shorten your code. In our code, we are using an anonymous WindowAdapter class as a con- venience. You should look in the WindowListener interface and see what methods are required to implement that interface. You will note there is no ActionAdapter because this has but one method, actionPerformed. Next, we will get the event handler for the quit menu item out of the way. This will be done with an anonymous inner class. quit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { //TODO: save any existing file. System.exit(0); } }); Observe we placed a TODO annotation in the le to indicate to ourselves we have some un nished business. We will later develop a method for saving our e orts to the current le. Now let us catch up and show the entire class. import javax.swing.JFrame; import javax.swing.JMenuBar; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowAdapter; import java.io.File; public class SimpleTextEditor extends JFrame implements Runnable { File currentFile; JEditorPane pain; JScrollPane jsp; 14 public SimpleTextEditor() { super("Simple Text Editor"); currentFile = null;//this inheres in unsaved situations. pain = new JEditorPane(); jsp = new JScrollPane(pain); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { System.out.println("closed for business"); } }); } public void run() { setSize(500,500); getContentPane().add(jsp); JMenuBar mbar = new JMenuBar(); setJMenuBar(mbar); JMenu fileMenu = new JMenu("File");//try to put in keyboard shortuct mbar.add(fileMenu); JMenuItem newFile = new JMenuItem("New"); JMenuItem open = new JMenuItem("Open"); JMenuItem save = new JMenuItem("Save"); JMenuItem saveAs = new JMenuItem("Save As..."); JMenuItem quit = new JMenuItem("Quit"); fileMenu.add(newFile); fileMenu.add(open); fileMenu.add(save); fileMenu.add(saveAs); fileMenu.add(quit); /******************Menu Item Action Listeners*************/ quit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { //TODO: save any existing file. System.exit(0); } }); setVisible(true); } public static void main(String[] args) { SimpleTextEditor ste = new SimpleTextEditor(); javax.swing.SwingUtilities.invokeLater(ste); 15 } } 4.4 A Little Private Business Throughout this business, we anticipate that there are three functions we will use: setting the current le, writing to the current le, and reading from the current le. We only use the reading function in the open menu item, so we will not separately code that. However, writing occurs in a couple of places as does setting the current le. Therefore we will add two private helper methods, one to set the current le and the other to write to it. We will set the current le by using the JFileChooser class. private void setCurrentFile() { JFileChooser jfc = new JFileChooser(); int dialogChoice = jfc.showOpenDialog(null); if(dialogChoice == JFileChooser.APPROVE_OPTION) { currentFile = jfc.getSelectedFile(); } } In this code, we create the JFileChooser, get it to show an open dialog box, and then set current le to the le chosen by the user. Notice that none of this requires any exception handling, since the File class is just a representation of an abstract path in a le system. Next, we create a private helper method to write the current le. Observe that this will overwrite any existing version of the le, just as you would expect from any standard application. private void writeCurrentFile() { try { if(currentFile == null) setCurrentFile(); BufferedWriter bw = new BufferedWriter(new FileWriter(currentFile)); bw.write(pain.getText()); bw.close(); } 16 catch(IOException e) { System.err.println("IOException"); } } 4.5 Quitting and Closing Having taken care of these back-o ce functions, let us turn our attention to the TODO line in the quit menu item?s action listener. When we quit, what do we expect? How do we prevent an accidental click in the go-away box for the editor window from becoming a loss of unsaved changes? 1. If the application?s data is not saved, we get asked if we want to save any changes. 2. The application closes cleanly. This should also happen should the user attempt to close by clicking the go- away box. This we handle using a window listener. Because the same code would appear in two places, we create a private method as follows. private void saveAndQuit() { int choice = JOptionPane.showConfirmDialog(null, "Save Changes?"); if(choice == 0) //if yes, write the file { writeCurrentFile(); System.exit(0); } if(choice == 1) //if no, just exit System.exit(0); //if the choice is 2, we cancel and do nothing. } If you have not already imported it, import the class javax.swing.JOptionPane. We can call this from the window listener and from the quit menu item. Because of the way in which writeCurrentFile is written, this process is very simple. We modify the action listener for quit as follows. We simply delete the TODO line and call writeCurrentFile. We put writeCurrentFile in charge of making all of the preprations for a clean exit and built it to recognize a never-saved le and ensured that it is saved prior to exiting. This makes our application safe for our user. Try opening any app and putting stu in an unsaved le. If you attempt to quit, it wil query you about saving the le. 17 Here we show the appropriate modi cations. Find these pieces of code in your program and update them. quit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { saveAndQuit(); } }); setVisible(true); } addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { saveAndQuit(); } }); 4.6 Opening a File To do this, we will close out any existing le and ask if it should be saved. We then will read the text of the le being opened and place it in the text window. To implement this, we attach an anonymous action listener to the open menu item. We begin by closing the le occupying the window, and setting the current le to a new le. open.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { saveAndCloseCurrentFile(); setCurrentFile(); } }); Our next task is to open the le, hoover it up into a big string, and put the re- sult into pain. Java exhibits some nice parallelism. We will use BufferedReader and FileReader to connect to the le. We then feed it into a StringBuffer, a mutable object designed for accumulating text. Once we are done, we call the string bu er?s toString() method and place that text into the text area of our editor. To do this, we create a try block and place this statement in it. 18 BufferedReader br = new BufferedReader(new FileReader(currentFile)); This creates a bu ered le reader connecting to the current le, which the JFileChooser chose. Next we create a StringBuffer; this object is a mutable bu er in which we may accumulate text. Do not just create a string and con- catenate; this action causes a host of useless immutable objects to be created and to clutter up your program?s performance. We also create a string to hold each line of the le as it is read. StringBuffer sb = new StringBuffer(); String buf = ""; Now we make a loop that reads the le a line at a time, feeding the lines into the StringBuffer. At the end of each line, we need to add a newline, or our text will glob onto a single line. while( (buf = br.readLine()) != null) { sb.append(buf); sb.append(?\n?); } The contents of the le are now read into the string bu er. We call sb?s toString() method to generate a string with the entire le in it. We then set pain?s text to be this string. Then we close the the BufferedReader. pain.setText(sb.toString()); br.close(); This is the method in its entirety. open.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { saveAndCloseCurrentFile(); setCurrentFile(); try { BufferedReader br = new BufferedReader(new FileReader(currentFile)); StringBuffer sb = new StringBuffer(); String buf = ""; while( (buf = br.readLine()) != null) { 19 sb.append(buf); //put lines on end of buffer sb.append(?\n?); //put newline } pain.setText(sb.toString()); br.close(); } } }); 4.7 The Save and Save As Menu Items Now we make these two menu items live. Much of the work has been done; we just attach action listeners and call existing methods. save.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { writeCurrentFile(); } }); saveAs.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { saveAndCloseCurrentFile(); setCurrentFile(); writeCurrentFile(); } }); 4.8 A Useful Enhancement and Making New live We will now cause the path of the le we are editing to be shown in the title bar of our editor?s frame. This is a simple process. If the le is unsaved, put \Unsaved File" in the title bar. Otherwise we will show the absolute path of the le. To do this, we have to look in only two places: setCurrentFile (Gee; Why?d we do that?) and we need to modify the constructor to put Simple Text Editor: Unsaved File in the title bar. Notice how our design makes this upgrade simple! In the constructor change the line super("Simple Text Editor"); to 20 super("Simple Text Editor: Unsaved File"); Now, in setCurrentFile, we add the line setTitle("Simple Text Editor: " + currentFile.getAbsolutePath()); Now our editor will display the full path of the le being edited. This feature is a very useful one that enhances the attractiveness of our program. Now, when we make a new document, we will query the user about saving the existing one, save it if asked to do so, and create a new, unsaved document that is blank. This is achieved by adding an action listener to the New menu item. newFile.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { saveAndCloseCurrentFile(); pain.setText(""); setTitle("Simple Text Editor: Unsaved File"); } }); Our hard work paid o in a big way: adding this new feature was very simple! Finally, we will tell our app to exit when the window is closed. To do this we use our old friend setDefaultCloseOperation(EXIT_ON_CLOSE); We place this in our run method. We now have a very simple text editor. It should remind you a bit of the Notepad editor present on Windoze boxes. This is a simple, complete, working application. It is capable of creating documents, saving them to les, and opening these les later. All the les are plain text les. For your convenience, here is the entire program. import javax.swing.JFrame; import javax.swing.JMenuBar; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JScrollPane; 21 import javax.swing.JOptionPane; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowAdapter; import java.io.File; import java.io.IOException; import java.io.FileWriter; import java.io.BufferedWriter; import java.io.FileReader; import java.io.BufferedReader; import java.io.FileNotFoundException; public class SimpleTextEditor extends JFrame implements Runnable { File currentFile; //boolean currentFileIsSaved JEditorPane pain; JScrollPane jsp; public SimpleTextEditor() { super("Simple Text Editor: Unsaved File"); currentFile = null;//this inheres in unsaved situations. //currentFileisSaved = false; pain = new JEditorPane(); jsp = new JScrollPane(pain); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e) { saveAndQuit(); } }); } public void run() { setSize(500,500); setDefaultCloseOperation(EXIT_ON_CLOSE); getContentPane().add(jsp); JMenuBar mbar = new JMenuBar(); setJMenuBar(mbar); JMenu fileMenu = new JMenu("File");//try to put in keyboard shortuct mbar.add(fileMenu); JMenuItem newFile = new JMenuItem("New"); JMenuItem open = new JMenuItem("Open"); JMenuItem save = new JMenuItem("Save"); 22 JMenuItem saveAs = new JMenuItem("Save As..."); JMenuItem quit = new JMenuItem("Quit"); fileMenu.add(newFile); fileMenu.add(open); fileMenu.add(save); fileMenu.add(saveAs); fileMenu.add(quit); /******************Menu Item Action Listeners*************/ newFile.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { saveAndCloseCurrentFile(); pain.setText(""); setTitle("Simple Text Editor: Unsaved File"); } }); quit.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { saveAndQuit(); } }); open.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { if(pain.getText().length() > 0) { saveAndCloseCurrentFile(); } setCurrentFile(); try { BufferedReader br = new BufferedReader(new FileReader(currentFile)); StringBuffer sb = new StringBuffer(); String buf = ""; while( (buf = br.readLine()) != null) { sb.append(buf); sb.append(?\n?); } //bw.write(pain.getText()); pain.setText(sb.toString()); br.close(); } catch(FileNotFoundException ex) 23 { System.err.println("File Not Found"); } catch(IOException ex) { System.err.println("IO Exception Occurred"); } } }); save.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { writeCurrentFile(); } }); saveAs.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e) { saveAndCloseCurrentFile(); setCurrentFile(); writeCurrentFile(); } }); setVisible(true); } private void setCurrentFile() { JFileChooser jfc = new JFileChooser(); int dialogChoice = jfc.showOpenDialog(null); if(dialogChoice == JFileChooser.APPROVE_OPTION) { currentFile = jfc.getSelectedFile(); } setTitle("Simple Text Editor: " + currentFile.getAbsolutePath()); } private void saveAndQuit() { int choice = JOptionPane.showConfirmDialog(null, "Save Changes?"); if(choice == 0) //if yes, write the file { writeCurrentFile(); System.exit(0); } if(choice == 1) //if no, just exit 24 System.exit(0); //if the choice is 2, we cancel and do nothing. } private void saveAndCloseCurrentFile() { int choice = JOptionPane.showConfirmDialog(null, "Save Changes?"); if(choice == 0) //if yes, write the file writeCurrentFile(); //the file is closed when we are done. //if the choice is 2, we cancel and do nothing. } //precondition: none //postcondition: current text in editor is written to the //current file and the current file is then closed. private void writeCurrentFile() { try { if(currentFile == null) setCurrentFile(); BufferedWriter bw = new BufferedWriter(new FileWriter(currentFile)); bw.write(pain.getText()); bw.close(); } catch(IOException e) { System.err.println("IOException"); } } public static void main(String[] args) { SimpleTextEditor ste = new SimpleTextEditor(); javax.swing.SwingUtilities.invokeLater(ste); } } Programming Exercises 1. Use a little conditional logic to guarantee that a le saved by SimpleTextEditor has an extension .ste. If the le is saved with such an extension, do not add a second one. 2. Go to the Java tutorial \How to use le choosers." Learn about FileFilter. Use this to enable the display of only directories and les with a .ste ex- tension. 25 3. Add a Font Size menu and use setFont on JEditorPane to enable the user of your editor to change font size. 4. Add a Font Menu that allows the user to change the typeface. 5 Serialization and Saving Objects in Files Now we will learn now to save Java objects into a le, pack them away in a binary format, and re ate them later. We will use them to save the state information of our program, so we can later reconstruct and restore our session with our application. The process of packing an object away in this fashion is called serialization; unpacking is called deserialization. Our next case study will consist of creating a simple drawing program, and enabling this program to archive and reconstitute our drawings. The discussion here will enable us to understand the necessary mechanism to accomplish the job. To make our objects serializable, our classes must implement the interface java.io.Serializable. This interface is a pure bundler interface: you are not required to implement any methods. Recall that all descendants of any class implementing an interface automatically implement that interface. Hence, any class you create that is serializable will automatically pass this property on to its children. 5.1 Serializing Objects You will need to employ two classes: and java.io.FileOutputStream and java.io.ObjectOutputStream To create a connection to a le in which we will store objects, we do the following. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(someFile); The object someFile should be a location in your le system. You may write any serializable object to the le by making the call oos.writeObject(someObject); 26 This causes someObject to be serialized and placed into someFile. All of these procedures are dangerous; they must be placed in a try block and the appro- priate exceptions should be caught and handled. 5.2 Deserializing Objects Now let?s enjoy the parallelism! You will need to employ two classes: java.io.FileInputStream and java.io.ObjectInputStream To create a connection to a le in which we will store objects, we do the following. ObjectInputStream ois = new ObjectInputStream(new FileInputStream(someFile); The object someFile should be a location in your le system. You may write any serializable object to the le by making the call oos.readObject(someObject); This causes someObject to be deserialized and become a useable object in your program. It will emerge as a generic Object object. You will need to cast it to the correct type. All of these procedures are dangerous; they must be placed in a try block and the appropriate exceptions should be caught and handled. 5.3 What if my class contains nonserializables state vari- ables? You can mark such objects transient; these will not be serialized when your object is serialized. 27 28
Back
Next
About this note
By: José Luis Salazar Espitia
Created: 2010-10-02
File Size: 28 page(s)
Views: 2
Created: 2010-10-02
File Size: 28 page(s)
Views: 2
About StudyBlue
STUDYBLUE makes things that make you better at school.
Things like online flashcards with photos and audio.
Things like personalized quizzes and friendly reminders about when (and what) to study next.
Think of it as a digital backpack™: access to all of your study materials online and on your phone.
STUDYBLUE exists to make studying efficient and effective for every student, for free. Join us.
“I have used this website for three exams, and I see a huge difference in my test results.”
Naj
Naj