Using The File Class


Java I/O Package Overview

The java.io package contains numerous classes to help you perform input and output (I/O) operations on a wide variety of sinks and sources including arrays, strings, processes, and files. In the context of I/O operations the term sink describes a destination to which data is written while the term source indicates an origination point from which data is read. This chapter focuses on using a subset of the java.io classes to access files. An understanding of the use of these I/O classes will lead to an understanding of how to use the other types of sinks and sources.

At first approach the java.io package can be intimidating to novice Java programmers. There are InputStreams and OutputStreams, Readers, and Writers, and a bewildering array of subclasses that inherit from these classes. To help tame the conceptual complexity it is helpful to group and categorize the java.io package classes in a couple of different ways. One method of grouping them is by inheritance hierarchy as is shown in figure 18-1. An inheritance hierarchy grouping of the java.io package classes offers several clues about the intended use of each class.

image from book
Figure 18-1: Partial java.io Package Hierarchy

Referring to figure 18-1 — an inheritance hierarchy grouping yields six distinct class categories: 1) the File class, 2) InputStreams, 3) OutputStreams, 4) Readers, 5) Writers, and 6) the RandomAccessFile. Each class category is discussed in greater detail below.

File Class

The File class is used to manipulate information about a file rather than the data contained within a file. A File object represents a file at a metadata level. Once you create a File object you can use it to obtain information about a file such as its length, its read/write ability, and other attributes. You can also use a File object to create an empty file, to delete a file, to create or delete directories, or manipulate lists of files and directories. You do not need to use a File object to create or use a file for data I/O, however, in many file I/O programming situations you will find its services extremely helpful.

InputStream Classes

The InputStream category includes classes that inherit from the InputStream class. InputStream classes treat their data source as a stream of bytes. A byte stream is simply a sequence of bytes that could represent any type of stored data. The InputStream class itself is abstract. This means you must use one, or a combination, of its subclasses to do any real work.

InputStream classes can be used to read raw bytes from a file as is the case with the FileInputStream class, or they can be used to read Java primitive data types (DataInputStream), or serialized objects (ObjectInputStream). You can also read characters but not as efficiently or as flexibly as you can with a Reader. Characters read with an InputStream class will be either 8-bit ASCII or UTF-8 (an ASCII-compatible encoding of a Unicode character). Regardless of what is being read, if it is being read with the help of an InputStream class its data source is treated as a stream of bytes.

OutputStream Classes

The OutputStream category is the complement of its InputStream cousin. OutputStream classes write data to a file as a sequence of bytes. You can use an OutputStream to write raw bytes, primitive Java data types, and serialized objects. You can write characters with OutputStreams as well but not as efficiently or as flexibly as you can with a Writer class. Like its InputStream counterpart, the OutputStream class is abstract so you must use one, or a combination, of its subclasses to do any real work.

Reader Classes

The Reader class category enables you to read a sequence of Unicode characters from a file. You can specify the character encoding scheme to use via a constructor call when you create an InputStreamReader object. Although the underlying data is still stored as a series of bytes, the difference between a Reader and an InputStream is the capability to specify the way in which the bytes are translated into characters vs. being locked into one specific encoding.

The Reader class is abstract. You must use one, or a combination, of its subclasses to perform any real work.

Writer Classes

The Writer class enables you to write a sequence of Unicode characters to a file. You can specify the character encoding scheme to use via a constructor call when you create an OutputStreamWriter object. The Writer class is abstract so you must use one, or a combination, of its subclasses to perform any real work.

RandomAccessFile Class

The RandomAccessFile class stands on its own as it is not an InputStream, OutputStream, Reader, or Writer. The RandomAccessFile class enables you to perform random access file input and output operations as opposed to sequential file I/O offered by the byte stream and character stream classes. You can use a RandomAccessFile object to write bytes, characters, and Java primitive types. If, however, you want to read and write serialized objects, you’ll need to use the ObjectInputStream and ObjectOutputStream classes.

How Do You Choose Between Byte Streams, Character Streams, and RandomAccessFile?

After reading the previous descriptions of InputStreams, OutputStreams, Readers, Writers, and The RandomAccessFile class you may be asking yourself, “OK, but which ones should I use in my program? It seems like RandomAccessFile does everything I need!” Good question.

Generally speaking, if you need to process large files of raw byte information such as image files, music files, or other similar types of data, use the byte stream classes that inherit from InputStream and OutputStream. You would also use these files if you were serializing objects or collections of objects. (i.e., saving a Vector or HashMap of People objects to a file.) Any operation that calls for sequentially accessing raw byte data from a file, or the serialization and deserialization of objects — use the byte stream classes.

If, on the other hand, you were working exclusively with large amounts of text data then the Reader and Writer classes will prove more efficient. These classes are especially helpful if you have a need to internationalize your program as they deal more effectively with Unicode characters than do the byte stream classes.

Finally, if you need to store and retrieve a combination of data such as primitive types mixed with text in a non-sequential manner then the RandomAccessFile is your ticket.

Another Way To Categorize The Java I/O Classes

Another helpful way to categorize the Java I/O classes is by what type of object is required in their constructors. This will help you figure out what class, or combination of classes, can be used to solve your particular file I/O problem. Table 18-1 provides an organization of the Java I/O classes by constructor argument type.

Table 18-1: Java File I/O Classes By Constructor Argument Type

Constructor Argument Type

Input & Output Streams

Readers & Writer

Other

Classes that require a File or String reference that represents the name of the file in the constructor

FileInputStream

FileOutputStream

FileReader

FileWriter

RandomAccessFile

File

Classes that require an InputStream reference in the constructor

BufferedInputStream

DataInputStream

ObjectInputStream

FilterInputStream [†]

InputStreamReader

 

Classes that require an OutputStream reference in the constructor

BufferedOutputStream DataOutputStream ObjectOutputStream PrintStream FilterOutputStream [†]

OutputStreamWriter

 

Classes that require a Reader reference in the constructor

 

BufferedReader

 

Classes that require a Writer reference in the constructor

 

BufferedWriter

 

Classes that require either an OutputStream or a Writer reference in the constructor

 

PrintWriter

 

[†] - The FilterInputStream and FilterOutputStream classes have protected constructors and must be subclassed to provide functionality.

Referring to table 18-1 — With the exception of the File class, all the classes appearing in the first row of the table can be considered to be the primary file I/O classes. Each of the classes FileInputStream, FileOutputStream, FileReader, FileWriter, and RandomAccessFile take either a File or String object as constructor arguments. These File or String arguments represent the name of the file to open or create. I will label these classes as being file-terminal classes, meaning that to perform I/O on a file you must create one or more objects of these types.

The RandomAccessFile class is used by itself to perform both file input and output. It has an extensive user interface that lets you write and read bytes, characters, and primitive types. Because of its extensive set of interface methods I will label this class as being a user-fronting class. Because the RandomAccessFile class is both a file-terminal class and user-fronting class it is used stand-alone to perform file I/O operations and needs no help from other java.io classes to perform its job.

The FileInputStream, FileOutputStream, FileReader, and FileWriter classes have only a few interface methods which are designed to read streams of bytes or characters. In fact, the FileReader and FileWriter classes possess only constructors and it is the methods provided by their base classes InputStreamReader and InputStreamWriter respectively that must be considered when using these classes. Because their interfaces are so sparse these classes are most often used in concert with other stream and reader classes to provide sufficient programmer functionality. Because of this I consider these classes, and by relationship the InputStreamReader and InputStreamWriter classes as well, not to be user-fronting classes.

The remaining classes in table 18-1 are considered to be either intermediate or user-fronting classes. An intermediate class is one that is used in conjunction with a file-terminal class to provide augmented functionality but does not possess sufficient user interface methods to make it a user-fronting class. Any class name that includes the word Buffer is considered to be an intermediate class. The purpose of a class that contains the word Buffer is to improve the efficiency of file I/O operations through the use of I/O buffering. Buffering improves I/O efficiency because individual disk reads and writes are temporarily stored in memory (a buffer, usually in the form of an internal array) until the contents of the buffer is flushed resulting in a combined disk read or write operation.

Table 18-2 provides a grouping of classes according to their classification as a file terminal, intermediate, or user fronting class.

Table 18-2: Java I/O Classes Organized By File-Terminal, Intermediate, Or User-Fronting Characteristic

Usage Characteristic

InputStream & Output Streams

Readers & Writers

Other

File-Terminal

FileInputStream

FileOutputStream

FileReader

FileWriter

RandomAccessFile

Intermediate

BufferedInputStream

BufferedOutputStream

InputStreamReader

BufferedReader

OutputStreamWriter

BufferedWriter

 

User-Fronting

DataInputStream

ObjectInputStream

DataOutputStream

ObjectOutputStream

PrintStream

PrintWriter

RandomAccessFile

Now, before I get into trouble with any Java experts reading this chapter, I have to clarify a few things regarding InputStreams, OutputStreams, Readers, and Writers. Just because I have labeled a class as being intermediate or fileterminal does not mean it cannot be used directly for file I/O. If you need to write or read arrays of bytes or chars to or from a file then the interface methods provided by these classes will suffice. However, the user-fronting classes provide a wide assortment of interface methods which are more convenient to programmers.

Referring to table 18-2 — this arrangement of classes is almost like a menu. Say, for example, you want to write primitive data types to a file using a byte stream. You will need a file-terminal object, optionally an intermediate object, and a user-fronting object. Browsing the table you might select the following: FileOutputStream, BufferedOutputStream, and DataOutputStream. If you wanted to write characters you could go the Writer path by selecting FileWriter, BufferedWriter, and PrintWriter.

The following sections will show you how to use the java.io classes in various combinations to conduct file I/O operations.

Quick Review

The classes in the java.io package can be used to perform I/O operations on various types of data sinks and sources. A sink is a destination to which data is written, and a source is an origination point from which data is read. Strings, arrays, processes, and files are examples of the types of sinks and sources supported by the java.io classes. This chapter focuses on using the java.io classes to perform I/O operations on files.

The java.io package can be intimidating to novice Java programmers. But there are several ways to organize the classes in the java.io package to help tame the conceptual complexity. A class hierarchy organization gives valuable clues regarding the intended use of the java.io classes.

The File class represents the name of a file or directory and is used to manipulate file metadata.

The InputStream and OutputStream classes operate on byte streams. InputStreams and OutputStreams enable you to read and write bytes, primitive types, 8-bit characters, and serialized objects. When performing character I/O with byte streams the local default character encoding is utilized.

The Reader and Writer classes operate on 16-bit Unicode characters. The character encoding can be specified. This is an important internationalization feature.

The RandomAccessFile class is used to perform both file input and output on bytes, chars, and primitive types.

It is also helpful to categorize java.io classes into file-terminal, intermediate, and user-fronting categories. File-terminal classes are used to create or open a file for input, output, or input/output operations. There are five file-terminal classes: FileInputStream, FileOutputStream, FileReader, FileWriter, and RandomAccessFile.

Intermediate classes are used to enhance the performance of file-terminal classes. Generally speaking, any class that contains the word Buffer is an intermediate class.

User-fronting classes are those classes that have a wide variety of user interface methods that make byte, character, primitive type, and/or object I/O operations convenient for the programmer.




Java For Artists(c) The Art, Philosophy, and Science of Object-Oriented Programming
Java For Artists: The Art, Philosophy, And Science Of Object-Oriented Programming
ISBN: 1932504052
EAN: 2147483647
Year: 2007
Pages: 452

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net