Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 21 – Advanced Input/Output

Similar presentations


Presentation on theme: "Chapter 21 – Advanced Input/Output"— Presentation transcript:

1 Chapter 21 – Advanced Input/Output

2 Chapter Goals To become familiar with text and binary file formats To learn about encryption To understand when to use sequential and random file access To read and write objects using serialization

3 Readers, Writers, and Streams
Two ways to store data: text and binary format. Text format: human-readable form, as a sequence of characters. E.g. Integer 12,345 stored as characters '1' '2' '3' '4' '5'. More convenient for humans: easier to produce input and to check output. Readers and writers handle data in text form. Binary format: data items are represented in bytes. E.g. Integer 12,345 stored as sequence of four bytes More compact and more efficient. Streams handle binary data.

4 Java Classes for Input and Output
Figure 1 Java Classes for Input and Output

5 Text Data Reader and Writer and their subclasses were designed to process text input and output. PrintWriter was used in Chapter 7. Scanner class is more convenient than Reader class. By default, these classes use the character encoding of the computer executing the program. OK, when only exchanging data with users from same country. Otherwise, good idea to use UTF-8 encoding: Scanner in = new Scanner(input, "UTF-8"); // Input can be a File or InputStream PrintWriter out = new PrintWriter(output, "UTF-8"); // Output can be a File or OutputStream

6 Self Check 21.1 Suppose you need to read an image file that contains color values for each pixel in the image. Will you use a Reader or an InputStream? Answer: Image data is stored in a binary format—try loading an image file into a text editor, and you won’t see much text. Therefore, you should use an InputStream.

7 Self Check 21.2 Special Topic 11.1 introduced the openStream method of the URL class, which returns an InputStream: URL locator = new URL(" InputStream in = locator.openStream(); Why doesn’t the URL class provide a Reader instead? Answer: For HTML files, a reader would be useful. But URLs can also point to binary files, such as

8 Binary Input and Output
Use InputStream and OutputStream and their subclasses to process binary input and output. To read: FileInputStream inputStream = new FileInputStream("input.bin"); To write: FileOutputStream outputStream = new FileOutputStream("output.bin"); System.out is a PrintStream object.

9 Binary Input Use read method of InputStream class to read a single byte. Returns the next byte as an int between 0 and Or, the integer -1 at end of file. InputStream in = . . .; int next = in.read(); if (next != -1) { Process next // a value between 0 and 255 }

10 Binary Output Use write method of OutputStream class to write a single byte: OutputStream out = . . .; int value = . . .; // should be between 0 and 255 out.write(value); Use the try-with-resources statement to ensure all open files are closed: try (InputStream in = . . ., OutputStream out = . . .) { Read from in. Write to out. }

11 An Encryption Program File encryption: To scramble file so that it is readable only to those who know the encryption method and secret keyword. To use Caesar cipher: Choose encryption key – a number between 1 and 25 that indicates the shift to be used in encrypting each byte. Example: If the key is 3, replace A with D, B with E, To decrypt, use the negative of the encryption key. Figure 2 The Caesar Cipher

12 An Encryption Program Encryption:
int next = in.read(); if (next == -1) { done = true; } else int encrypted = encrypt(next); out.write(encrypted);

13 section_2/CaesarCipher.java import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; 4 5 6 7 8 9 /** This class encrypts files using the Caesar cipher. For decryption, use an encryptor whose key is the negative of the encryption key. */

14 section_2/CaesarEncryptor.java import java.io.File;
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Scanner; 8 9 /**

15 Self Check 21.3 Why does the read method of the InputStream class return an int and not a byte? Answer: It returns a special value of -1 to indicate that no more input is available. If the return type were byte, no special value would be available that could be distinguished from a legal data value.

16 Self Check 21.4 Decrypt the following message: Khoor/#Zruog$. Answer: It is "Hello, World!", encrypted with a key of 3.

17 Self Check 21.5 Can you use the sample program from this section to encrypt a binary file, for example, an image file? Answer: Yes—the program uses input and output streams and encrypts each byte.

18 Random Access Sequential access: process file one byte at a time.
Random access: access file at arbitrary locations. Only disk files support random access. System.in and System.out do not. Each disk file has a special file pointer position. Read or write at pointer position. Figure 3 Sequential and Random Access

19 RandomAccessFile Class
Open a file with open mode: Reading only ("r"). Reading and writing ("rw"). RandomAccessFile f = new RandomAcessFile("bank.dat","rw"); To move the file pointer to a specific byte: f.seek(position); To get the current position of the file pointer: long position = f.getFilePointer(); // of type "long" because files can be very large To find the number of bytes in a file: long fileLength = f.length();

20 Bank Account Program Use a random access file to store a set of bank accounts. Program lets you pick an account and deposit money into it. To manipulate a data set in a file, pay special attention to data formatting. Suppose we store the data as text: Say account 1001 has a balance of $900, and account 1015 has a balance of 0: Want to deposit $100 into account 1001: Writing out the new value:

21 Bank Account Program Better way to manipulate a data set in a file:
Give each value a fixed size that is sufficiently large. Every record has the same size. Easy to skip quickly to a given record. To store numbers, it is easier to store them in binary format.

22 Bank Account Program RandomAccessFile class stores binary data.
The readInt and writeInt methods read and write integers as four-byte quantities. The readDouble and writeDouble methods process double-precision floating-point numbers as eight-byte quantities. double x = f.readDouble(); f.writeDouble(x); To find out how many bank accounts are in the file: public int size() throws IOException { return (int) (file.length() / RECORD_SIZE); // RECORD_SIZE is 12 bytes: // 4 bytes for account number plus // 8 bytes for balance }

23 Bank Account Program To read the nth account in the file:
public BankAccount read(int n) throws IOException { file.seek(n * RECORD_SIZE); int accountNumber = file.readInt(); double balance = file.readDouble(); return new BankAccount(accountNumber, balance); }

24 Bank Account Program To write the nth account in the file:
public void write(int n, BankAccount account) throws IOException { file.seek(n * RECORD_SIZE); file.writeInt(account.getAccountNumber()); file.writeDouble(account.getBalance()); }

25 section_3/BankSimulator.java import java.io.IOException; import java.util.Scanner; 3 4 5 6 7 8 9 /** This program demonstrates random access. You can access existing accounts and deposit money, or create new accounts. The accounts are saved in a random access file. */ public class BankSimulator

26 section_3/BankData.java Program Run:
import java.io.IOException; import java.io.RandomAccessFile; 3 4 5 6 7 8 9 /** This class is a conduit to a random access file containing bank account records. */ public class BankData { Program Run: Account number: Amount to deposit: Adding new account. Done? (Y/N) N Account number: 1018 Amount to deposit: 200 Adding new account. Done? (Y/N) N Account number: 1001 Amount to deposit: New balance: Done? (Y/N) Y

27 Self Check 21.6 Why doesn’t System.out support random access? Answer: Suppose you print something, and then you call seek(0), and print again to the same location. It would be difficult to reflect that behavior in the console window.

28 Self Check 21.7 What is the advantage of the binary format for storing numbers? What is the disadvantage? Answer: Advantage: The numbers use a fixed amount of storage space, making it possible to change their values without affecting surrounding data. Disadvantage: You cannot read a binary file with a text editor.

29 Object Streams ObjectOutputStream class can save entire objects to disk. ObjectInputStream class can read them back in. Use streams, not writers because objects are saved in binary format.

30 Writing an Object to File
The ObjectOutputStream saves all instance variables: BankAccount b = ...; ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("bank.dat")); out.writeObject(b);

31 Reading an Object From File
readObject method returns an Object reference. Need to remember the types of the objects that you saved and use a cast: ObjectInputStream in = new ObjectInputStream( new FileInputStream("bank.dat")); BankAccount b = (BankAccount) in.readObject(); readObject method can throw ClassNotFoundException checked exception. You must catch or declare it.

32 Write and Read Array List
ArrayList<BankAccount> a = new ArrayList<>(); // Now add many BankAccount objects into a out.writeObject(a); Read: ArrayList<BankAccount> a = (ArrayList<BankAccount>) in.readObject();

33 Serializable Interface
Objects that are written to an object stream must belong to a class that implements the Serializable interface: class BankAccount implements Serializable { . . . } Serializable interface has no methods. Serialization: Process of saving objects to a stream. Each object is assigned a serial number on the stream. If the same object is saved twice, only serial number is written out the second time. When reading, duplicate serial numbers are restored as references to the same object.

34 section_4/Bank.java This bank contains a collection of bank accounts.
import java.io.Serializable; import java.util.ArrayList; 3 4 5 6 7 8 9 /** This bank contains a collection of bank accounts. */ public class Bank implements Serializable { private ArrayList<BankAccount> accounts;

35 section_4/SerialDemo.java Program Run: Second Program Run:
import java.io.File; import java.io.IOException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; 7 8 9 /** This program demonstrates serialization of a Bank object. Program Run: 1001: 1015: Second Program Run: 1001: 1015:

36 Self Check 21.8 Why is it easier to save an object with an ObjectOutputStream than a RandomAccessFile? Answer: You can save the entire object with a single writeObject call. With a RandomAccessFile, you have to save each instance variable separately.

37 Self Check 21.9 What do you have to do to the Country class from Section 10.1 so that its objects can be saved in an ObjectOutputStream? Answer: Add implements Serializable to the class definition.

38 File and Directory Operations
Path interface provides sophisticated handling of names of files and directories. Obtain Path object get method: Path inputPath = Paths.get("input.txt"); Path dirPath = Paths.get("/home/myname"); Combine paths with the resolve method: Path fullPath = dirPath.resolve(inputPath); // The path /home/myname/input.txt Paths can be: Absolute (starting at the root of the file system). Relative (only meaningful when resolved against some other path). For example: /home/myname is an absolute path. input.txt is a relative path.

39 File and Directory Operations
Convert a relative path into an absolute path with toAbsolutePath method: Path absolutePath = Paths.get("input.txt").toAbsolutePath(); Get containing directory: Path parent = fullPath.getParent(); // The path /home/myname Get file name without containing directory: Path fileName = fullPath.getFileName(); // The path input.txt To get all components of a Path, use an enhanced for loop. Path interface extends the Iterable<Path> interface: for (Path p : fullPath) { Analyze p. }

40 Path objects are not strings.
To convert a Path to a String, use the toString method.

41 Creating and Deleting Files and Directories
Create an empty file or directory with: Files.createFile(path); Files.createDirectory(path); To check whether a path exists: boolean pathExists = Files.exists(path); To check whether existing path is a file or a directory, use Files.isRegularFile or Files.isDirectory. To delete a file or an empty directory: Files.delete(path); Create a temporary file or directory using unique name: Path tempFile = Files.createTempFile(prefix, extension); Path tempDir = Files.createTempDirectory(prefix); Don't need to delete the file or directory when you are done. Operating system will clean temporary files & directories.

42 Useful File Operations
Get size of a file in bytes: long size = Files.size(path); Read entire text file into a list of lines: List<String> lines = Files.readAllLines(path); Read entire binary file into a byte array: byte[] bytes = Files.readAllBytes(path); Write a collection of lines to a file: Files.write(path, lines); Write an array of bytes to a file: Files.write(path, bytes);

43 Useful File Operations
Read a file into a single string: String contents = new String(Files.readAllBytes(path), "UTF-8"); Write a string to a file: Files.write(path, contents.getBytes("UTF-8")); Read a text file as a stream (see Chapter 19): Lines are read lazily. Be careful to use try-with-resources. Example: get the first ten lines containing a given string: String target = " and "; final int MAX_LINES = 10; List<String> result = null; try (Stream<String> lines = Files.lines(path)) { result = lines .filter(s -> s.contains(target)) .limit(MAX_LINES) .collect(Collectors.toList()); } Copy or move a file: Files.copy(fromPath, toPath); Files.move(fromPath, toPath);

44 Visiting Directories Get a List of all files:
try (Stream<Path> entries = Files.list(dirPath)) { List<Path> paths = entries.collect(Collectors.toList()); Process the list paths. } Get a Stream<Path> of all files in a directory using Files.list. Can use filter, map, and collect. try (Stream<Path> entries = Files.list(dirPath)) { Process the stream entries. } Files.list does not visit subdirectories. To descend into subdirectories, use Files.walk instead. Gives descendants in depth-first order.

45 Self Check 21.10 Construct a Path object downloads with the path to the directory on your computer that contains downloaded files. Answer: The details depend on your operating system. On my computer, it is Path downloads = Paths.get("/home/cay/Downloads");

46 Self Check 21.11 Call a method of the Files class to create a subdirectory bigjava in your downloads directory. Answer: Files.createDirectory(downloads.resolve("bigjava"));

47 Self Check 21.12 Given a Path object p for /home/cay/output.txt, how do you get a path to /home/cay/output.bak? Answer: Path q = Paths.get(p.toString().replace(".txt", ".bak")); Or, if you are worried that the directory name of p might contain the string .txt, Path q = p.getParent().resolve( p.getFileName().replace(".txt", ".bak"));

48 Self Check 21.13 How can you make a backup copy of a file with path p before writing to it? Answer: First get a path for the backup file and change the suffix as in the preceding answer or, as is common in Linux, add a ~ to the filename: Path q = Paths.get(p.toString() + "~"); Then copy the file: Files.copy(p, q);

49 Self Check 21.14 What happens in Self Check 13 if the backup file already exists? How can you overcome that problem? Answer: Then the call to copy throws an exception. Delete the file first if it exists: if (Files.exists(q)) { Files.delete(q); } Files.copy(p, q);


Download ppt "Chapter 21 – Advanced Input/Output"

Similar presentations


Ads by Google