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)
Download
Report
Transcript 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 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