The ability of the computer to store alphanumeric data, graphic images, and so on in files, and its ability to retrieve the contents has revolutionized applications in almost all aspects of life. Therefore, life without files is unimaginable.
Even the programs which we write are stored in files. We write our programs in .java
file. It is a text file. We compile our program and create .class
file. It is a bytecode file. A file is nothing but a sequential collection of bytes stored with a name.
In Windows OS, file names have optional extension. It helps in identifying the nature of contents of the file. A .class
extension tells us that this is a bytecode file. A .wav
extension tells us that the file contains sound.
In this chapter, we will explain how to perform reading and writing operations on files on a disk.
When we work on a computer, data and programs are stored in RAM, which is a volatile memory device. When we switch off the power, the data as well as the program present in it vanishes. When we restart the computer, we may wish to run the same program again. But it is not present in the memory. Therefore, we require a non-volatile memory. It stores our programs (and data too) even when the power is switched off. In computers, floppies, hard disks, and CDs form the secondary memory. The data and programs are stored in it in the form of a file. Thus, the study of files becomes very important.
Let us start our study of file classification with a few questions and answers.
Short Questions and Answers
Q. What are the two basic types of files?
A. Files can be classified as either text files or binary files.
Q. How does the internal construction of binary and text files differ?
A. Text files are those which contain normal ASCII text characters (printable). These files are line oriented. An end of line can be represented by new-line character. In DOS, a new line is signified by two characters, LF and FF (ASCII values 10 and 13). The number of characters in a line is not fixed.
Binary files are files of bytes. There is no concept of line. Binary file is a plain sequential collection of (data) bytes.
Q. What are the advantages of text file?
A. They are many:
Q. What are the advantages of binary files?
A. There are two main advantages:
Their size is smaller than corresponding text files.
The speed at which programs can read data from them is very high (as compared to text files).
Q. What is the disadvantage of binary files?
A. They cannot be easily read or written by ordinary tools. They need special programs for it.
Q. How can we sub-classify binary files?
A. Binary files can be sub-classified as (1) binary data files and (2) binary program files.
Q. How can we sub-classify data files?
A. Data files can be classified as either input file or output file. An input file can only be read and output files can only be written. This description is only simplistic. But it helps our understanding of files. (It is possible to open a file for both input and output. More of it shall be discussed at a later stage.)
Q. How can we classify data files on the basis of how they are accessed?
A. Data files can be classified as either sequential access files or direct access files. In a sequential access file, components are accessed one after the other (sequentially) whereas in direct access files, any component can be accessed directly (without accessing its previous components). Hence, these files are also called as random access files.
So far, files have been classified as follows:
We do not want to complicate the issue by trying permutation and combination of these classes though it is understood that a particular file can simultaneously belong to multiple classes (types). A file can be binary sequential data file. A text file can be an input file or an output file. The only thing to note is that text files cannot be random access files.
File
To handle files, Java offers us a very useful class named File
. This class has many constructors and methods. Let us study it in an informal way.
We can construct an object of this class by simply calling a constructor as shown as follows.
File f1 = new File( “abc.txt”);
The computer creates an object of class File
with name abc.txt
. Here we have not specified any directory. Hence, our default working directory is assumed. The computer associates this symbolic name f1 with an actual file name (as understood by the OS) abc.txt
. The file with this name may or may not exist in the current directory. Please note that this constructor has created an object of type file and not an actual file.
To test whether such a file exists or not, Java provides Boolean method exists()
. Let us study this with the help of a program.
Problem: Write a program to test whether a given file exists in the current directory.
Solution: See Program 17.1.
PROGRAM 17.1 Test for File Existence
// file1.java
import java.io.* ;
class file1
{ public static void main(String[] args) throws Exception
{ File f1 = new File(“abc.txt”);
System.out.println(“<---file1.java starts--->”);
if( f1.exists() ) System.out.println(“File exists”);
else System.out.println(“ File does not exists”);
};
}
If you run this program, you will get the following output.
Output
<---file1.java starts--->
File does not exists
We know that files can be used for either input or output. When we create data files and want to use them for reading, we do not want the program to accidentally delete or modify it. The simplest way is to make it read-only. (This is possible in every OS.) Once a file is made “read-only”, a program cannot write to it.
Java allows us to test whether files are read-only or not. It supports two methods canRead()
and canWrite()
for this purpose.
Problem: Write a program to test whether a file exists in the current directory. Also, test if you can read from or write to that file.
Solution: If a file is read-only, we cannot write to it. However, Java has provided two separate methods. So we will use both of them (see Program 17.2).
PROGRAM 17.2 Test for Read–Write
// file2.java
import java.io.* ;
class file2
{ public static void main(String[] args) throws Exception
{ File f1 = new File(“abc.txt”);
System.out.println(“<---file2.java starts--->”);
if( f1.exists() ) System.out.println(“File exists”);
else System.out.println(“ File does not exists”);
if( f1.canRead() ) System.out.println(“can read “);
else System.out.println(“ cannot read”);
if( f1.canWrite() ) System.out.println(“can write “);
else System.out.println(“cannot write”);
};
}
If you run this program, you will get the following output.
Output
<---file2.java starts--->
File exists
can read
cannot write
Before running Program 17.2, a file with this name was created in the current directory. We deliberately made it read-only (by setting property in Windows OS). Hence, we get this particular output.
While working with methods in this class, many times we have to deal with the name of the path where the file is placed. We can use absolute pathname or abstract pathname. Absolute pathname specifies the path starting from the drive letter. Abstract pathname indicates the relative path, that is relative to current working directory.
Table 17.1 illustrates all the important methods supported by class File
.
Table 17.1 Summary of Methods: Class File
boolean |
canRead() |
Tests whether the application can read the file denoted by this abstract pathname. |
boolean |
canWrite() |
Tests whether the application can modify the file denoted by this abstract pathname. |
int |
compareTo(File pathname) |
Compares two abstract pathnames lexicographically |
int |
compareTo(Object o) |
Compares this abstract pathname to another object. |
boolean |
createNewFile() |
Atomically creates a new, empty file named by this abstract pathname, if and only if a file with this name does not exist. |
static File |
createTempFile(String prefix, String suffix) |
Creates an empty file in the default temporary-file directory, using the given prefix and suffix to generate its name. |
static File |
createTempFile(String prefix, String suffix, File directory) |
Creates a new empty file in the specified directory, using the given prefix and suffix strings to generate its name. |
boolean |
delete() |
Deletes the file or directory denoted by this abstract pathname. |
void |
deleteOnExit() |
Requests that the file or directory denoted by this abstract pathname be deleted when the virtual machine terminates. |
boolean |
equals(Object obj) |
Tests this abstract pathname for equality with the given object. |
boolean |
exists() |
Tests whether the file denoted by this abstract pathname exists. |
File |
getAbsoluteFile() |
Returns the absolute form of this abstract pathname. |
String |
getAbsolutePath() |
Returns the absolute pathname string of this abstract pathname. |
File |
getCanonicalFile() |
Returns the canonical form of this abstract pathname |
String |
getCanonicalPath() |
Returns the canonical pathname string of this abstract pathname. |
String |
getName() |
Returns the name of the file or directory denoted by this abstract pathname. |
String |
getParent() |
Returns the pathname string of the parent of this abstract pathname, or null if this pathname does not name a parent directory. |
File |
getParentFile() |
Returns the abstract pathname of the parent of this abstract pathname, or null if this pathname does not name a parent directory. |
String |
getPath() |
Converts this abstract pathname into a pathname string. |
int |
hashCode() |
Computes a hash code for this abstract pathname. |
boolean |
isAbsolute() |
Tests whether this abstract pathname is absolute. |
boolean |
isDirectory() |
Tests whether the file denoted by this abstract pathname is a directory. |
boolean |
isFile() |
Tests whether the file denoted by this abstract pathname is a normal file. |
boolean |
isHidden() |
Tests whether the file named by this abstract pathname is a hidden file. |
long |
lastModified() |
Returns the time that the file denoted by this abstract pathname was last modified. |
long |
length() |
Returns the length of the file denoted by this abstract pathname. |
String[] |
list() |
Returns an array of strings naming the files and directories in the directory denoted by this abstract pathname. |
String[] |
list(FilenameFilter filter) |
Returns an array of strings naming the files and directories in the directory denoted by this abstract pathname that satisfy the specified filter. |
File[] |
listFiles() |
Returns an array of abstract pathnames denoting the files in the directory denoted by this abstract pathname. |
File[] |
listFiles(FileFilter filter) |
Returns an array of abstract pathnames denoting the files and directories in the directory denoted by this abstract pathname that satisfy the specified filter. |
File[] |
listFiles(FilenameFilter filter) |
Returns an array of abstract pathnames denoting the files and directories in the directory denoted by this abstract pathname that satisfy the specified filter. |
static File[] |
listRoots() |
List the available file system roots. |
boolean | mkdir() |
Creates the directory named by this abstract pathname. |
boolean |
mkdirs() |
Creates the directory named by this abstract pathname, including any necessary but non-existent parent directories. |
boolean |
renameTo(File dest) |
Renames the file denoted by this abstract pathname. |
boolean |
setLastModified(long time) |
Sets the last-modified time of the file or directory named by this abstract pathname. |
boolean |
setReadOnly() |
Marks the file or directory named by this abstract pathname so that only read operations are allowed. |
String |
toString() |
Returns the pathname string of this abstract pathname. |
URL |
toURL() |
Converts this abstract pathname into a file: URL. |
Many other facilities can be seen in Section 17.11 (Program 17.13). Now, after studying class File
, we want to use files for reading and writing. To begin with, let us start our study with text files.
Let us first study how to create a text file and write to it. For this purpose, we need class FileWriter
. Let us try a simple program.
Problem: Write a program to create a text file. Write in this file Name
of a person and his weight in kilograms.
Solution: See Program 17.3.
PROGRAM 17.3 Introduction to Text File
// fo3.java
import java.io.* ;
class fo3
{ public static void main(String[] args) throws Exception
{ String s1 = “Anthony Gonsalves”;
String s2 = new String(“56.3”) ;
System.out.println(“<---fo3.java--->”);
FileWriter f2 = new FileWriter(“fo3.dat”);
f2.write(“my name = “ + s1 + “
”);
f2.write(“My Weight = “ + s2);
f2.close();
System.out.println(“file fo3.dat created”);
}
} ;
If you run this program, you will get the following output.
Output
<---fo3.java--->
file fo3.dat created
If you try to inspect the created text file, it will appear as follows:
Text File fo3b.dat
my name = Anthony Gonsalves
My Weight = 56.3
Please note that method close()
belongs to class FileWriter
. It closes this writer and flushes any pending data. In effect, it closes the file too.
Now it is the time to read a file. Text files can be read one character at a time, but it is advantageous to read the entire line at a time. Java supports a very useful class String
. It is suitable for reading one line of text at a stretch. We can get (extract) all the characters from a string easily.
Problem: Write a program to open and read a text file line by line.
Solution: See Program 17.4.
PROGRAM 17.4 Reading a Text File
// fi2.java
import java.io.* ;
class fi2
{ public static void main(String[] args) throws Exception
{ String s1 ;
// String s2 ;
boolean flag ;
System.out.println(“<---fi2.java--->”);
FileReader f1 = new FileReader(“fi2.dat”);
BufferedReader fin = new BufferedReader(f1);
while ( fin.ready() )
{ s1 = fin.readLine();
System.out.println(s1);
}
fin.close();
}
}
If you run this program, you will get the following output.
Output
<---fi2.java--->
Hello!
This is a text file.
You are reading line by line.
Thank You for reading me.
Note the function fin.ready()
.
Text files can be used to store the data in a formatted manner. Consider a case of a text file which stores the colours. A colour has a name and values of RGB colour components. A typical file is shown as follows:
Input Text File— col_values.text
It is possible to read such a file and extract data from it.
For reading files, we use class FileReader
. It is capable of reading files. However, for efficiency purpose, it is necessary to use a class BufferedReader
along with the FileReader
class. Consider the following program.
Problem: Write a program to read an input file named col_values.txt
and get colour names and RGB values.
Solution: When we inspect the input file, we note that
Now we read one line at a time in a string. Get name and values of colours in sub-strings. As sub-strings may have leading and trailing blanks, we trim them. Lastly, hexadecimal colour values are converted into integer by method parseInt()
(see Program 17.5).
PROGRAM 17.5 Reading a Formatted File
// format3.java
// Simple table
// formatted input.
import java.io.* ;
class format3
{ public static void main(String[] args) throws IOException
{ int i,j,k ;
char box[] = new char[51];
FileReader f1 = new FileReader("col_values.txt");
BufferedReader Jin = new BufferedReader(f1) ;
System.out.println("<---format3.java--->");
for(i=1; i<=4; i++) // knowing 4 lines in file
{ String sb0, sb1,sb2,sb3,sb4,stemp ;
int red, green, blue=0 ;
sb0 = Jin.readLine();
k= sb0.length();
stemp = sb0.substring(0,15);
sb1= stemp.trim();
stemp = sb0.substring(15,25);
sb2 = stemp.trim();
red = Integer.parseInt(sb2,16);
stemp = sb0.substring(25,35);
sb3 = stemp.trim();
green = Integer.parseInt(sb3,16);
stemp = sb0.substring(35,37);
sb4 = stemp.trim();
blue = Integer.parseInt(sb4,16);
System.out.println(sb1+ " " + red + " " +green +" "+blue);
}
}
} ;
If you run this program, you will see the following output.
You may wonder what the use of this program is. Well, it shows you how to read and accept colour data. With little modification, you can build an array of colour information and use it in graphics programs.
Old programming languages like Fortran and COBOL accepted only formatted data. In a formatted data, elements appear in fixed columns. Many times data may not be properly formatted. Programming languages like Pascal boasted of reading format-free data. This facility continued in languages like C and C+ +.
When data elements are separated by any number of separating characters like blanks and tabs, such data is called format-free data. To read such data, Java provides a class StringTokenizer.
It extracts tokens from a string. It implies that it automatically skips all separating characters. Once we have a string which contains a known type of data like integer or double, extracting data from it becomes very simple.
Problem: A data file contains the data of a SUDOKU puzzle. Every line contains a row number, a column number, and the value. These numbers (integers) are separated by any number of blanks and/or tabs. In other words, they are present in format-free manner. Write a program to read this data in an array.
Solution: We will read data line by line in a string. Subject this string to StringTokenizer
.
As data may have maximum 81 rows, array will have 81 rows and three columns ( see Program 17.6).
PROGRAM 17.6 Using StringTokenizer
// token1.java
import java.io.* ;
import java.util.* ;
class token1
{ public static void main(String[] args) throws IOException
{ int a[][] = new int[81][3] ;
String line = null;
String str1,str2,str3 ;
int i,j,N;
i=0;
try {
FileReader f1 = new FileReader("token1.txt");
BufferedReader br = new BufferedReader( f1);
while ((line = br.readLine()) != null)
{ System.out.println("line read is: " + line);
j=0;
StringTokenizer st = new StringTokenizer(line);
while (st.hasMoreTokens())
{ str1 = st.nextToken() ;
a[i][j] = Integer.parseInt(str1);
j++;
}
i++;
}
br.close();
}
catch(Exception e)
{ System.out.println("Some Error"); }
N=i-1;
System.out.println("Now printing array a");
for(i=0;i<=N;i++)
{ for(j=0;j<3;j++)
System.out.print(a[i][j]+" ");
System.out.println();
}
}
}
If you run the program, you will get the following output.
Output
line read is: 1 2 3
line read is: 3 4 5
line read is: 5 6 7
Now printing array a
1 2 3
3 4 5
5 6 7
As mentioned earlier, there are certain advantages of binary files. Let us try to create and use binary files. These files are used to store data. Hence, the simplest example will be of storing a few integers. Study the following program.
As we are writing binary data in a file, we have to use class FileOutputStream
embedded in class DataOutputStream
.
Problem: Write a program to create a binary data file binfile1.dat
. The file should contain first 10 odd integers.
Solution: See Program 17.7.
PROGRAM 17.7 Creating Binary File
// binfile1.java
import java.io.* ;
class binfile1
{ public static void main(String[] args) throws Exception
System.out.println("<---binfile1--->");
FileOutputStream fx = new
FileOutputStream("binfile1.dat");
DataOutputStream f2 = new DataOutputStream(fx);
for(i = 1;i<20;i=i+2)
{ f2.writeInt(i);
}
f2.close();
System.out.println("file created successfully");
}
} ;
This program creates the file binfile1.dat
. As stated earlier, you cannot see this file in word processor and will need a program to see the contents of that file. One may ask what is the use of such binary files. Practically, every large data file is stored as binary file. Large databases are also binary files. But DBMS software comes with built-in programs to view them. Let us write a simple program to read a binary file.
When we want to read a binary file, we have to use class FileInputStream
embedded in class DataInputStream
.
Problem: Write a program to read a binary data file binfile1.dat
and display its contents. It is known that the file contains 10 integers.
Solution: See Program 17.8.
PROGRAM 17.8 Reading a Binary File
// binfile2.java
import java.io.* ;
class binfile2
{ public static void main(String[] args) throws Exception
{ int i,k;
System.out.println(“<---binfile2--->”);
FileInputStream fy = new
FileInputStream(“binfile1.dat”);
DataInputStream f1 = new DataInputStream(fy);
for(i = 0;i<10;i++)
{ k=f1.readInt();
System.out.println(k + “ “);
}
f1.close();
}
};
If you run this program, you will get the following output.
Output
<---binfile2--->
1
3
5
9
11
13
15
17
19
This console output displays the contents of binary file binfile1.dat
generated by Program 17.7.
In the previous section, we first created and then read a binary file consisting of integers. We can do that for any other primary data type like float, long, and double. A file can contain different data types as well. In early days of computer programming, binary files were used to contain records (see Box 17.1). In terms of object-oriented language, an object represents a record. Hence, a binary file can be used to store objects. (Of course, all belong to the same class.) (See Box 17.2.)
Record is a very popular term of old programming languages. A record means collection of variables in a bundle. In C/C+ +, it is called struct
. Actually, an object is improvised version of struct
. Type class can also represent struct
. In C+ +, both class
and struct
are available. Java developers decided to drop the type struct
.
Theoretically, it is possible that a binary file can contain variables of different primitive types. But when you read such a file, you must know the exact sequence of the data in that file. This is practically a very difficult task. We will need another file to keep this information, and the speed with which we read will also decrease. Also, we will not be able to jump to the nth record directly. This prevents any arbitrary combination of primitive data types in a file. Hence, a binary file will have all integers or all bytes or all doubles. Though we said primitive data types, the point is valid for objects too.
Let us write a program which creates a file for objects and reads it back.
Problem: Write a program to create a (binary data) file of objects. The file should contain five objects of class complex number. Next, open that file for reading and fill the array of complex numbers from the file.
Solution: To write binary data, we have to use class FileOutputStream
embedded in class DataOutputStream
. When we want to read that file, we have to use class FileInputStream
embedded in class DataInputStream
(see Program 17.9).
PROGRAM 17.9 File for Objects
// objfile2.java
import java.io.* ;
class Complex
{ double x, y ;
{ System.out.print(“ Complex number: “ );
System.out.println(x +” +j “+ y);
};
Complex(double x1, double y1)
{ x=x1;
y=y1;
};
} ;
class objfile2
{ public static void main(String arg[]) throws Exception
{ int i;
Complex n1, n2, n3, n4, n5 ;
System.out.println(“--->objfile2.java starts<---”);
double x, y ;
FileOutputStream fx = new
FileOutputStream(“objfile2.dat”);
DataOutputStream f1 = new DataOutputStream(fx);
n1 = new Complex(3.1, 5.1);
n2 = new Complex(5.1, 7.2);
n3 = new Complex(7.1, 9.3);
n4 = new Complex(9.1, 11.4);
n5 = new Complex(11.1,13.5);
System.out.println(“Writing data to file”);
f1.writeDouble(n1.x);
f1.writeDouble(n1.y);
f1.writeDouble(n2.x);
f1.writeDouble(n2.y);
f1.writeDouble(n3.x);
f1.writeDouble(n3.y);
f1.writeDouble(n4.x);
f1.writeDouble(n4.y);
f1.writeDouble(n5.x);
f1.writeDouble(n5.y);
f1.close();
// Now the same file will be open for input
FileInputStream fy = new
FileInputStream(“objfile2.dat”);
DataInputStream f2 = new DataInputStream(fy);
Complex A[] = new Complex[5];
// reading from file into an array
System.out.println(“Reading data from file”);
for (i=0 ; i< 5; i++)
{ x = f2.readDouble();
y = f2.readDouble();
A[i] = new Complex(x, y);
System.out.println(“Displaying data from array”);
for (i=0 ; i< 5; i++)
A[i].show();
}
}
If you run this program, you will get the following output.
Output
--->objfile2.java starts<---
Writing data to file
Reading data from file
Displaying data from array
Complex number: 3.1 +j 5.1
Complex number: 5.1 +j 7.2
Complex number: 7.1 +j 9.3
Complex number: 9.1 +j 11.4
Complex number: 11.1 +j 13.5
Important: So for we have not discussed any limitations on objects that can be stored in a binary file. The object must contain only basic data types. It should not contain strings. Strings have no fixed length. Hence, different objects will have different lengths. It will be difficult to handle them. In other words, the object we want to handle must get converted into a fixed number of bytes. This was not the case with text files. Text files can have every line of different length.
As mentioned earlier, a file can be opened for either reading or writing. This is a simplistic model of files. Nevertheless, it helps us in understanding and using the files easily. In early days of computing, files were strictly sequential. Data was to be read and processed from these files, and the output was kept in another file. For example, the basic pay of an employee was to be read as the data file, and salary statements (or salary slips) were written to output file.
Nowadays the scenario has changed. Databases have become common. Transaction processing has become “online”. It calls for a file to be read and written simultaneously. In such a case, there is no meaning to sequential accessing of a file. Access has to be “random”, and such files are called random access files. Random means we should be able to reach to a particular position directly. Therefore, such files are also known as direct access files. Such access puts a restriction on the file. All the elements of the file should be of same type. The type can be either elementary type or an object in general.
Figure 17.1 shows a schematic random access file. To allow us to work with such files, Java provides a class RandomAccessFile
.
Figure 17.1 Random Access File
This class implements interfaces DataInput
and DataOutput.
These interfaces define basic input/ output methods.
There are two constructors for this class.
RandomAccessFile(File fileObject , String access) throws
FileNotFoundException
and
RandomAccessFile( String filename, String access) throws
FileNotFoundException
Access string can be either “r” or “rw” signifying read or read–write operation.
Let us study this class with a program.
Problem: Write a seat reservation program using random access file. Consider a hill station with a tourist helicopter. Assume that it has 10 seats numbered 1 to 10. Assume the following situation:
Solution: To begin with, all seats are free. Hence, all are marked with value 0. Please note that the ticket numbers start from 1. Hence, writing ticket number 0 is same as no ticket is issued for this seat.
When a seat number is requested, using seek instruction, we try to find the data (ticket number). If the ticket number is zero, we write the current ticket number to this seat.
At the end of the day, we want to have a summary. It may be noted that random access file can be accessed sequentially as well.
Hence, we go to the first record and keep on reading the seat numbers.
See Program 17.10.
PROGRAM 17.10 Random Access File
// rand1.java
import java.io.* ;
class rand1
{ public static void main(String[] args) throws Exception
{ int i,k,num,Tnum;
int request = 0 ;
int data[] = { 3, 5, 6, 5, 3, 4 , 9, 7, 2, 1 } ;
int ticket_number = 1 ;
System.out.println("program rand1.java starts");
RandomAccessFile frand = new
RandomAccessFile("rand1.dat","rw");
for(i = 0;i<11;i++)
{ frand.writeInt(0);
}
// data initialisation over
// live transation starts 6 in number
while (request < 6)
{ k = data[request++];
System.out.println("Requested seat number : "+ k);
frand.seek(4 * k );
num = frand.readInt();
if( num == 0 ) // seat availble
{ frand.seek(4 * k ); //very important
frand.writeInt(ticket_number); // to file
System.out.print("Seat reserved ");
System.out.print(" ticket number " + ticket_number);
System.out.println(" seat number " + k );
ticket_number++;
}
else
System.out.println(" sorry this seat is booked");
}
// printing summary
System.out.println(" printing summary " );
System.out.println("seat ticket");
frand.seek(4 * 0 );
for(i=0;i<10;i++)
{ Tnum = frand.readInt();
System.out.println(i + " " + Tnum);
}
frand.close();
}
}
If you run this program, you will get the following output.
Output
Requested seat number : 3
Seat reserved ticket number 1 seat number 3
Requested seat number : 5
Seat reserved ticket number 2 seat number 5
Requested seat number : 6
Seat reserved ticket number 3 seat number 6
Requested seat number : 5
sorry this seat is booked
Requested seat number : 3
sorry this seat is booked
Requested seat number : 4
Seat reserved ticket number 4 seat number 4
printing summary
seat ticket
0 0
1 0
2 0
3 1
5 2
6 3
7 0
8 0
9 0
While the text was in development, one of my friends pointed out that the title “file for objects” is incorrect. It should be “file of objects”. I politely pointed out that the use of word “for” was deliberate. What we have created was not the file of objects. He asked, “Is it because no strings?” (He was right in a way. Strings are also objects but they require unequal memory. The present model requires that every object must need the same number of bytes.) I replied, “No. The main reason is in that in this model we could not allow even reference!”
As mentioned earlier, there are two dynamic data structures, namely, linked list and binary tree. In these structures, it is possible for an object to refer to one or many objects. Those objects can refer to still more objects.
Hence, if we claim to store one object, we may have to store 100 objects with complex interlinking. This appears to be a very difficult task. But Java makes it amazingly simple. Java allows serialization of the object. It also allows us to simply call one particular write method. However, this topic is beyond the scope of this chapter.
It is a known fact that data stored in binary form is read very quickly. However, it is not possible to test the premise when we deal with small size files. In practice, files are of very large size in applications like databases. Hence, it will be a good idea to measure the time needed to read a large binary file.
Problem: Write a program to demonstrate reading of large binary files.
Solution: Let us first create a binary file storing 10,000,000 integers. Then we will read them back. For measuring time, we will use methods from class BPtimer
(see Program 17.11).
PROGRAM 17.11 Large Binary File
// binfile12.java
// Creating LARGE Binary file
import java.io.* ;
class binfile12
{ public static void main(String[] args) throws Exception
{ int i,k=0;
System.out.println("<---binfile12.java starts--->");
FileOutputStream fx = new
FileOutputStream("binfile1.dat");
BufferedOutputStream bos = new
BufferedOutputStream(fx);
DataOutputStream f2 = new DataOutputStream(bos);//(fx);
for (i=1;i<=10000000;i++)
// while( f2.ready() )
{ f2.writeInt(i);
}
f2.close();
System.out.println("file created successfully");
FileInputStream fy = new
FileInputStream("binfile1.dat");
BufferedInputStream bis = new BufferedInputStream(fy);
DataInputStream f1 = new DataInputStream(bis);//(fy);
System.out.println("reading starts");
BPtimer.start();
for (i=1;i<=10000000;i++)
k=f1.readInt();
System.out.println("file read successfully");
System.out.println(k + " ");
f1.close();
BPtimer.stop();
}
} ;
class BPtimer
{ private static long t0;
private static long t1;
public static void start()
{ t0 = System.currentTimeMillis();
}
public static void stop()
{ t1 = System.currentTimeMillis() - t0 ;
System.out.println("time measured = " + t1
+ "
milliSeconds");
}
}
If you run this program, you will get the following output.
Output
<---binfile12.java starts--->
file created successfully
reading starts
file read successfully
10000000
time measured = 1063
milliseconds
We have just seen a large binary file. For comparison purpose, we are required to work with a large text file which will take much more time to read and write. Computer scientists have developed the concept of buffering (hardware) to reduce this time. Java offers us the classes BufferedReader
and BufferedWriter
for this purpose. Let us study it with help of a program.
Problem: Write a program to show that one can read faster with the help of BufferedReader
.
Solution: To appreciate the speed, we must have a very large file. Here we will create a large text file and keep natural numbers from 1 to 10,000,000 in it (one number in one line). Then we will read this file. We will use methods from class BPtimer
to measure the time (see Program 17.12).
PROGRAM 17.12 Large Text File
// big size text files
// fo4.java
import java.io.* ;
public class fo4
{ public static void main(String[] args) throws Exception
{ String s1 ;
int i =10 ;
int k =0;
System.out.println("<---fo4.java--->");
System.out.println("Creating Data file");
FileWriter f2 = new FileWriter("fo4.dat");
BufferedWriter bw = new BufferedWriter (f2) ;
for (i=1;i<=10000000;i++)
bw.write(i+ "
" );
bw.close();
System.out.println("file fo4.dat created");
FileReader f1 = new FileReader("fo4.dat");
BufferedReader fin = new BufferedReader(f1);
System.out.println("file reading starts");
BPtimer.start();
while ( fin.ready() )
{ s1 = fin.readLine();
k=Integer.parseInt(s1);
}
// System.out.println(k); // for debugging
fin.close();
BPtimer.stop();
System.out.println("program over");
}
} ;
class BPtimer
{ private static long t0;
private static long t1;
public static void start()
{ t0 = System.currentTimeMillis();
}
public static void stop()
{ t1 = System.currentTimeMillis() - t0 ;
System.out.println("time measured = " + t1 + "
in milli seconds");
}
}
If we run this program, we will get the following output.
Output
<---fo4.java--->
Creating Data file
file fo4.dat created
file reading starts
time measured = 5797
in milli seconds
program over
You may modify the program in such a way that BufferedReader
is not used. Find the time to read in that case.
The contents of this text file were same as binary file of the previous program. Compare the time recorded in both the programs.
Problem: Write a program to find and list all the files in a given directory.
Solution: Java supports a very interesting method named list()
. It gets all the names of all the files in the directory and put it in an array of string. See Program 17.13.
PROGRAM 17.13 Listing Files from a Directory
// file3.java
import java.io.* ;
class file3
{ public static void main(String[] args) throws Exception
{ int i, k ;
String dname = new String("c:/jprog/ch17/file3");
File d1 = new File( dname);
String[] filelist ;
System.out.println("<---file3.java starts--->");
if( d1.isDirectory() )
System.out.println("Yes it is a directory");
else
{ System.out.println(
" File named is not a directory");
System.exit(0);
}
k = filelist.length;
System.out.println("no of entries are " + k);
for(i=0;i<k;i++)
System.out.println(i+") " + filelist[i] );
}
}
If you run this program, you will get the following output.
Output
<---file3.java starts--->
Yes it is a directory
no of entries are 2
0) file3.class
1) file3.java
As expected, the program lists all the files in the specified directory. Unfortunately, this method also lists folders (directories) as files when they exist. It is left to the readers to improve the program such that the output contains only files and not the folders (directories).
Problem: Write a program to read a matrix from a binary data file.
Solution: Earlier we solved a problem on 3 × 3 matrix addition. We will use the same program but will add a new constructor which will accept the file name as a parameter (see Program 17.14).
PROGRAM 17.14 Reading an Array from Binary File
// matrix3.java
// reading from binary file
/ matrix addition
import java.io.* ;
class mat3x3
{ int[][] ele = new int[3][3];
mat3x3( int[] A )
{ int i,j,k=0;
for(i=0;i<=2;i++)
for(j=0;j<=2;j++)
ele[i][j]=A[k++];
}
mat3x3() // creates matrix without assigning values
{
};
mat3x3(String fname) throws Exception
// creates matrix from file
{ int i,j,k;
FileInputStream fy = new
FileInputStream(fname);
DataInputStream(fy);
System.out.println(“constructor invoked”);
for(i=0;i<=2;i++)
for(j=0;j<=2;j++)
{ k=f1.readInt();
System.out.print(k + “ “); // for debugging only
ele[i][j] = k ;
}
System.out.println();
fy.close();
};
}
class matrix3
{
public static void main(String arg[]) throws Exception
{ mat3x3 mat1 = new mat3x3(“mat1.dat”) ;
mat3x3 mat2 = new mat3x3(“mat2.dat”) ;
mat3x3 mat3 = new mat3x3();
int i,j;
System.out.println(“--->matrix3.java<---“);
// calculating
for(i=0;i<=2;i++)
for(j=0;j<=2;j++)
mat3.ele[i][j] = mat1.ele[i][j] + mat2.ele[i][j];
System.out.println(“mat1”);
for(i=0;i<=2;++i)
{ for(j=0;j<=2;++j)
System.out.print(“ ” + mat1.ele[i][j]);
System.out.println();
}
System.out.println(“mat2”);
for(i=0;i<=2;++i)
{ for(j=0;j<=2;++j)
System.out.print(“ ” + mat2.ele[i][j]);
System.out.println();
}
System.out.println(“mat3”);
for(i=0;i<=2;++i)
{ for(j=0;j<=2;++j)
System.out.print(“ ” + mat3.ele[i][j]);
System.out.println();
}
}
}
If you run this program, you will get the following output.
Output
Note that line
“constructor invoked”
tells us that the constructor with file name as parameter is invoked.
File structure in most of the OSs is tree structure. We can see only one folder at a time. We cannot see or list all the files easily. Hence, an application which can list all the files in a given directory is highly desirable. Let us try our knowledge of files to do this task.
Problem: Write a program to find (using recursion) all the files in a given directory and all of its sub directories.
Solution: Writing a solution without recursion will be difficult. Recursion makes the program simple and short. In essence, we should develop a recursive method which gets all the files. Let us name such method as getThemAll
(see Program 17.15).
PROGRAM 17.15 Listing all Files
// ftree3.java
// uses recursion to list all files.
//
import java.io.* ;
class ftree3
{ static File[] filelist ;
static FileWriter f2;
static int fileCount =0;
static void getThemAll(File d1) throws IOException
{ int i,k,dind;
System.out.println("Yes it is a directory-> "+ d1);
filelist = d1.listFiles();
k = filelist.length;
System.out.println("no of entries are " + k);
File dirArray[] = new File[k] ;
dind =0 ; // index for darray
for(i=0;i<k;i++)
{ if(filelist[i].isDirectory() )
{ dirArray[dind++] = filelist[i] ;
}
else
{ System.out.println(fileCount + ") " + filelist[i] +" "+"file");
f2.write(fileCount + ") " + filelist[i] +"
");
fileCount++;
}
}
for(i=0;i<dind;i++)
{ System.out.println( i + ") " + dirArray[i] );
getThemAll ( dirArray[i] );
}
}
public static void main(String[] args) throws Exception
{ int i, k ;
String dname = new String("C://Jprog");
File d1 = new File( dname);
f2 = new FileWriter("ftree3.out");
System.out.println("<---ftree3.java starts--->");
if( d1.isDirectory() == false)
{ System.out.println(" File named is not adirectory");
return ;
}
getThemAll( d1);
f2.close();
}
}
If you run this program, you will get the output on screen as well as stored in the file. When I ran this program, there were more than 12,000 lines in the output. Only the first few lines are presented in the following output.
Output
0) C:JprogJXP7.bat
1) C:JprogJXP6n.bat
2) C:JprogcmdJdk6.bat
3) C:JprogBPJA6new.bat
4) C:JprogBPJA6N.EXE
5) C:JprogxxBPJA6NEW.EXE
6) C:JprogLatest Java_prog_list.txt
7) C:JprogBPJA6N.PIF
8) C:Jprogubgra1.class
9) C:Jprogch3it1it1.class
11) C:Jprogch3area1area1.class
12) C:Jprogch3area1area1.ctxt
13) C:Jprogch3area1area1.java
14) C:Jprogch3area1luej.pkg
15) C:Jprogch3area1luej.pkh
16) C:Jprogch3char1char1.java
17) C:Jprogch3char1char1.class
18) C:Jprogch3char1char1.out
19) C:Jprogch3char3char3.java
20) C:Jprogch3char3char3.class
21) C:Jprogch3char3char3n.class
22) C:Jprogch3char3char3n.out
23) C:Jprogch3char3char3n.java
24) C:Jprogch3const1const1.java
25) C:Jprogch3const1const1.class
26) C:Jprogch3final1afinal1a.err
27) C:Jprogch3final1afinal1a.java
28) C:Jprogch3final1final1.java
29) C:Jprogch3final1final1.class
30) C:Jprogch3line1line1.java
31) C:Jprogch3line1line1.class
32) C:Jprogch3line1line1.out
33) C:Jprogch3logical1logical1.java
34) C:Jprogch3logical1logical1.class
35) C:Jprogch3modulo1modulo1.java
36) C:Jprogch3modulo1modulo1.class
37) C:Jprogch3
elop1
elop1.java
38) C:Jprogch3shift1shift1.java
39) C:Jprogch3shift1shift1.class
40) C:Jprogch3 runc1 runc1.java
41) C:Jprogch3 runc1 runc1.class
42) C:Jprogch3unicode1unicode1.class
43) C:Jprogch3unicode1unicode1.java
44) C:Jprogch3firstabc1.doc
45) C:Jprogch3firstfirst.class
46) C:Jprogch3firstfirst.java
47) C:Jprogch3firstfirst.out
48) C:Jprogch3unicode2unicode2.out
49) C:Jprogch3unicode2unicode2.java
50) C:Jprogch3unicode2unicode2.class
If you study the output, you will find that this program first lists all the files from a given directory namely C:Jprog
. Then it prints files in the sub-directories also.
absolute pathname, abstract pathname, binary files, BufferedReader
, BufferedWriter
, canRead()
, canWrite()
, class File
, DataInputStream
, DataOutputStream
, delete()
, deleteOnExit()
, direct access file, exists()
, FileInputStream
, FileNotFoundException
, FileOutputStream
, Format-free data, formatted data, getAbsoluteFile()
, getAbsolutePath()
, getParent()
, getParentFile()
, input file, isAbsolute()
, lastModified()
, list()
, listFiles()
, mkdir()
, object serialization, output file, random access files, record, sequential access file, text files.
StringTokenizer
?The information should be entered using console.
3.145.101.81