19-ch06-2-linebased
Download
Report
Transcript 19-ch06-2-linebased
Building Java Programs
Chapter 6: File Processing
Lecture 6-2: Advanced file input
reading: 6.3 - 6.5
self-check: #7-11
exercises: #1-4, 8-11
Copyright 2009 by Pearson Education
Hours question
Given a file hours.txt with the following contents:
123 Susan 12.5 8.1 7.6 3.2
456 Brad 4.0 11.6 6.5 2.7 12
789 Jenn 8.0 8.0 8.0 8.0 7.5
Consider the task of computing hours worked by each
person:
Susan (ID#123) worked 31.4 hours (7.85 hours/day)
Brad (ID#456) worked 36.8 hours (7.36 hours/day)
Jenn (ID#789) worked 39.5 hours (7.9 hours/day)
Can we produce this data token by token?
Copyright 2009 by Pearson Education
2
Hours program strategy
123 Susan 12.5 8.1 7.6 3.2
456 Brad 4.0 11.6 6.5 2.7 12
789 Jenn 8.0 8.0 8.0 8.0 7.5
We want to process the tokens, but we also care about
the line breaks (they mark the end of a person's data).
A better solution:
First, break the overall input into lines.
Then break each line into tokens.
What if you tried it token by token first?
Copyright 2009 by Pearson Education
3
Hours answer (flawed)
import java.io.*;
import java.util.*;
// for File
// for Scanner
public class HoursWorked {
// a non-working solution
public static void main(String[] args)
throws FileNotFoundException {
Scanner input = new Scanner(new File("hours.txt"));
while (input.hasNext()) {
// process one person
int id = input.nextInt();
String name = input.next();
double totalHours = 0.0;
int days = 0;
while (input.hasNextDouble()) {
totalHours += input.nextDouble();
days++;
}
System.out.println(name + " (ID#" + id +
") worked " + totalHours + " hours (" +
(totalHours / days) + " hours/day)");
}
}
}
Copyright 2009 by Pearson Education
4
Flawed output
Susan (ID#123) worked 487.4 hours (97.48 hours/day)
Exception in thread "main"
java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:840)
at java.util.Scanner.next(Scanner.java:1461)
at java.util.Scanner.nextInt(Scanner.java:2091)
at HoursWorked.main(HoursBad.java:9)
The inner while loop is grabbing the next person's ID.
Hard to tell it where to stop!
The line breaks indicate the end of the data
Much easier and more natural to process by asking for a line of
input at a time, then only concentrating on that line
Copyright 2009 by Pearson Education
5
Tokenizing lines of a file
A Scanner object can also be used to process a String
Scanner lineScan = new Scanner(string);
A String Scanner can tokenize each line of a file.
Scanner input = new Scanner(new File("file name"));
while (input.hasNextLine()) {
String line = input.nextLine();
Scanner lineScan = new Scanner(line);
process the contents of this line...
}
Copyright 2009 by Pearson Education
6
Hours program solution
// Processes an employee input file and outputs each employee's hours data.
import java.io.*;
// for File
import java.util.*; // for Scanner
public class Hours {
public static void main(String[] args) throws FileNotFoundException {
Scanner input = new Scanner(new File("hours.txt"));
while (input.hasNextLine()) {
String line = input.nextLine();
Scanner lineScan = new Scanner(line);
int id = lineScan.nextInt();
// e.g. 456
String name = lineScan.next();
// e.g. "Brad"
double sum = 0.0;
int count = 0;
while (lineScan.hasNextDouble()) {
sum = sum + lineScan.nextDouble();
count++;
}
double average = sum / count;
System.out.println(name + " (ID#" + id + ") worked " +
sum + " hours (" + average + " hours/day)");
}
}
}
Copyright 2009 by Pearson Education
7
File Processing Summary
Token-based file processing:
Breaks up entire file into tokens to process data
Scanner input = new Scanner(new File("midterm.txt"));
while(input.hasNext()) {
... (use methods from input to process file)
}
Line-based file processing:
Breaks up file into lines to process data
Scanner input = new Scanner(new File("hours.txt"));
while(input.hasNextLine()) {
String line = input.nextLine();
Scanner lineScan = new Scanner(line);
... (use methods from lineScan to process file)
}
Copyright 2009 by Pearson Education
8
Confusion w/ nextLine
Using nextLine in conjunction with the token-based
methods on the same Scanner can cause odd results.
23
Joe
3.14
"Hello world"
45.2
19
You'd think you could read 23 and 3.14 with nextInt and
nextDouble, then read Joe "Hello world" with
nextLine .
System.out.println(input.nextInt());
System.out.println(input.nextDouble());
System.out.println(input.nextLine());
// 23
// 3.14
//
But the nextLine call produces no output! Why?
Copyright 2009 by Pearson Education
9
Mixing lines and tokens
Don't read both tokens and lines from the same
Scanner:
23
Joe
3.14
"Hello world"
45.2
19
input.nextInt()
23\t3.14\nJoe\t"Hello world"\n\t\t45.2
^
input.nextDouble()
23\t3.14\nJoe\t"Hello world"\n\t\t45.2
^
input.nextLine()
23\t3.14\nJoe\t"Hello world"\n\t\t45.2
^
// 23
19\n
// 3.14
19\n
// "" (empty!)
19\n
input.nextLine()
// "Joe\t\"Hello world\""
23\t3.14\nJoe\t"Hello world"\n\t\t45.2 19\n
^
Copyright 2009 by Pearson Education
10
Line-and-token example
Scanner console = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = console.nextInt();
System.out.print("Now enter your name: ");
String name = console.nextLine();
System.out.println(name + " is " + age + " years old.");
Log of execution (user input underlined):
Enter your age: 12
Now enter your name: Sideshow Bob
is 12 years old.
Why?
User's overall input:
After nextInt():
After nextLine():
Copyright 2009 by Pearson Education
12\nSideshow Bob
12\nSideshow Bob
^
12\nSideshow Bob
^
11
Array traversals,
text processing
reading: 7.1, 4.4
self-check: Ch. 7 #8, Ch. 4 #19-23
Copyright 2009 by Pearson Education
Text processing
text processing: Examining, editing, formatting text.
Often involves for loops to break up and examine a String
Examples:
Count the number of times 's' occurs in a file
Find which letter is most common in a file
Count A, C, T and Gs in Strings representing DNA strands
Copyright 2009 by Pearson Education
13
Strings as arrays
Strings are represented internally as arrays.
Each character is stored as a value of primitive type char.
Strings use 0-based indexes, like arrays.
We can write algorithms to traverse Strings.
Example:
String str = "Mr. E.";
index
0
1
2
3
4
5
value
'M'
'r'
'.'
' '
'E'
'.'
Copyright 2009 by Pearson Education
14
Recall: type char
char: A primitive type representing a single character.
Values are surrounded with apostrophes: 'a' or '4' or '\n'
Access a string's characters with its charAt method.
String word = console.next();
char firstLetter = word.charAt(0);
if (firstLetter == 'c') {
System.out.println("That's good enough for me!");
}
Copyright 2009 by Pearson Education
15
String traversals
traversal: An examination of each element of an array.
for (int i = 0; i < array.length; i++) {
do something with array[i];
}
Use for loops to examine each character.
for (int i = 0; i < string.length(); i++) {
do something with string.charAt(i);
}
Copyright 2009 by Pearson Education
16
Section attendance problem
Consider an input file of course attendance data:
111111101011111101001110110110110001110010100
111011111010100110101110101010101110101101010
110101011011011011110110101011010111011010101
week1 week2 week3 week4 week5 week6 week7 week8 week9
11111 11010 11111 10100 11101 10110 11000 11100 10100
week2
student1 student2 student3 student4 student5
1
1
0
1
0
Each line represents a section (5 students, 9 weeks).
1 means the student attended; 0 means absent.
Copyright 2009 by Pearson Education
17
Section attendance problem
Write a program that reads the preceding section data file
and produces the following output:
Section #1:
Sections attended: [9, 6, 7, 4, 3]
Student scores: [20, 18, 20, 12, 9]
Student grades: [100.0, 90.0, 100.0, 60.0, 45.0]
Section #2:
Sections attended: [6, 7, 5, 6, 4]
Student scores: [18, 20, 15, 18, 12]
Student grades: [90.0, 100.0, 75.0, 90.0, 60.0]
Section #3:
Sections attended: [5, 6, 5, 7, 6]
Student scores: [15, 18, 15, 20, 18]
Student grades: [75.0, 90.0, 75.0, 100.0, 90.0]
Copyright 2009 by Pearson Education
18
Data transformations
In this problem we go from 0s and 1s to student grades
This is called transforming the data.
Often each transformation is stored in its own array.
We must map between the data and array indexes.
Examples:
by position
(store the i th value we read at index i )
tally
(if input value is i, store it at array index i )
explicit mapping (count 'M' at index 0, count 'O' at index 1)
Copyright 2009 by Pearson Education
19
Section attendance answer
// This program reads a file representing which students attended
// which discussion sections and produces output of the students'
// section attendance and scores.
import java.io.*;
import java.util.*;
public class Sections {
public static void main(String[] args) throws FileNotFoundException {
Scanner input = new Scanner(new File("sections.txt"));
while (input.hasNextLine()) {
// process one section
String line = input.nextLine();
int[] attended = countAttended(line);
int[] points = computePoints(attended);
double[] grades = computeGrades(points);
results(attended, points, grades);
}
}
// Produces all output about a particular section.
public static void results(int[] attended, int[] points, double[] grades) {
System.out.println("Sections attended: " + Arrays.toString(attended));
System.out.println("Sections scores: " + Arrays.toString(points));
System.out.println("Sections grades: " + Arrays.toString(grades));
System.out.println();
}
...
Copyright 2009 by Pearson Education
20
Section attendance answer 2
}
...
// Counts the sections attended by each student for a particular section.
public static int[] countAttended(String line) {
int[] attended = new int[5];
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
// c == '1' or c == '0'
if (c == '1') {
// student attended their section
attended[i % 5]++;
}
}
return attended;
}
// Computes the points earned for each student for a particular section.
public static int[] computePoints(int[] attended) {
int[] points = new int[5];
for (int i = 0; i < attended.length; i++) {
points[i] = Math.min(20, 3 * attended[i]);
}
return points;
}
// Computes the percentage for each student for a particular section.
public static double[] computeGrades(int[] points) {
double[] grades = new double[5];
for (int i = 0; i < points.length; i++) {
grades[i] = 100.0 * points[i] / 20.0;
}
return grades;
}
Copyright 2009 by Pearson Education
21
File input/output
reading: 6.4 - 6.5
Copyright 2009 by Pearson Education
22
Prompting for a file name
We can ask the user to tell us the file to read.
The file name might have spaces: use nextLine()
// prompt for the file name
Scanner console = new Scanner(System.in);
System.out.print("Type a file name to use: ");
String filename = console.nextLine();
Scanner input = new Scanner(new File(filename));
What if the user types a file name that does not exist?
Copyright 2009 by Pearson Education
23
Fixing file-not-found issues
File objects have an exists method we can use:
Scanner console = new Scanner(System.in);
System.out.print("Type a file name to use: ");
String filename = console.nextLine();
File file = new File(filename);
while (!file.exists()) {
System.out.print("File not found! Try again: ");
String filename = console.nextLine();
file = new File(filename);
}
Scanner input = new Scanner(file); // open the file
Output:
Type a file name to use: hourz.text
File not found! Try again: h0urz.txt
File not found! Try again: hours.txt
Copyright 2009 by Pearson Education
24
Output to files
PrintStream: An object in the java.io package that
lets you print output to a destination such as a file.
System.out is also a PrintStream.
Any methods you have used on System.out
(such as print, println) will work on every PrintStream.
Do not open a file for reading (Scanner) and writing
(PrintStream) at the same time.
You could overwrite your input file by accident!
The result can be an empty file (size 0 bytes).
Copyright 2009 by Pearson Education
25
Printing to files, example
Printing into an output file, general syntax:
PrintStream name =
new PrintStream(new File("file name"));
...
If the given file does not exist, it is created.
If the given file already exists, it is overwritten.
PrintStream output = new PrintStream(new File("output.txt"));
output.println("Hello, file!");
output.println("This is a second line of output.");
Can use similar ideas about prompting for file names here.
Copyright 2009 by Pearson Education
26
PrintStream question
Modify our previous Sections program to use a
PrintStream to output to the file section_output.txt.
Section #1:
Sections attended: [9, 6, 7, 4, 3]
Student scores: [20, 18, 20, 12, 9]
Student grades: [100.0, 90.0, 100.0, 60.0, 45.0]
Section #2:
Sections attended: [6, 7, 5, 6, 4]
Student scores: [18, 20, 15, 18, 12]
Student grades: [90.0, 100.0, 75.0, 90.0, 60.0]
Section #3:
Sections attended: [5, 6, 5, 7, 6]
Student scores: [15, 18, 15, 20, 18]
Student grades: [75.0, 90.0, 75.0, 100.0, 90.0]
Copyright 2009 by Pearson Education
27
PrintStream answer
// Section attendance
// This version uses a PrintStream for output.
import java.io.*;
import java.util.*;
public class Sections {
public static void main(String[] args) throws FileNotFoundException {
Scanner input = new Scanner(new File("sections.txt"));
PrintStream out = new PrintStream(new File("section_output.txt"));
while (input.hasNextLine()) {
// process one section
String line = input.nextLine();
int[] attended = countAttended(line);
int[] points = computePoints(attended);
double[] grades = computeGrades(points);
results(attended, points, grades, out);
}
}
// Produces all output about a particular section.
public static void results(int[] attended, int[] points,
double[] grades, PrintStream out) {
out.println("Sections attended: " + Arrays.toString(attended));
out.println("Sections scores: " + Arrays.toString(points));
out.println("Sections grades: " + Arrays.toString(grades));
out.println();
}
...
Copyright 2009 by Pearson Education
28