• Tidak ada hasil yang ditemukan

Input/Output for Binary File

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 195-200)

Working with Files

7.6 Input/Output for Binary File

Sometimes, the order of the catch clauses matters. Suppose we want to catch “file not found” separately from all other exceptions. We may be tempted to write this:

try {

Scanner in = new Scanner(new FileReader("input.txt"));

n = in.nextInt();

}

catch (Exception e) {

//code for all exceptions (except “file not found”, presumably) }

catch (FileNotFoundException e) { //code for file not found }

This code would not even compile! When Java reaches the last catch, it will complain that

FileNotFoundException has already been caught. This is because FileNotFoundException is a subclass of Exception.

To fix the problem, we must put catch (FileNotFoundException e) before catch (Exception e).

In general, subclass exceptions must come before the containing class.

Program P7.2

import java.io.*;

import java.util.*;

public class CreateBinaryFile {

public static void main(String[] args) throws IOException { Scanner in = new Scanner(new FileReader("num.txt"));

DataOutputStream out = new DataOutputStream(new FileOutputStream("num.bin"));

int n = in.nextInt();

while (n != 0) { out.writeInt(n);

n = in.nextInt();

}

out.close();

in.close();

} //end main

} //end class CreateBinaryFile Suppose num.txt contains the following:

25 18 47 96 73 89 82 13 39 0

When Program P7.2 is run, the numbers (except 0) will be stored in their internal form in the file, num.bin.

The new statement in Program P7.2 is this:

DataOutputStream out = new DataOutputStream(new FileOutputStream("num.bin"));

A data output stream lets a program write primitive Java data types to an output stream. A file output stream is an output stream for writing data to a file. The following constructor creates an output stream connected to the file num.bin:

new FileOutputStream("num.bin")

The following are some of the methods in the DataOutputStream class. All methods write to the underlying output stream, and all values are written with the high byte first (that is, from most significant to least significant byte).

void writeInt(int v) //write an int

void writeDouble(double v) //write a double value

void writeChar(int v) //write a char as a 2-byte value void writeChars(String s) //write a string as a sequence of chars void writeFloat(float v) //write a float value

void writeLong(long v) //write a long value void write(int b) //write the low 8-bits of b

In Program P7.2, out.writeInt(n) writes the integer n to the file num.bin. If you try to view the contents of num.

bin, all you would see is nonsense. Only a program can read and make sense of what is in the file.

Consider Program P7.3, which reads the numbers from the file num.bin and prints them.

Program P7.3

import java.io.*;

public class ReadBinaryFile {

public static void main(String[] args) throws IOException {

DataInputStream in = new DataInputStream(new FileInputStream("num.bin"));

int amt = 0;

try {

while (true) {

int n = in.readInt();

System.out.printf("%d ", n);

++amt;

} }

catch (IOException e) { }

System.out.printf("\n\n%d numbers were read\n", amt);

} //end main

} //end class ReadBinaryFile

If num.bin contains the output from Program P7.2, then Program P7.3 produces the following output:

25 18 47 96 73 89 82 13 39 9 numbers were read

The new statement in Program P7.3 is this:

DataInputStream in = new DataInputStream(new FileInputStream("num.bin"));

A data input stream lets a program read primitive Java data types from an input stream that was created as a data output stream. A file input stream is an input stream for reading data from a file. The following constructor creates an input stream connected to the file num.bin:

new FileInputStream("num.bin")

The following are some of the methods in the DataInputStream class:

int readInt() //read 4 input bytes and return an int value double readDouble() //read 8 input bytes and return a double value char readChar() //read a char as a 2-byte value

void readFully(byte[] b) //read bytes and store in b until b is full float readFloat() //read 4 input bytes and return a float value long readLong() //read 8 input bytes and return a long value int skipBytes(int n) //attempts to skip n bytes of data;

//returns the number actually skipped

Generally speaking, these methods are used to read data that was written using the corresponding “write”

methods from DataOutputStream.

Note the use of try . . . catch to read numbers until end-of-file is reached. Recall that there is no “end-of-data”

value in the file, so we can’t test for this. The while statement will read from the file continuously. When the end-of- file is reached, an EOFException is thrown. This is a subclass of IOException and so is caught.

The catch block is empty, so nothing happens there. Control goes to the following statement, which prints the amount of numbers read.

7.6.2 Binary File of Records

In the previous section, we created, and read from, a binary file of integers. We now discuss how to work with a binary file of records, where a record can consist of two or more fields.

Suppose we want to store information on car parts. For now, we assume that each part record has two fields—an int part number and a double price. Suppose we have a text file parts.txt that contains the parts data in the following format:

4250 12.95 3000 17.50 6699 49.99 2270 19.25 0

We read this data and create a binary file, parts.bin, with Program P7.4.

Program P7.4

import java.io.*;

import java.util.*;

public class CreateBinaryFile1 {

public static void main(String[] args) throws IOException { Scanner in = new Scanner(new FileReader("parts.txt"));

DataOutputStream out = new DataOutputStream(new FileOutputStream("parts.bin"));

int n = in.nextInt();

while (n != 0) { out.writeInt(n);

out.writeDouble(in.nextDouble());

n = in.nextInt();

}

in.close(); out.close();

} //end main

} //end class CreateBinaryFile1

Each record in parts.bin is exactly 12 bytes (4 for int + 8 for double). In the example, there are 4 records so the file will be exactly 48 bytes long. We know that the first record starts at byte 0, the second at byte 12, the third at byte 24, and the fourth at byte 36. The next record will start at byte 48.

In this scenario, we can easily calculate where record n will start; it will start at byte number (n – 1) * 12.

To set the stage for what will come later, we will rewrite Program P7.4 using the following Part class:

class Part { int partNum;

double price;

public Part(int pn, double pr) { partNum = pn;

price = pr;

}

public void printPart() {

System.out.printf("\nPart number: %s\n", partNum);

System.out.printf("Price: $%3.2f\n", price);

}

} //end class Part

Program P7.5 reads the data from the text file parts.txt and creates the binary file parts.bin.

Program P7.5

import java.io.*;

import java.util.*;

public class CreateBinaryFile2 { static final int EndOfData = 0;

public static void main(String[] args) throws IOException { Scanner in = new Scanner(new FileReader("parts.txt"));

DataOutputStream fp = new DataOutputStream(new FileOutputStream("parts.bin"));

Part part = getPartData(in);

while (part != null) { writePartToFile(part, fp);

part = getPartData(in);

}

in.close();

fp.close();

} //end main

public static Part getPartData(Scanner in) { int pnum = in.nextInt();

if (pnum == EndOfData) return null;

return new Part(pnum, in.nextDouble());

}

public static void writePartToFile(Part part, DataOutputStream f) throws IOException { f.writeInt(part.partNum);

f.writeDouble(part.price);

part.printPart(); //print data on standard input } //end writePartToFile

} //end class CreateBinaryFile2 //class Part goes here

When run, Program P7.5 produces the following output:

Part number: 4250 Price: $12.95 Part number: 3000 Price: $17.50 Part number: 6699 Price: $49.99 Part number: 2270 Price: $19.25

After the file has been created, we can read the next Part record with this:

public static Part readPartFromFile(DataInputStream in) throws IOException { return new Part(in.readInt(), in.readDouble());

} //end readPartFromFile This assumes the following declaration:

DataInputStream in = new DataInputStream(new FileInputStream("parts.bin"));

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 195-200)