Chapter Thirteen

Java Input and Output*

Some of the computing in the chapters to follow is made easier by being able to write output to files, and being able to read from the keyboard or from a file. Even though we will give you the commands needed to do that in those chapters, we will not explain just how they go about doing it. In this optional chapter we do explain some of the theory and details of Java I/O, for those who care to or need to know about them. As we have indicated before, we consider the difficulty of Java’s I/O a major weakness of the language for scientific computing, a weakness that is being overcome as this book goes to press. Part of this difficulty arises from the increased security needed to be able to use Java over the Web, and part from Java being designed more for graphical output than text. Already Java 1.5 has added scanner, a version of scanf, and we suspect that printf will follow shortly [Jgran].

You have seen in Chapter 9, “Getting Started with Java,” that we printed out a line of output with the basic Java command:

System.out.println(“R = “ + r + “, A = “ +A);

Even though this seems rather ungainly for such a simple operation, we advised you to just use it and not worry about its form or meaning. As we get on with more serious computing, it would be nice to have some more control over the input and output (I/O) within our programs. In particular, it is useful to enter input from the keyboard or from a file and to place our output into files that are stored for later use.

In the first part of this chapter we discuss the standard I/O streams of Java and how to use them to read and write files. Rather than give all details of the theory of I/O, we primarily give examples of how these things are done, with little discussion of the various steps that Java must undertake to get them done. In the second part of this chapter we give examples of the use of a freely available package that provides convenient reading and writing of formatted data. That package contains Java versions of the well known C-language printf and scanf commands.

13.1 BASIC INPUT WITH SCANNER

As this book was going to press, Sun announced their latest version of Java, j2se/1.5.0. It contains the simple scanner command that reads input and converts (parses) it into primitive data types and strings, without the user having to deal with the complication of buffers. While its introduction was too late for us to include in our sample codes, in Listing 13.1 we give ScannerIn.java containing examples of its use with various data types.

Listing 13.1 ScannerIn.java

image

13.2 STREAMS: STANDARD OUTPUT, INPUT, AND ERROR

The most basic I/O in Java is that which comes packaged as part of the Java “system.” It consists of

System.in

standard input stream (keyboard)

System.out

standard output stream (monitor screen)

System.err

standard error stream (varies)

Here the word stream represents a one-way path connecting your program and a device, such as a file. You may issue system-level commands that redirect where the input comes from and where the output goes, but unless you do so, the default input is the keyboard and the default output is the screen. To prove the point, when in Listing 13.2:

Table 13.1 Control characters for formatting output.

Control Character

Effect

Control Character

Effect

new line



backspace

return (no line feed)

tab

Listing 13.2 Area2.java

image

we issue the System.out.println command, we actually are using the println method to send a line of data to be printed on the standard output stream System.out. The method is in the out classes that are part of Java’s System.

The original version of Java (1.0) was written so that it transfers data one byte at a time. Java 1.1 and beyond permit I/O using characters as well. Both systems are still part of Java, and commands from each tend to get intermixed. Though you as a programmer are free to go through all the effort of converting your input and output to byte-size chucks, use of the println method does this for you. However, println takes only a single string as its argument, which is why we use the + operator to convert doubles and ints to strings that are then concatenated into a single, long string. Here are a few examples:

13.2.1 Screen Output; Area2.java

For beginning work we usually output to the screen. In Listing 13.2 we have Area2.java, a modified version of our old friend Area. It produces the output:

R = 1.0

C = 6.283185307179586

R = 1.0, A = 3.141592653589793

Survey some new things here. First, how the third println command includes a control character before the symbol. This causes a “new” or blank line to be inserted in the output, in this case, before the symbol R is printed. (The indentation occurs because there is a blank space after the .) Other control characters that you may use to control the format of the output are given in Table 13.1. Another new thing in Area2 is our printing both r and A on the same line:

Table 13.2 String to primitive type conversion methods.

Conversion Method

Converts to

Double.parseDouble(String str)

double

Double.valueOf(String str).doubleValue()

double

Integer.parseInt(String str)

int

Integer.valueOf(String str).integerValue()

int

Long.parseLong(String str)

long

Long.valueOf(String str).longValue()

long

Float.parseFloat(String str)

float

Float.valueOf(String str).floatValue()

float

Boolean.valueOf(String str).booleanValue()

boolean

System.out.println(“ R = “ + r +”, A = “ + A);

We did this by the concatenation of a string + data conversion + string + data conversion. Some care is needed here in keeping track of where the double quotes begin and end, although you may rest assured that Java will tell you when you do not get it quite right!

13.2.2 Keyboard Input, Screen Output

The keyboard is the standard stream for input, much as the screen is the standard stream for output. We may accomplish all the conversions and transfers needed for output with a single command like println, yet an additional step is needed for input, because we must both transfer a stream of bytes into our program and then convert these bytes into the appropriate data type (such as double, int, or string). Java provides the methods to look after the details, but you must tell Java what it is you want done. In fact, there are a number of different methods to accomplish this task, as you shall see in the examples.

Data read into your program enters as a long string. If you want to assign that long string to a string variable, then no conversion is necessary. If you want to convert that string into double, int, or boolean data types, then you may use the type conversion methods indicated in Table 13.2 [Chap 04, Bron 03, Dav 99]. Observe how the first part of the method name is actually the name of the class to which it belongs, while the second part, after the decimal point, is the method’s proper name. So, for example, when we say

Double.parseDouble(String str)

the method name is parseDouble, and it is contained in the class Double. This agrees with our convention that class names are capitalized, while method names are not. The method’s argument is in the parentheses, (String str), with String indicating the data type. In contrast to primitive data types, which we declare with lowercase key words like double, Strings are variable-length objects that we create, and are therefore declared with the capitalized String.

Before we lose you with all the talk, look at ReadStnd.java in Listing 13.3:

Listing 13.3 ReadStnd.java

image

This code uses the standard input stream (keyboard) and produces the output:

Please type in your name

Loren B

Hi Loren B

Please enter r

10

Bye Loren B R = 10.0, A = 314.1592653589793

This example also illustrates a step in the input process known as buffering. As a general rule, you do not want your program (software) to interact directly with an I/O device (hardware), as then you may have your fast program waiting for some slow hardware. On these grounds, the data in the input stream gets placed in a buffer where it accumulates until there is a full line ready for transmission to your program. So it follows that, like a shock absorber on an automobile smoothing out the ride, a buffer in the I/O streams smooths out the data flow. To include a buffer in the program, on line 7 we have the command

BufferedReader b = new BufferedReader(new InputStreamReader(system.in));

This means that the standard java.io package creates BufferedReader objects to buffer the data in the input stream. The method readLine() used on line 10 reads the line in the buffer and returns it to the program as a String. The reading of the data from the input stream is done by the object InputStreamReader (line 7), which is passed to BufferedReader. We see (line 10) that we have read in a string name with the user’s name and stored it as a string. Then (line 12) we read in String rS, which we converted to the double r with the command Double.valueOf(rS).doubleValue(). However, we do not need to convert the string name to a string, as it already is one.

Now in Listing 13.4 we give ReadStnd2.java, a version of this program that still uses the same BufferedReader object but uses the parse conversion of the string rather than the valueOf form:

Listing 13.4 ReadStnd2.java

image

This program produces the output:

Please type in your age 101 Hi at 101 years

Please enter r

1. Done, R = 1.0, A = 3.141592653589793

We see in ReadStnd2.java that Integer.parseInt() is used to convert a String to an int, and Double.parseDouble() is used to convert a String to a double.

13.2.3 Keyboard Input via Command Line: CommandLineIn.java

Recall how the main method is always declared with a statement containing void main(String[] argv). The main method gets called by the Java interpreter when you issue the java command, and since it is a method, it takes arguments (parameter list) and returns values. The word void here means that no argument gets returned to the command that calls main, while String[] argv means that the argument argv is an array (indicated by the []) of the data type String. Although we have not done it yet, you are permitted to pass arguments (data) to the main method from the command line, that is, from the shell command java that you use to run your program. As an example, the program CommandLineIn.java in Listing 13.5 accepts and then uses arguments from the command line. Consequently, if you issue the command:

> java CommandLineIn Manuel 1.0

the string Manuel and the double 1.0 will be transferred to the main program for use, and will produce the output:

Please enter your name & r as command line arguments

1st argument: Manuel, 2nd argument: 1.

How’s life Manuel? radius = 1.0

Done Manuel, A = 3.141592653589793

Here you are free to use any name and number, or any number of arguments, and the program will have that information transferred to it.

Listing 13.5 CommandLineIn.java

image

Look at CommandLineIn.java to see how to create a command-line interpreter in Java. We see first that the main-method declaration on line 4 looks like

the usual one (which declares argv to be an array of strings). Line 6 reminds the user that she should have entered arguments on the command line, which will be useful the next time the program is run. Line 7 prints out the two strings that are fed to the program through the command line. Seeing that the input is always an array of strings, no conversion is necessary if you want to use elements of the array as a string. This is, in fact, what we do on line 7 with the printouts, and on line 9 with the second argument s = argv[1]. However, if you want to use the input string s for numerical computation, then you must convert it to the appropriate data type. This is done on line 10, where we first convert the string s to a double object with the Double.valueOf(s) command, and then convert that object to a static double by appending the .doubleValue() method to the object.

13.2.4 File Input and File Output: AFileIO.java, FT.java

Assume you need to store the output of your program in a file or read data from a file. As a case in point, you may want to store data to be plotted by a graphics program, or you may want to read in the results from an experiment so that you may analyze them. The simplest way to do this is by using command-line redirection from within the shell in which you are running your program:

image

will redirect the standard input stream from the keyboard to the file infile.dat. Likewise,

image

redirects the standard output stream from the screen to the file outfile.dat. Or, for complete redirection, you could put both together:

image

You may also read and write formatted and nonformatted files from within your Java program without any shell commands. Nonformatted files are useful when creating large databases, while formatted files, being simpler to deal with, is all we shall deal with.

Our discussion of the need for buffering when dealing with I/O streams is also true for file I/O. On that account, examine AFileIO.java in Listing 13.6. You see that reading a file also uses the BufferedReader method. Likewise, we also use the println method, but now with a buffer. What is new with file I/O is that we need to create an object that is associated with a physical file on our computer.

Table 13.3 File readers and writers.

Reader

Writer

BufferedReader

PrintWriter

FileReader

FileWriter

BufferedWriter

Listing 13.6 AFileIO.java

image

Take note of how in AFileIO.java, we open the input file NameAndR.dat and associate it with the object b via the logical but not succinct command:

image

We now open output file A.dat and associate it with object q:

image

Here the words in quotes, “NameAndR.dat” and “A.dat” are the names of physical files on our computer, and unless a more complete path is indicated, they are assumed to reside in the directory from which the java command is issued. The variables FileInputStream and FileOutputStream are objects in which large amounts of data may accumulate. If the data come from an input device, they are accumulated one byte at a time and then passed to the InputStreamReader in a large chunk. If the data are to be sent to an output device, it is accumulated in a large chuck from the FileOutputStream and then passed to the file, one byte at a time. Java does the same thing in multiple ways. Other options are in Table 13.3.

Once these admittedly awkward commands are issued, reading and writing files is simply accomplished by modifying the objects b and q. For instance, examine the AFileIO.java code in Listing 13.6. Check out how the declaration of the main method on lines 5–6 includes the throws IOException phrase, as needed when dealing with files. After that, we create an object b (line 11) that represents the input file, and then a second object q (line 19) that represents the output file. After that it is easy to read and write files just by affixing a read or write line method to the object, for example, lines 14 and 20:

String s = b.readLine(); q.println(“r = “ +r);

In Listing 13.7 we present the code FT.java that uses standard Java to read data from a file until it runs out of data (instring is null), and then places those data into an array for processing. The array is then processed and written to another file. The input file contains data of the form:

0.026643

0.017807

0.008962

0.000107

-0.008756 -0.017628 -0.026508 -0.035396

These data are positions y(ti) of a nonlinear oscillator as a function of time t, measured in discrete steps of h. In other words, the data are y(0), y(h), y(2h), , with one y per line, and with each line corresponding to t increasing by h (the actual value of h is not given). The program computes the discrete Fourier transform [CP 05] of these data via:

image

where N is the number of times at which the input signal was measured. The code is given in Listing 13.7. It produces a file with lines of the form:

0

-425.183626 0.0

1

128.80130855519593

964.4441383691654

2

-1.3054384301614006

5.840535198361542

3

31.463783796425304

11.33636196280638

4

12.11948839663997

-0.7004454432124283

5

8.944525602799267

-0.7686320522517022

In §13.5 we give another version of this code, which uses formatted output for an improved listing.

Listing 13.7 FT.java

image

13.3 I/O EXCEPTIONS: FILECATCHTHROW.JAVA

You may have noted that the programs containing file I/O have declared their main methods with a statement of the form:

main (String[] argv) throws IOException

This is required by the Java compiler when dealing with files. Exceptions occur when something goes wrong during the I/O process, such as not finding a file, trying to read past the end of a file, or interrupting the I/O process. In fact, you may get more information of this sort reported back to you by including any of these phrases:

image

after the words throws IOException. As an instance, ReadStnd2 in Listing 13.4 contains the statements:

image

where the added comma is to be noted. In this case, we add in the subclass FileNotFoundException, which you may have noted in some of the examples.

Dealing with I/O exceptions is important, since it prevents the computer from locking if a file cannot be read or written. If, for example, a file is not found, then Java will create an Exception object and pass it along (“throws exception”) to the program that called this main method. This extended declaration creates an object (variable) through which error messages concerning things that can go wrong with your file I/O to be transmitted back to the main method. When you issue the java command to run the main method, you will have the error message delivered to you.

Listing 13.8 FileCatchThrow.java

image

Just how the program deals with (catches) the thrown exception object is beyond the level of this book, although Listing 13.8 does give an example of the try-catch construct below. Beware, the file specification on line 11 is for Unix/Linux. For Windows it would be of the form (note double backslash):

new FileOutputStream(“c:\jan\MyDocs\FileThrowCatch.out”),true);

We see here that while the declaration of the main method on line 4 does not contain any statement about an exception being thrown, in its place we have a try-catch construct on lines 9–11. The statements within the try block are executed, and if they throw an exception, it is caught by the catch statement, which prints out a statement to the effect. To illustrate, this program creates a file in the home directory of user jan. Well, unless you happen to be user jan, an exception should be thrown and you should see the line Could not write to file printed out. If you place your user name in place of jan, then rather than getting an error message, you should get the file FileThrowCatch.out written in your home directory. In summary, if you use files, an appropriate throws IOException statement is required for successful compilation.

Table 13.4 Tag forms for javadoc.

@author Loren Rose

before class

@version 12.3

before class

@parameter sum

before method

@exception <exception name>

before method

@return weight for trap integration

before method

@see <class or method name>

before method

13.4 AUTOMATIC CODE DOCUMENTATION: JAVADOC

In Chapter 14, “Numerical Integration,” we present a program TrapMethods.java that contained multiline comments of the form:

image

Here the comments began with a /**, rather than the standard /*, and ended with the standard /*. As usual, Java ignores the text within a comment field but leaves them in the code listing as an aide in understanding the code. What makes these /**, or doc comments different from the standard ones is that with minimal effort you automatically produce a Web (HTML) page containing these comments, as well as an outline of the formal structure of your entire program.1 For this to work, the comments must appear before the class or method that they describe and contain key words, such as @param.

A sample documentation page, as viewed from a Web browser, is shown in Figure 13.1. This page is named TrapMethods.html (it is on the CD) and is produced by operating on your TrapMethods.java file with the javadoc command:

image

Not visible in the figure are the specific definition fields produced by the @param tags. Other tags are shown in Table 13.4.

image

Figure 13.1 A sample of the automatic code documentation produced by running javadoc on the program TrapMethods.java.

13.5 NONSTANDARD FORMATTED OUTPUT: PRINTF

If you have been trying to make sense of all the ways that Java has to do I/O and all the commands needed to do it, you may be saying to yourself “there must be an easier way.” Well there are actually numerous convenience classes of methods written to improve upon Java I/O. Unfortunately, none of these convenience classes are yet part of the Java standard or even universally accepted and maintained by the Java community.

A particularly attractive and promising package for Java I/O is the Java printf package [Printf]. This package is free for noncommercial use, easy to use, and provides Java versions of the C-language I/O routines fprintf(), printf(), and sprintf(), which are the standard for much programming. We recommend that the interested reader go to its Web site, read over the documentation, browse the 200 examples, and download the package if interested. The I/O commands are listed in Table 13.5. These commands are in the package com.braju.format and in the class Format. Accordingly, to include the needed fprintf methods in your program, you start your program (before any methods) with the line

import com.braju.format.*;

Then, just replace System.out.println with Format.printf (since the commands are in the Format class, you affix the class name):

Table 13.5 Nonstandard formatted I/O commands (static methods).

Command

Purpose

fprintf

format and output text to named output stream

printf

format and output text to the standard output

fscanf

read formatted text from named input stream

scanf

read formatted text from standard input stream

Table 13.6 Components of the printf/scanf formatted I/O commands.

Component

Purpose

Parameters p

object used to store input or output stream

NumberVariable

object containing single number from input

IntegerVariable

object containing specific NumberVariable

DoubleVariable

object containing specific NumberVariable

CharacterVariable

object containing specific NumberVariable

StringVariable

object containing specific NumberVariable

intValue()

method to extract integer’s value from a NumberVariable

doubleValue()

method to extract double’s value from a NumberVariable

charValue()

method to extract characters from a NumberVariable

Format.printf(“Hello universe! ”);

This prints the string Hellow universe! and skips a line.

Using the printf/scanf command involves the components shown in Table 13.6. Beware, standard Java contains components, such as

Double.valueOf(str).doubleValue(), Integer.valueOf(str).integerValue()

that have similar names but are not designed to work with the printf objects. Of course it is the formatting of output that makes the printf package so useful, and it handles many types of output. The basic idea is that to output some data, you have printf convert one of Java’s primitive data types into the format you prefer. You denote this by placing the conversion symbol % in front of a letter indicating the format you want. As an example, for Al being a String:

image

Inspect here how %s outputs a string, while %d outputs an integer.2 The outputs are not done directly, but instead get added to a Parameters object, which may accumulate other output as well. By way of example, consider the command:

Table 13.7 Sample formatted output for floating-point numbers.

Type

Java Statement

Output

floating

Format.printf(“a=%6.2f, b=%.2f”, p.add(1.456).add(1.456));

a= 1.46, b=1.5

fixed

Format.printf(“d=%+010f” p.add(d));

d=-1234.56789

exponent

Format.printf(“d=%12.1e” p.add(d));

d= -1.2e+03

general

Format.printf(“d=%+12.4G” p.add(d));

d= -1235

left general

Format.printf(“d=%-12.4G” p.add(d));

d= -1235

Format.printf(“3s = %d yrs”, p.add(Russ).add(30));

The first part of the command says to format for output a String (%s) and then a decimal integer (%d). The second part of the command says to take the converted form of each variable and add each to the object p. The object p, which you may name most anything you want, is a special type of object that holds the parameter list produced by the printf command. It is called a Parameters object and is created by the default (null) constructor, or with an argument (here a string):

In our example, the Parameters object has the string Russ added to it, and then the decimal integer 30 added. More calls to the get method will continue to add more output to the Parameters object. If you prefer, you may save some space— but this makes commands harder follow and debug—by creating the Parameters object within the printf command:

Format.printf (“M = %15.4e, v = %15.4g”, new Parameters(m).add(v)) ;

Now let us look at the commands for fixed-decimal-point floating-point numbers, floating-point numbers in scientific notation, and general floating-point numbers. You use these to control both the total width (number of spaces) used for the output as well as the number of digits that are given to the right of the decimal point. For instance, %.2f produces a fixed-decimal-point number with two digits after the decimal point, while %6.2f uses a total of six spaces, one for the decimal point, two after the decimal point, and one before it (including the sign). If the value for the width is negative, the output is left justified. Some specific examples are given in Table 13.7.

Listing 13.9 FormatFT.java

image

In Listing 13.9 we give the complete code FormatFT.java. It illustrates how to use standard Java to read data from a file until you run out of data (read string is null) and then places those data into an array for processing. The array is then processed and Format is used for output. The file is the same series of positions of an oscillator used in §13.2.4, and the program computes the same Fourier transform. This produces the formatted output:

image

13.5.1 Formatting Input with Java scanf

Reading in data involves a number of steps. The data are stored on a device in some type of coded format, and so you must first have the computer parse or scan the data so that there is a copy of it in the computer’s RAM. You then must break up the input stream into individual items and then convert those items to numerical values that are then assigned to variables in your program. The printf package we have been discussing also includes a scanf component that reads in data, much like the analogous command in the C language.

To see how printf/scanf works, we give here an annotated example. In trying to make sense of this, it is helpful to remember that the variables representing objects, such as p and num, just point to a location in memory. To extract the value(s) associated with the object, a method must be applied to it (and that is done with the dot operation that affixes the method to the object):

image

In Listing 13.10 we give the complete code F2C.java based on an example taken from the Format package. This illustrates how to read from the standard input stream both a double and a character, and then how to process both of them. Some typical output is:

image

Listing 13.10 F2C.java

image

1  Some basics of the World Wide Web are described in Chapter 21, “Web Computing.”

2  The use of d for an integer indicates that this is a decimal integer, in contrast to an octal integer. Therefore,

%i  also outputs a decimal integer, although this is not true in standard C printf. If you want an octal integer, that is converted with %o.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.68.14