# Help me to understand this code



## virkjay (Nov 1, 2007)

Assignment :- Write a program that asks the user for a file name and prints the number of characters, words and lines in that file. Then the programe asks for the name of the next file. When the user enters a file that doesn't exit ( such as the empty string), the program exits.

import java.io.FileReader;
import java.io.IOException;

/**
A class to count the number characters, words, and lines in a file.
*/
public class FileCounter
{
/**
Construct a FileCounter object.
*/
public FileCounter() 
{
chars = 0;
words = 0;
lines = 0; 
}

/**
Read the input file and count the number.
of words, characters, and lines.
@param file the file to count
*/
public void read(FileReader reader) throws IOException
{
boolean space = true;
boolean more = true;

while (more)
{ 
int ic = reader.read();
if (ic == -1) more = false;
else
{ 
chars++;
char c = (char) ic;
if (c == '\n') 
{ 
lines++; 
space = true; 
}
else if (c == ' ' || c == '\r') 
space = true;
else
{ 
if (space)
words++;
space = false;
}
}
lines++;
}
}

/**
Gets the number of characters in a file.
@return the number of characters
*/
public int getCharacterCount() 
{
return chars;
}

/**
Gets the number of words in a file.
@return the number of words
*/ 
public int getWordCount()
{
return words;
}

/**
Gets the number of lines in a file.
@return the number of lines
*/ 
public int getLineCount() 
{
return lines;
}

private int chars;
private int words;
private int lines;
}

Please help me to understand why we are using variable boolean space in method read()
and then assigning value true to space few time in that method.

Tester programe is given below

import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

/**
This class tests the FileCounter class.
*/
public class ExP16_1
{
public static void main(String[] args)
{ 
Scanner in = new Scanner(System.in);
String input = "";

try
{ 
boolean done = false;
while (!done)
{
System.out.print("Filename (-1 to end): ");
input = in.next();
if (input.equals("-1")) 
done = true;
else
{
FileReader fin = new FileReader(input);
FileCounter fileCounter = new FileCounter();
fileCounter.read(fin); 
System.out.println(
fileCounter.getCharacterCount() + " chars, " 
+ fileCounter.getWordCount() + " words, " 
+ fileCounter.getLineCount() + " lines");
fin.close();
}
}
}
catch (IOException e)
{ 
e.printStackTrace();
}
}
}

Thanks in advance. Please help me.


----------



## Chicon (Jul 29, 2004)

Hi virkjay,

I've had a try of your coding and I have some remarks.

1) There's a mistake in the lines counting.

2) It is not a good idea to pass an object like *FileReader* as parameter of an external class method :
- it increases the level of dependency between 2 classes; *FileReader* is more an _action_ class which only goal is to read a text file
- as *FileReader* throws exceptions, the programmer has also to treat the exceptions of the same object in two different classes

Instead of passing a *FileReader*, you may pass a *File* as parameter. *File* may be considered as an _info_ class.
It provides a lot of useful informations about files, directories.
Example :

```
[SIZE=2]
// in the [B]main[/B] method of your [B]ExP16_1[/B] class
FileCounter fc = new FileCounter()
File file = new File(input); // [I]input[/I] is the string that contains the file/directory path
if (file.exits()) {
    if (file.isFile() {
        fc.read(file);
    }
}

// in the [B]read[/B] method of your [B]FileCounter[/B] class
public void read(File file) {
    try {
        FileReader frdr = new FileReader(file);
        ....
        frdr.close();
    } catch(FileNotFoundException fnf) {
        System.out.println(fnf.getMessage());
    } catch(IOException io) {
        System.out.println(io.getMessage());
    }
}
[/SIZE]
```
3) When you use a *FileReader*, it is also recommanded to use its little bro' : *BufferedReader*.
It will prevent the whole content of your file being entirely loaded into the memory.
If your input file has 500 MB of size, you will have to increase the memory heap size of your JVM if you don't use *BufferedReader*.
Here's the proper and secure way of reading a text file in Java whatever the size of the file :

```
[SIZE=2]
public void read(File file) {
    String ln;
    try {
        FileReader frdr = new FileReader(file);
        BufferedReader brdr = new BufferedReader(frdr);
        ln = brdr.readLine();
        while (ln != null) {
            ...
            ...
            ...
            ln = brdr.readLine();
        }
        brdr.close();
        frdr.close();
    } catch(FileNotFoundException fnf) {
        System.out.println(fnf.getMessage());
    } catch(IOException io) {
        System.out.println(io.getMessage());
    }
}
[/SIZE]
```
4)In Java, primitives like *char*, *int*, ... each have a corresponding _wrapper_ class.
For *char*, the _wrapper_ class is *Character* and it provides a lot of useful methods.
And one of them is the *isWhitespace* method : it checks if the character is a space, a tab, a paragraph separator, a line separator, ...
It also prevents the user of writing expressions like :

```
[SIZE=2]if ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n')) ...[/SIZE]
```
Example of usage :

```
[SIZE=2]
char c = [I]some_character[/I];
if (Character.isWhitespace(c)) {
    System.out.println("c is blanco");
}[/SIZE]
```


----------

