Sams Teach Yourself Java 2 in 24 Hours
- Table of Contents
- Copyright
- About the Author
- About the Technical Editor
- Acknowledgments
- We Want to Hear from You!
- Reader Services
- Introduction
- Hour 1. Becoming a Programmer
- Hour 2. Writing Your First Program
- Hour 3. Vacationing in Java
- Hour 4. Understanding How Java Programs Work
- Part II: Learning the Basics of Programming
- Hour 5. Storing and Changing Information in a Program
- Hour 6. Using Strings to Communicate
- Hour 7. Using Conditional Tests to Make Decisions
- Hour 8. Repeating an Action with Loops
- Part III: Working with Information in New Ways
- Hour 9. Storing Information with Arrays
- Hour 10. Creating Your First Object
- Hour 11. Describing What Your Object Is Like
- Hour 12. Making the Most of Existing Objects
- Part IV: Programming a Graphical User Interface
- Hour 13. Building a Simple User Interface
- Hour 14. Laying Out a User Interface
- Hour 15. Responding to User Input
- Hour 16. Building a Complex User Interface
- Part V: Creating Multimedia Programs
- Hour 17. Creating Interactive Web Programs
- Hour 18. Handling Errors in a Program
- Hour 19. Creating a Threaded Program
- Hour 20. Reading and Writing Files
- Part VI: Creating Multimedia Programs
- Hour 21. Using Fonts and Color
- Hour 22. Playing Sound Files
- Hour 23. Working with Graphics
- Hour 24. Creating Animation
- Part VII: Appendixes
- Appendix A. Tackling New Features of Java 2 Version 1.4
- Appendix B. Using the Java 2 Software Development Kit
- Appendix C. Programming with the Java 2 Software Development Kit
- Appendix D. Using Sun ONE Studio
- Appendix E. Where to Go from Here: Java Resources
- Appendix F. This Book's Web Site
Streams
To save data permanently within a Java program, or to retrieve that data later, you must use at least one stream.
A stream is an object that takes information from one source and sends it to another. The name is inspired by streams that take fish, boats, inner tube riders, and industrial pollutants from one place to another.
Streams connect a diverse variety of sources, including computer programs, hard drives, Internet servers, computer memory, and CD-ROMs. Because all these things use streams, once you learn how to work with one kind of data, you will be able to work with others in the same manner.
During this hour, you will use streams to read and write data stored in files on your computer.
There are two kinds of streams:
- Input streams, which read data from a source
- Output streams, which write data to a source
All input and output streams are made up of bytes, individual integers with values ranging from 0 to 255. You can use this format to represent data, such as executable programs, word-processing documents, and MP3 music files, but those are only a small sampling of what bytes can represent. A byte stream is used to read and write this kind of data.
A more specialized way to work with data is in the form of characters—individual letters, numbers, punctuation, and the like. A character stream can be used when you are reading and writing text files, word-processing documents, Web pages and the like.
Whether you work with a stream of bytes, characters, or other kinds of information, the overall process is the same:
- You create a stream object associated with the data.
- You call methods of the stream to either put information in the stream or take information out of it.
- You close the stream by calling the object's close() method.
Files
In Java, files are represented by the File class, which also is part of the java.io package. Files can be read from hard drives, floppy drives, CD-ROMs, and other storage devices.
A File object can represent files that already exist and files you want to create. To create a File object, use the name of the file as the constructor, as in this example:
File bookName = new File("address.dat");
This creates an object for a file named address.dat in the current folder. You can also include a path in the filename:
File bookName = new File("data\address.dat");
Once you have a File object, you can call several useful methods on that object:
- exists()— true if the file exists, false otherwise.
- getName()— The name of the file, as a String.
- length()— The size of the file, as a long value.
- createNewFile()— Creates a file of the same name, if one does not exist already.
- delete()— Delete the file, if it exists.
- renameTo( File )— Renames the file, using the name of the File object specified as an argument.
You also can use a File object to represent a folder on your system rather than a file. Specify the folder name in the File constructor, which can be absolute (such as "C:\MyDocuments\") or relative (such as "java\database").
Once you have an object representing a folder, you can call its listFiles() method to see what's inside the folder. This method returns an array of File objects representing every file and subfolder it contains.
Reading Data from a Stream
The first project of the hour is to read data from a file using an input stream. You can do this using the FileInputStream class, which represents input streams that will be read as bytes from a file.
You can create a file input stream by specifying a filename or a File object as the argument to the FileInputStream() constructor method.
The file must exist before the file input stream is created. If it doesn't, an IOException will be generated when you try to create the stream. Many of the methods associated with reading and writing files will generate this exception, so it's often convenient to put all statements involving the file in their own try-catch block, as in this example:
try {
File cookie = new File("cookie.web");
FileInputStream = new FileInputStream(cookie);
System.out.println("Length of file: " + cookie.length());
} catch (IOException e) {
System.out.println("Could not read file.");
}
File input streams read data in bytes. You can read a single byte by calling the stream's read() method without an argument. If no more bytes are available in the stream because you have reached the end of the file, a byte value of -1 will be returned.
When you read an input stream, it begins with the first byte in the stream—such as the first byte in a file. You can skip some bytes in a stream by calling its skip() method with one argument: an int representing the number of bytes to skip. The following statement skips the next 1024 bytes in a stream named scanData:
scanData.skip(1024);
If you want to read more than one byte at a time, do the following:
- Create a byte array that is exactly the size of the number of bytes you want to read.
- Call the stream's read() method with that array as an argument. The array will be filled with bytes read from the stream.
You will create an application that reads ID3 data from an MP3 audio file. Because MP3 is such a popular format for music files, 128 bytes are often added to the end of an ID3 file to hold information about the song, such as the title, artist, and album it is from.
The ReadID3 application reads an MP3 file using a file input stream, skipping everything but the last 128 bytes. The remaining bytes are examined to see if they contain ID3 data. If they do, the first three bytes will be the numbers 84, 65, and 71.
Open the editor you have been using, and enter the text of Listing 20.1. Save the file as ReadID3.java.
Example 20.1. The Full Text of ReadID3.java
1: import java.io.*;
2:
3: public class ReadID3 {
4: public static void main(String[] arguments) {
5: try {
6: File song = new File(arguments[0]);
7: FileInputStream file = new FileInputStream(song);
8: int size = (int)song.length();
9: file.skip(size - 128);
10: byte[] last128 = new byte[128];
11: file.read(last128);
12: String id3 = new String(last128);
13: String tag = id3.substring(0, 3);
14: if (tag.equals("TAG")) {
15: System.out.println("Title: " + id3.substring(3, 32));
16: System.out.println("Artist: " + id3.substring(33, 62));
17: System.out.println("Album: " + id3.substring(63, 91));
18: System.out.println("Year: " + id3.substring(93, 97));
19: } else
20: System.out.println(arguments[0] + " does not contain"
21: + " ID3 info.");
22: file.close();
23: } catch (Exception e) {
24: System.out.println("Error — " + e.toString());
25: }
26: }
27: }
When you compile this source file, a ReadID3 class file will be created. You can run this class as an application, specifying an MP3 file on your system as a command-line argument. For example:
java ReadID3 Everlong.mp3
If you have the song Everlong.mp3 on your system (and you really should), here's an example of what the ReadID3 application will display:
Title: Everlong Artist: Foo Fighters Album: The Colour and the Shape Year: 1997
The application reads the last 128 bytes from the MP3 in Lines 10–11 of Listing 20.1, storing them in a byte array. This array is used in Line 12 to create a String object that contains the characters represented by those bytes.
If the first three characters in the string are "TAG," the MP3 file being examined contains ID3 information in a format the application understands.
In Lines 15–18, the string's substring() method is called to display portions of the string. The characters to display are from the ID3 format, which always puts the artist, song, title, and year information in the same positions in the last 128 bytes of an MP3 file.
Some MP3 files either don't contain ID3 information at all or contain ID3 information in a different format than application can read.
The file Everlong.mp3 will contain readable ID3 information if you created it from a copy of The Colour and the Shape CD that you purchased, because programs that create MP3 files from audio CDs read song information from a music industry database called CDDB.
After everything related to the ID3 information has been read from the MP3's file input stream, the stream is closed in Line 22. You should always close streams when you are finished with them to conserve resources in the Java interpreter.
Buffered Input Streams
One of the ways to improve the performance of a program that reads input streams is to buffer the input. Buffering is the process of saving data in memory for use later when a program needs it. When a Java program needs data from a buffered input stream, it looks in the buffer first, which is faster than reading from a source such as a file.
To use a buffered input stream, you create an input stream such as a FileInputStream object, then use that object to create a buffered stream. Call the BufferedInputStream( InputStream ) constructor with the input stream as the only argument. Data will be buffered as it is read from the input stream.
To read from a buffered stream, call its read() method with no arguments. An integer from 0 to 255 will be returned that represents the next byte of data in the stream. If no more bytes are available, -1 is returned instead.
As a demonstration of buffered streams, the next program you create will add a feature to Java that many programmers miss from other languages they have used: console input.
Console input is the ability to read characters from the console (also known as the command line) while running an application.
The System class, which contains the out variable used in the System.out.print() and System.out.println() statements, has a class variable called in that represents an InputStream object. This object receives input from the keyboard and makes it available as a stream.
You can work with this input stream like any other. The following statement creates a buffered input stream associated with the System.in input stream:
BufferedInputStream bin = new BufferedInputStream(System.in);
The next project, the ReadConsole class, contains a class method you can use to receive console input in any of your Java applications. Enter the text of Listing 20.2 in your editor and save the file as ReadConsole.java.
Example 20.2. The Full Text of ReadConsole.java
1: import java.io.*;
2:
3: public class ReadConsole {
4: public static String readLine() {
5: StringBuffer response = new StringBuffer();
6: try {
7: BufferedInputStream bin = new
8: BufferedInputStream(System.in);
9: int in = 0;
10: char inChar;
11: do {
12: in = bin.read();
13: inChar = (char) in;
14: if (in != -1) {
15: response.append(inChar);
16: }
17: } while ((in != -1) & (inChar != '\n'));
18: bin.close();
19: return response.toString();
20: } catch (IOException e) {
21: System.out.println("Exception: " + e.getMessage());
22: return null;
23: }
24: }
25:
26: public static void main(String[] arguments) {
27: System.out.print("You are standing at the end of the road ");
28: System.out.print("before a small brick building. Around you ");
29: System.out.print("is a forest. A small stream flows out of ");
30: System.out.println("the building and down a gully.\n");
31: System.out.print("> ");
32: String input = ReadConsole.readLine();
33: System.out.println("That's not a verb I recognize.");
34: }
35: }
The ReadConsole class includes a main() method that demonstrates how it can be used. When you compile and run it as an application, the output should resemble the following:
You are standing at the end of the road before a small brick building. Around you is a forest. A small stream flows out of the building and down a gully. > go north That's not a verb I recognize.
The ReadConsole class contains one class method, readLine(), which receives characters from the console. When the Enter key is hit, readLine() returns a String object that contains all the characters that were received.
If you save the ReadConsole class in a folder that is listed in your CLASSPATH environment variable, you can call ReadConsole.readLine() from any Java program that you write.
Writing Data to a Stream | Next Section

Account Sign In
View your cart