Chapter 3 – Implementing Classes

Download Report

Transcript Chapter 3 – Implementing Classes

Chapter 16 – Files and
Streams
Announcements

Only responsible for 16.1,16.3


Other sections “encouraged”
Responsible for online supplements for
Exceptions and File I/O (see syllabus)
Chapter Goals




To be able to read and write text files
To become familiar with the concepts of text
and binary formats
To learn about encryption
To understand when to use sequential and
random file access
keyboard
standard
input stream
CPU
standard
output
stream
monitor
terminal
console
What does information
travel across?
Streams
MEM
HDD
keyboard
standard
input stream
CPU
monitor
terminal
console
standard
output
stream
What does information
travel across?
Streams
file
input
stream
LOAD
READ
MEM
HDD
files
file
output
stream
SAVE
WRITE
16.1 Reading and Writing Text Files

Text files – files containing plain text


Created with editors such as notepad, etc.
Simplest way to learn it so extend our use of
Scanner


Associate with files instead of System.in
All input classes, except Scanner, are in java.io

import java.io.*;
Review: Scanner


Two ways to use scanner  two constructors
First constructors takes an object of type
java.io.InputStream – stores information
about the connection between an input device
and the computer or program


Example: System.in
Recall – only associate one instance of
with System.in in your program
Scanner
Review: Numerical Input

First way:
 Use nextInt()
int number = scanner.nextInt();

Second way:
 Use nextLine(), Integer.parseInt()
String input = scanner.nextLine();
int number = Integer.parseInt(input);
What’s the difference?


Exceptions

nextInt() throws InputMismatchException

parseInt() throws NumberFormatException
Optimal use

nextInt() when multiple information on one line

nextLine() + parseInt() when one number
per line
Reading

To read from a disk file, construct a
FileReader

Then, use the FileReader to construct a
Scanner object
FileReader reader = new FileReader("input.txt");
Scanner in = new Scanner(reader);
Alternative

Use File instead of

FileReader
Has an exists( ) method we can call to avoid
FileNotFoundException
File file = new File ("input.txt");
Scanner in;
if(file.exists()){
in = new Scanner(file);
} else {
//ask for another file
}
What does this do?

Allows us to use methods we already know


next, nextLine, nextInt, etc.
Reads the information from the file instead of
console
File Class

java.io.File
 associated with actual file on hard drive
 used to check file's status

Constructors


File(<full path>),
File(<path>, <filename>)
Predicate Methods



exists()
canRead(), canWrite()
isFile(), isDirectory()
Writing To File

We will use a PrintWriter object to write to a
file
What if file already exists?  Empty file (delete
whatever is there)
 Doesn’t exist?  Create empty file with that name


How do we use a PrintWriter object?

Have we already seen one? Almost.
PrintWriter

The out field of System is a PrintStream object associated
with the console. PrintWriter is a similar class optimized
for writing characters.


We will associate our PrintWriter with a file now
Can use either a filename or File object
PrintWriter fileOut = new PrintWriter("output.txt");
fileOut.println(29.95);
fileOut.println(new Rectangle(5, 10, 15, 25));
fileOut.println("Hello, World!");

This will print the exact same information as with System.out
(except to a file “output.txt”)!
Closing File

Only difference is that we have to close the file
stream when we are done writing

If we do not, some output may not get written

At the end of output, call close()
fileOut.close();
Why?

Short answer
When you call print( ) and/or println( ), the output is
actually written to buffer. When you close or flush
the output, the buffer is written to the file
 The slowest part of the computer is hard drive
operations – much more efficient to write once
instead of writing repeated times

File name

When determining a file name, default is to place in
the same directory as your .class files

If we want to define other place, use absolute path
(e.g. C:\My Documents)
in
= new FileReader(“C:\\homework\\input.dat”);
Getting it all to work

Remember:
Have to import from java.io
 I/O requires us to catch checked exceptions



java.io.IOException
How long do we read from the file?
Until the end. (duh)
 Use the hasNext( ), hasNextLine( ) and hasNextInt( )
predicate methods from Scanner.


Otherwise you risk creating a NoSuchElementException
Java Input Review
CONSOLE:
Scanner stdin = new Scanner( System.in );
FILE:
Scanner inFile = new
Scanner( new File ( srcFileName ) );
import
import
import
import
java.io.FileReader;
java.io.IOException;
java.io.PrintWriter;
java.util.Scanner;
public class LineNumberer {
public static void main(String[] args){
Scanner console = new Scanner(System.in);
System.out.print(“Enter input file: ");
String inFile = console.next();
System.out.print(“Enter output file: ");
String outFile = console.next();
try{
File reader = new File(inFile);
Scanner in = new Scanner(reader);
PrintWriter out = new PrintWriter(outputFileName);
int lineNumber = 1;
while (in.hasNextLine()){
String line = in.nextLine();
out.println("/* " + lineNumber + " */ " + line);
lineNumber++;
}
out.close();
} catch (IOException exception){
System.out.println("Error processing file: "
+ exception.getMessage());
}
}
}
Common Error

You can run into problems using nextLine( ) in
conjunction with nextInt( ) from the Scanner
class.
77
hello
In order to read this file
 You typed this code, but got this output

int I = input.nextInt();
String s = input.nextLine();
System.out.println(i+”,”+s);

What went wrong?
77,
Buffering gone bad



To Java, the file is a long
buffer of characters
nextInt removes the
characters corresponding to a
number, and that’s all.
nextLine looks for the next
newline character (‘\n’), and
returns everything before the
first one it finds, even if that
String is empty!
7 7 \n h e
l
\n h e
o \n …
l
l
l
o \n
l
…
i = 77
h e
s = “”
l
…
What to do?

Avoid using nextInt( ) and nextLine( ) in
combination
Always use nextLine( ) and convert to integers using
Integer.parseInt( )
 Use nextInt( ) in conjunction with next( ), which will
skip over newlines to find the next non-whitespace
string


Check to see if Strings from nextLine( ) have
length 0, and if so, call it again.
16.3 An Encryption Program

Demonstration: Use encryption to show file
techniques

File encryption
To scramble a file so that it is readable only to those
who know the encryption method and secret
keyword
 (Big area of CS in terms of commercial applications
– biometrics, e-commerce, etc.)

Caesar Cipher


Encryption key – the function to change the value
Simple key – shift each letter over by 1 to 25 characters


If key = 3, A  D B  E etc.
Decrypt = reverse the encryption

Here we just subtract the key value
Caesar Cipher for alphabetic characters
public void encrypt (Scanner in, PrintWriter out, int key) {
while (in.hasNextLine()) {
String line = in.nextLine();
String outLine = “”;
for (int i=0; i<line.length; i++) {
char c = line.charAt(i);
if (c >= ‘a’ && c <= ‘z’)
c = (char)((c – ‘a’ + key) % 26 + ‘a’);
else if (c >= ‘A’ && c <= ‘Z’)
c = (char)((c – ‘A’ + key) % 26 + ‘A’);
outLine += c;
}
out.println(outLine);
}
}
"Meet me at the secret place." key=5 => "Rjjy rj fy ymj xjhwjy uqfhj."
Modifications of Output

Two constraints so far:
Files are overwritten
 Output is buffered and not written immediately



We have options to get around this if we need
to
More on that after this…
Tokenizing

Often several text values are in a single line in a
file to be compact
“25 38 36 34 29 60 59”

Line must be broken into parts (i.e. tokens)
“25”
“38”
“36”

Tokens then can be parsed as needed
“25” can be turned into the integer 25
Why

Inputting each value on a new line makes the file
very long

May want a file of customer info – name, age,
phone number all on one line

File usually separate each piece of info with a
delimiter – any special character designating a
new piece of data (space in previous example)
Tokenizing in Java

Use a method of the String class called split




Parameters: delimiting rules
Returns: An array of tokens
We need to determine what delimiters are needed for
each line.
Put them in a string that looks like this:



“[<delimeters>]+”
“[,]+”
“[ \n\t]+”
String Tokenizing in Java
Scanner stdin = new Scanner(System.in);
System.out.print("Enter a line with commaseparated integers(no space): " );
String input = stdin.nextLine();
String[] st = input.split(“[,]+”);
for ( int i=0; i<st.length; i++ )
{
int n = Integer.parseInt(st[i]);
System.out.println(n);
}
What if I want to read this file?
Class 1:8:10:7:6:5
Class 2:4:4:5:10:8:8:8
Class 3:6:7:9:10:7:5
Class 4:9:9:8:7:8
Class 5:9:10:9:3
Write a program to print out the average of the scores for
each class
File gradeFile = new File(“scores.txt”);
if(gradeFile.exists()) {
Scanner inFile = new Scanner(gradeFile);
while( inFile.hasNextLine() ) {
String line = inFile.nextLine();
String[] st = line.split(“[:]+");
System.out.print(st[0] + “’s”);
double sum = 0;
for (int n=1; n<st.length; n++)
sum += Integer.parseInt(st[n]);
System.our.println(" average is "+ sum/(st.length-1));
}
inFile.close();
}
Modifications of Output

Two constraints so far:
Files are overwritten
 Output is buffered and not written immediately


But what if we want more control?
File Class

java.io.FileWriter
 Associated
with File object
 Connects an output stream to write bytes of info

Constructors


FileWriter( <Filename>, <boolean> );
 true to append data, false to overwrite all of file
This will overwrite an existing file

To avoid, create File object and see if
exists()
is true
Java File Output

PrintWriter
 composed from several objects false: overwrite
true: appends
PrintWriter out =
new PrintWriter(
new FileWriter( dstFileName, false ), true );


throws FileNotFoundException
Methods
true: autoflush
false: no autoflush

print(), println(): buffers data to write

flush(): sends buffered output to destination

close(): flushes and closes stream
Java File Output
// Append to an existing file
PrintWriter outFile1 =
new PrintWriter(
new FileWriter(dstFileName,true),false);
// Autoflush on println
PrintWriter outFile2 =
new PrintWriter(
new FileWriter(dstFileName,false),true);
outFile1.println( “appended w/out flush” );
outFile2.println( “overwrite with flush” );
to flush or not to flush

Advantage to flush:


Disadvantage


Safer – guaranteed that all of our data will write to the file
Less efficient – writing to file takes up time, more efficient to
flush once (on close)
Can call flush( ) on a PrintWriter object created with
just a filename at any time to force the buffer to disk
Other Ways to Read/Write Files

Binary files (InputStream/OutputStream)




Storing readable text is rather inefficient (2 bytes/character, but
we tend to use less than 100 letters)
Images, music, class files use 0’s and 1’s directly
Can read and write these files, but we typically must work byte
by byte
Random access (RandomAccessFile)


What if we don’t want to read from the beginning to the end?
We have a “cursor” in the file, and can “seek” around to
different points in any order, overwriting what was there before