Monday, February 13, 2012

New methods of the File class

In Java SE 6.0, the File class has been enhanced to include new methods that provide information about disk usage:

  • getTotalSpace()
  • getFreeSpace()
  • getUsableSpace()
getTotalSpace()
The getTotalSpace method provides information on a particular File's partition size in bytes.
getFreeSpace()
The getFreeSpace method provides information about the available space still unused in a particular File partition in bytes.
getUsableSpace()
Similar to getFreeSpace, the getUsableSpace method further checks for OS restrictions and available write permissions associated with the File.
This code is an example of how to use the getTotalSpace, getFreeSpace, and getUsableSpace methods.
import java.io.*;

public class SampleFileMethod {
  public static void main(String args[]) {

       if(args.length>0) {
    File f=new File(args[0]);
    System.out.println(" Total size of " + f + " is=:"+ f.getTotalSpace());
    System.out.println(" Available space of " + f + " is=:"+ f.getFreeSpace());
    System.out.println(" Usable space of " + f + " is=:"+ f.getUsableSpace());
      } else {
    System.out.println(" Enter a Filename");
    }
  }
}
Additional methods used to specify restrictions or permissions in reading, writing, or executing a File object are
  • setWritable()
  • setReadable()
  • setExecutable():
setWritable()
The setWritable method specifies the permissions on write operations to a File object. This method is overloaded as follows:
  setWritable(boolean writable)
  setWritable(boolean writable, boolean ownerOnly)

The first method is used to specify if the file is writable or not. The second method enhances the first by specifying if the write permission is applicable only to the owner.
setReadable()
The setReadable method specifies the permissions on read operations to a File object. This method is overloaded as follows:
  setReadable(boolean readable)
  setReadable(boolean readable, boolean ownerOnly)
The first method specifies if the file can be accessed or not. The second method enhances the first by specifying if the read permission is applicable only to the owner.

If the underlying file system cannot distinguish the owner's read permission from that of others, the permission will apply to everybody, regardless of this value.
setExecutable():
The setExecutable method specifies the execute permissions on a File object being executed. This method is overloaded as follows:
  setExecutable(boolean executable)
  setExecutable(boolean executable, boolean ownerOnly)


The method used to test if the file can be executed or not is the canExecute() method.
This code is an example of how setWritable() can be used.
import java.io.*;

public class SampleFileWrite {

  public static void main(String args[]) {
       if(args.length>0) {
    File f=new File(args[0]);
    f.setWritable(false);
    System.out.println("File writable? " + f.canWrite());
    //checks if the File is editable
    f.setWritable(true, true);
    System.out.println("File writable? " + f.canWrite());
    //checks if the File is editable
      } else {
    System.out.println(" Enter a Filename");
    }
  }
}
The canWrite method is used to check whether the file can be edited or is read only (where setWritable() is set to false).

Console Class

The Console class is a new feature of Java 6.0. It provides an alternative to the standard streams currently being used.



The Console is commonly used as a support in securing password entries. It contains methods that can suppress the characters being displayed on the user's screen, and remove them from memory when they are no longer needed.
To use the Console, you must retrieve the Console object using the System.console method. If the Console object is available, the Console object is returned. Otherwise, it returns null, and use of the Console is not permitted. This happens when the Console is not supported by the underlying OS or the application is launched in an environment that is not interactive.
Consider this sample code that uses the Console class to verify a password.

The first statement executed within the static main method attempts to retrieve an instance of the Console object using System.console().
import java.util.Arrays ;
import java.io.* ;
public class SampleConsole {
    
    public static void main (String args[]) throws IOException {

        Console c = System.console() ;
        if (c == null) {
            System.err.println("No console is available.") ;
            System.exit(1) ;
        }

        String login = c.readLine("Please enter your login information: ") ;
        char [] oldPassword = c.readPassword("Enter your old password: ") ;
      boolean test ;
        
            do {
                char [] newPassword1 =
                    c.readPassword("Input your new password: ") ;
                char [] newPassword2 =
                    c.readPassword("Input the new password again: ") ;
                test = ! Arrays.equals(newPassword1, newPassword2) ;
                if (test) {
                    c.format("Your passwords do not match. Try again.%n") ;
                } else {
                    c.format("The password for %s changed.%n", login) ;
                }
                
            } while (test) ;        
  }  
}
If the Console object is not available, the application is aborted using the System.exit(1) method.

If a Console object is available, the readLine method is invoked to prompt for and read the user's login name.
The readPassword method is invoked to prompt and read the password. Values typed are not echoed on screen. This provides a secure entry of values being typed for a password.
import java.util.Arrays ;
import java.io.* ;
public class SampleConsole {
    
    public static void main (String args[]) throws IOException {

        Console c = System.console() ;
        if (c == null) {
            System.err.println("No console is available.") ;
            System.exit(1) ;
        }

        String login = c.readLine("Please enter your login information: ") ;
        char [] oldPassword = c.readPassword("Enter your old password: ") ;
      boolean test ;
        
            do {
                char [] newPassword1 =
                    c.readPassword("Input your new password: ") ;
                char [] newPassword2 =
                    c.readPassword("Input the new password again: ") ;
                test = ! Arrays.equals(newPassword1, newPassword2) ;
                if (test) {
                    c.format("Your passwords do not match. Try again.%n") ;
                } else {
                    c.format("The password for %s changed.%n", login) ;
                }
                
            } while (test) ;        
  }  
}
The Arrays.equals method is used to test the two character arrays. If they contain the same values, the Arrays.equals method will return a boolean value.
The format method writes output to the console's outputstream using the specified format. It is similar to a printf method because it enables more control over how the output should display.
import java.util.Arrays ;
import java.io.* ;
public class SampleConsole {
    
    public static void main (String args[]) throws IOException {

        Console c = System.console() ;
        if (c == null) {
            System.err.println("No console is available.") ;
            System.exit(1) ;
        }

        String login = c.readLine("Please enter your login information: ") ;
        char [] oldPassword = c.readPassword("Enter your old password: ") ;
      boolean test ;
        
            do {
                char [] newPassword1 =
                    c.readPassword("Input your new password: ") ;
                char [] newPassword2 =
                    c.readPassword("Input the new password again: ") ;
                test = ! Arrays.equals(newPassword1, newPassword2) ;
                if (test) {
                    c.format("Your passwords do not match. Try again.%n") ;
                } else {
                    c.format("The password for %s changed.%n", login) ;
                }
                
            } while (test) ;        
  }  
}
The %s coversion type format is used to represent a value as a String. The login varaible represents the value that is being formatted by %s and the %n conversion type format is equivalent to a carriage return.

Reader and Writer classes

Reader classes are similar to input streams, and writer classes are similar to output streams. Reader classes descend from the abstract Reader class, whereas the Writer classes descend from the abstract Writer class.


Both readers and writers are divided into low-level and high-level classes. Low-level classes communicate with I/O devices, and high-level classes communicate with the low-level ones.
Readers and writers are designed specifically for Unicode characters. Low-level readers and writers deal with chars.
The java.io package provides the following low-level Reader classes:
  • FileReader
  • CharArrayReader
  • PipedReader
  • StringReader
FileReader
The FileReader class is used to read streams of characters from a file.

This class is useful to read text files.
CharArrayReader
The CharArrayReader class reads arrays of characters by implementing a character buffer. The character array acts like a character input stream.
PipedReader
The PipedReader class provides a piped character-input stream.

It should be used with a piped character-output stream so that data written to the PipedWriter will be available from this reader.
StringReader
The StringReader class uses strings as its source of a character stream. Individual characters can be marked and read from the string.
The high-level reader classes include
  • BufferedReader
  • FilterReader
  • InputStreamReader
BufferedReader
The BufferedReader class is used to read text from a character-input stream.

You can use the class to improve the efficiency of your code. Buffers enable you to write and read data in bulk. It is recommended to always use buffered I/O.
FilterReader
The FilterReader class is an abstract class that is used to filter character streams. By overriding the appropriate methods of FilterReader, a subclass can decide what gets read and how it is handled. For example, you can filter lines from a file, based on a regular expression.
InputStreamReader
The InputStreamReader is a class that is used to convert a byte stream into a set of characters, using a specified Charset. You can use InputStreamReader to accept input from System.In, up to a designated escape character or sequence.
Consider the code for the InnerActionListener class. The FileReader class, which the application uses to read data, has two constructors. One constructor takes a File object as a parameter.
class InnerActionListener
  implements ActionListener {
  public void actionPerformed (ActionEvent e) {
    String s ;
    long len ;
    contents.setText(null) ;
    File f = new File (tb.getText().trim()) ;
    if (f.exists() && f.isFile()
    && f.canRead()) {
      try {
        FileReader buff = new FileReader (f) ;
        BufferedReader theFile = 
        new BufferedReader(buff) ;
        while ((s = theFile.readLine()) != null) {
          contents.append (s + "\n") 
        }
        target.setText(tb.getText().trim()+"2") ;
        theFile.close() ;
FileReader(String pathname)
FileReader(File file)
The application first creates a File object. The File object allows you to interrogate the file system.
The file object is passed into the constructor for a FileReader called buff. The FileReader is a low-level object that allows you to read from a file.
BufferedReader - one of the high-level readers in the java.io package - has an internal buffer that enables data to be read in large blocks. This reduces I/O overhead.
class InnerActionListener
  implements ActionListener {
  public void actionPerformed (ActionEvent e) {
    String s ;
    long len ;
    contents.setText(null);
    File f = new File (tb.getText().trim()) ;
    if (f.exists() && f.isFile()
    && f.canRead()) {
      try {
        FileReader buff = new FileReader (f) ;
        BufferedReader theFile = 
        new BufferedReader(buff);
        while ((s = theFile.readLine()) != null) {
          contents.append (s + "\n") ;
        }
        target.setText(tb.getText().trim()+"2") ;
        theFile.close();
Its readLine method can read the next line of text sent to it by a low-level reader.
String readLine() throws IOException
It is a good idea to wrap buffered readers around unbuffered readers to make I/O more efficient.
A BufferedReader object can accept any type of low-level reader as an input source. For example, you can specify that the buff FileReader object is used as an input source by passing it into the constructor of the BufferedReader class as a parameter.
class InnerActionListener
  implements ActionListener {
  public void actionPerformed (ActionEvent e) {
    String s ;
    long len ;
    contents.setText(null);
    File f = new File (tb.getText().trim()) ;
    if (f.exists() && f.isFile()
    && f.canRead()) {
      try {
        FileReader buff = new FileReader (f) ;
        BufferedReader theFile = 
        new BufferedReader(buff) ;
        while ((s = theFile.readLine()) != null) {
          contents.append (s + "\n") ;
        }
        target.setText(tb.getText().trim()+"2") ;
        theFile.close() ;
You can use a while loop to read the next line from the specified file and display it in the application's contents area.
As with input and output streams, most reader classes have a corresponding writer class. In this example, an application uses a FileReader and a BufferedReader to read files. It uses a FileWriter and a BufferedWriter to write them.
class innerButtonListener extends MouseAdapter{
  public void mouseClicked(MouseEvent evt) {
  File f = new File(target.getText().trim());
    Button b2;
    if(f.exists()) {
      enter.setText("This file already exists");
      return;
    }
  try{
    FileWriter output = new FileWriter(f);
    BufferedWriter out =
    new BufferedWriter(output);
    String s = contents.getText();
    //write out contents of TextArea
    out.write(s,0,s.length());
    //send output from write to file
    out.flush();
    out.close();
    //close files
    output.close();
  }
The write method of BufferedWriter writes the data from the application's contents area.
But it does not write data to its destination if the amount of data is smaller than the BufferedWriter object's buffer. If that is the case, the object stores the data instead of writing it to the file. When the buffer's size limit is reached, the object writes the contents of the object's buffer to the file.
To prevent this data being lost when you close the file, you use the flush method to send all the remaining data from the BufferedWriter object's buffer to the FileWriter object.
Exception errors often occur when executing an application that uses the input and output classes. These can be thrown by the JVM. Some important errors include
  • FileNotFoundException
  • EOFException
  • InterruptedIOException
  • ObjectStreamException
FileNotFoundException
A FileNotFoundException occurs when an attempt to locate a file at a specified path is unsuccessful.
EOFException
An EOFException occurs when the end of a file is reached unexpectedly.
InterruptedIOException
An InterruptedIOException occurs when the input or output operation is interrupted unexpectedly.
ObjectStreamException
The ObjectStreamException class is the base class for errors thrown by the ObjectStream classes.

High-level streams

High-level input and output streams communicate with low-level streams rather than with I/O devices. You can use them for high-level input and output.

Most of Java's high-level input and output classes inherit attributes from the FilterInputStream and FilterOutputStream superclasses. In turn, these classes inherit from the abstract InputStream and OutputStream classes.
Suppose you are using a DataInputStream constructor for one of these classes. You need to pass an InputStream to the constructor as a parameter.
DataInputStream(InputStream objectName)
You can use any class that inherits from the InputStream class as an input source for a high-level stream. For example, you can use a FileInputStream object that you have already created, or use input from a socket or pipe.
When a high-level stream object, such as an instance of the DataInputStream class, receives byte input from a low-level stream, it processes the bytes and converts them into the appropriate datatype.

The DataInputStream class contains read methods that convert bytes into all the primitive datatypes, as well as into UTF strings. For example, the readInt method reads the next four bytes and converts them into an int. For the methods to work correctly, these four bytes must represent an int. You need to make sure that the data is read in the same order in which it is written to a stream.
To close a DataInputStream object, you use the class's close method.

If you need to close a chain of stream objects, you do so in reverse order so that the object that was created first is the last one to close.

This prevents you from closing an InputStream before you close the high-level stream that uses it as an input source.
For example, the code sample that reads sales data from a file uses the close method to close an instance of the DataInputStream object.
    for (int i = 0; i < descs.length; i ++) {
      myData = new SalesData (descs[i], amounts[i], values[i]);
      writeSalesData ( myData ) ;
    }
    out.close() ;


    // Prepare to read it in
    in = new DataInputStream(new FileInputStream(fruitfile)) ;

    for (int i=0; i<6; i++) {
      myData = readSalesData () ;
      System.out.println("You sold " +
      myData.desc + " at $" +
      myData.value + " each. Amount was " + myData.amount) ;
    }
    in.close() ;
  }

The subclasses of the FilterOutputStream class include
  • DataOutputStream
  • BufferedOutputStream
  • PrintStream
DataOutputStream
You use the DataOutputStream to write data to a stream by passing an OutputStream to a DataOutputStream object as a parameter when you create the object.
BufferedOutputStream
You use the BufferedOutputStream to write data to a buffer. This in turn writes it to the underlying stream.
PrintStream
A PrintStream allows other output streams to conveniently print data of various formats. This class never throws an IOException, unlike other output streams.
The methods of the DataOutputStream class process data, such as characters, integers, and UTF strings, convert it to bytes, and write it to the stream.
File f = new File (myFileName);
if(f.exists() && f.isFile() && f.canWrite()) {
  try {
    FileOutputStream fostream = 
    new FileOutputStream(f);
    DataOutputStream dostream =
    new DataOutputStream(fostream);
    
    dostream.writeUTF("Some UTF data");
    dostream.close();
    
    fostream.close();
  }
  catch (IOException e) {
  }
}

Supplement

Selecting the link title opens the resource in a new browser window.
View the DataInputStream and DataOutputStream methods.
Consider the code that creates a FileOutputStream object named fostream, and a DataOutputStream object named dostream.
File f = new File (myFileName);
if(f.exists() && f.isFile() && f.canWrite()) {
  try {
    FileOutputStream fostream = 
    new FileOutputStream(f);
    DataOutputStream dostream =
    new DataOutputStream(fostream);
    
    dostream.writeUTF("Some UTF data");
    dostream.close();
    
    fostream.close();
  }
  catch (IOException e) {
  }
}
In doing so, the code writes the DataOutputStream to the FileOutputStream. - fostream.
It passes a string as a parameter to the writeUTF method, which writes it to the output stream.
Finally, it closes the two streams in the correct order. This way, the one that was created last is closed first.
File f = new File (myFileName);
if(f.exists() && f.isFile() && f.canWrite()) {
  try {
    FileOutputStream fostream = 
    new FileOutputStream(f);
    DataOutputStream dostream =
    new DataOutputStream(fostream);
    
    dostream.writeUTF("Some UTF data");
    dostream.close();
    
    fostream.close();
  }
  catch (IOException e) {
  }
}

Low-level streams

When Java reads or writes data, it opens a data stream, reads or writes the information, and closes the stream.



Java uses the stream, reader, and writer classes for streamed data.
Stream classes deal with general data input and output, whereas the reader and writer classes deal specifically with Unicode and Unicode Transformation Format (UTF) string input and output.
Data received from or sent to general I/O devices consists of bytes. However, Java can support higher-level I/O by piecing together bytes to represent other types of data, such as integers, characters, or strings.
For example, a sequence of four bytes can make up an int.
Java uses a hierarchy of classes to deal with different types of data. The InputStream and OutputStream are abstract classes that use low-level I/O streams to read bytes from or send them to I/O devices such as files, network sockets, and pipes.
Low-level streams provide access directly to underlying bytes. High-level streams build upon low-level streams for additional capabilities.

The FilterInputStream and FilterOutputStream classes extend InputStream and OutputStream respectively. They use high-level filter streams to read or write data, such as strings and ints, from byte streams.
All low-level stream classes inherit from either the InputStream or OutputStream abstract classes.

Many stream input classes have a corresponding output class with similar methods. For example, the FileInputStream class, which is the input class for files, has a corresponding output class, FileOutputStream.
The low-level streams that are direct descendants of the InputStream or OutputStream include
  • ByteArrayInputStream and ByteArrayOutputStream
  • FileInputStream and FileOutputStream
  • ObjectInputStream and ObjectOutputStream
  • PipedInputStream and PipedOutputStream
  • SequenceInputStream
ByteArrayInputStream and ByteArrayOutputStream
The ByteArrayInputStream and ByteArrayOutputStream classes read and write arrays of bytes with buffering.
FileInputStream and FileOutputStream
The FileInputStream receives data from a file in byte form. The FileOutputStream outputs the data to a file.
ObjectInputStream and ObjectOutputStream
The ObjectInputStream deserializes primitive data and objects that have been previously serialized using an ObjectOutputStream object.
PipedInputStream and PipedOutputStream
The PipedInputStream and PipedOutputStream classes work with thread communication. They enable you to create and connect two sides of a stream.
SequenceInputStream
The SequenceInputStream class enables you to concatenate other input streams and to read from each of them, in turn.
The corresponding InputStream and OutputStream subclasses have complementary structures and functions, including
  • constructors
  • read and write methods
  • reading and writing arrays
constructors
The FileInputStream and FileOutputStream classes have similar constructors.

The syntax for the constructors is

FileInputStream(String pathname)
FileInputStream(File file)
FileOutputStream(String pathname)
FileOutputStream(File file)
read and write methods
The FileInputStream class uses the read method to read the next byte from a file. The FileOutputStream class uses the write method to write a byte to a file.

The syntax for these methods is

int read () throws IOException
void write (int <b>) throws IOException
reading and writing arrays
The FileInputStream and FileOutputStream classes have complementary read and write methods for reading and writing arrays of bytes.

The syntax for these methods is

int read(byte[] b)
int read(byte[] b, int off, int len)

void write(byte[] b)
void write(byte[] b, int off, int len)
Suppose you have code that reads information on sales from a file and prints it to the standard output. To do this, the code creates a DataInputStream. This class has an InputStream data member, which is inherited from FilterInputStream.
    for (int i = 0; i < descs.length; i ++) {
      myData = new SalesData (descs[i], amounts[i], values[i]) ;
      writeSalesData ( myData ) ;
    }
    out.close() ;


    // Prepare to read it in
    in = new DataInputStream(new FileInputStream(fruitfile)) ;

    for (int i=0; i<6; i++) {
      myData = readSalesData () ;
      System.out.println("You sold " +
      myData.desc + " at $" +
      myData.value + " each. Amount was " + myData.amount);
    }
    in.close() ;
  }
The DataInputStream object wraps a FileInputStream instance. This enables native datatypes to be read in a machine-independent fashion.
You can layer stream objects together to create streams capable of performing very specific I/O functions.

For example, you can extend FilteredInputStream to create custom filters that discriminately read formatted data. Your custom filter can, in turn, be chained to other streams.

The java.io.File class

Programs are required to write and read data to and from external sources - such as files, other programs, or network resources.

The Java Input/Output (I/O) package - java.io - enables Java programs to read and write data in various formats. Text, sound, graphics, and video files can be processed by appropriate classes from the java.io package.
The java.io package contains classes that enable you to access data both sequentially and at random.

Note

In sequential data access, data is read or written in sequence, from the first record to the last. Nonsequential or random - data access involves reading or writing data in a random order.
The Reader and Writer classes, and their various subclasses, are used for sequential data access. These classes input or output data sequentially as ordered streams of bytes.

The RandomAccessFile class and its subclasses are used to input or output data in a file. The bytes do not need to be in ordered sequences, as opposed to a stream.
The java.io.File class represents either a directory or a single file within the file system.It allows you to navigate, describe, and access those files or directories.
The Java security manager allows only specified operations to be performed within a given security context. Because most browsers don't allow any kind of file access, the File class and related I/O classes are usually used in applications instead of applets.
Creating a File object does not necessarily mean that you create a real file or directory. While representing the name of a file, the File object does not represent, or enable you to access, the data in the file.

Similarly, when a File object is deleted by the garbage collector, no physical files are deleted.
Creating a File object does not actually create a file on the local system. It merely encapsulates the specified string in one of a number of constructors:
  • File (File directoryObj, String fileName)
  • File (String pathName)
  • File (String pathName, String fileName)
File (File directoryObj, String fileName)
This constructor creates a new File instance using the pathname from an existing File instance and a string containing the filename.
File (String pathName)
This constructor creates a new File instance using the given pathname string.
File (String pathName, String fileName)
This constructor creates a new File instance using the given pathname string and filename string.
Consider the code that creates a simple file access application in Java. To access a file, you should first import the relevant Java classes – in this case File and RandomAccessFile, which are both part of the java.io package.
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SampleWriteFile implements ActionListener {"
The java.awt , java.awt.event, and javax.swing packages are imported to be able to utilize GUI components.
Once you have imported the relevant java.io classes, you need to instantiate the GUI components to be able to input names. These names are written to a RandomAccessFile named sampletext.txt.
public class SampleWriteFile  implements ActionListener {

  private Frame f;
  private Button write, clear, exit;
  private TextField txt;
  public SampleWriteFile(String s) {
    f=new Frame(s);
    write=new Button("Write to file");  write.addActionListener(this);
    clear=new Button("Clear entries");  clear.addActionListener(this);
    exit=new Button("Exit");  exit.addActionListener(this);
    txt=new TextField(20);  
    Label l=new Label("Enter name");
    Panel p=new Panel();
    Panel p2=new Panel();
    p.add(l);p.add(txt);
    p2.add(write);p2.add(clear);p2.add(exit);
    f.add(p, "North");
    f.add(p2);
    f.pack();
    f.setResizable(false); f.setVisible(true);  
  } 
In the RandomAccessFile instantiation, the rw option is used to be able to read and write data from the file.
public void writeFile() {
       try {
  RandomAccessFile file=new RandomAccessFile("sampletext.txt", "rw");
  file.seek(file.length());
  file.writeBytes(txt.getText()+ "\n");
      }
      catch(IOException e) {
  JOptionPane.showMessageDialog(null,"Cannot write to File","Exception",JOptionPane.ERROR_MESSAGE);
}
The seek method is used to get to a specific location in the file. The value returned by the length method is passed to the seek method, so that we can get to the end of the specified file.
The writeBytes method is used to write data coming from the text field into the file named SampleText.txt.

Supplement

Selecting the link title opens the resource in a new browser window.
View the code for the SampleWriteFile application.
There are 12 methods you can use on a File object. These include
  • exists
  • getName
  • getAbsolutePath
  • isDirectory
  • isFile
  • canRead
exists
You use the exists method to confirm whether a specified file exists. The method returns a value of true if the file exists.
getName
You use the getName method to return the name of a file or directory - the last element of a full pathname.
getAbsolutePath
The getAbsolutePath method returns a String value, which is the full absolute path to a file or directory, whether the file was initially constructed using a relative pathname or not.
isDirectory
The isDirectory method returns a value of true if the string specified in the object's constructor represents a directory instead of a file.
isFile
The isFile method determines whether a File object represents a file or a directory. The method returns a boolean value of true if an abstract filename exists, and is a normal file - that is, the File object does not represent a directory. Otherwise it returns false. The MS Windows implementation of the isFile method has been reworked in JDK1.6. It is now always set to return false for devices such as CON, NUL, AUX, LPT, which makes it consistent with the UNIX implementation of isFile.
canRead
The canRead method determines whether data can be read from a file. It returns a boolean value of true only if the file exists and can be read by the application. Otherwise it returns false.
The remaining six methods are
  • getTotalspace
  • getFreespace
  • getUsablespace
  • setWritable
  • setExecutable
  • canExecute
getTotalspace
The getTotalspace method returns a long value representing the size in bytes of the partition named by the abstract path.
getFreespace
The getFreespace method returns a long value, which is the number of bytes available on the partition named by the abstract path. The value returned is a hint, and not a guarantee that all the bytes are usable. The number of unallocated bytes are most likely accurate after the call to gerFreespace. This method does not guarantee that write operations to the file system are successful.
getUsablespace
The getUsablespace method returns a long value, which is the number of bytes available on the partition named by the abstract path name.
setWritable
The setWritable method allows a particular file to be writeable and takes two parameters. The first parameter is a boolean value. If set to true, the file becomes writable, but if set to false, the file becomes read only. The second parameter is also a boolean value. If set to true, the write permission applies only to the owner or the creator of the file, but if set to false, the write permission applies to everybody.
setExecutable
The setExecutable method sets the execute permission of a file. It also takes two parameters. If the first parameter is set to true, the file is set to allow execute operations. If the second parameter is set to true, the execute permissions apply only to the owner or the creator of the file. If the second parameter is set to false, the execute permission is applied to everybody.
canExecute
The canExecute method returns a boolean value. If true is returned, the file can be executed.
Consider the code that uses the isDirectory method to determine whether an array element - a File instance - is a directory. If it is, the application searches it for a specified file.
class InnerActionListener implements
  ActionListener {
    public void actionPerformed (ActionEvent e) {
      ReportAction r = new ReportAction() ;                  
      r.setPriority(Math.min(r.getPriority() + 1,
            Thread.MAX_PRIORITY));
      r.start() ;
      
      File[] allDrives = File.listRoots();
      for (int i=1 ; i<allDrives.length-1; i++) {
              if (allDrives[i].isDirectory())
        answer.append (search(allDrives[i], "test.txt"));
      }
      r.interrupt() ;
    }
}
Suppose you want to create an instance of a File and use the most common methods associated with a File class. This application searches for files using a method that takes a File object and a search string as parameters. The File object represents the directory being searched.
String search (File f, String fileName) {
  String contents[] = f.list() ;
  int i = 0;
  String found = "Not found" ;

  for (i=0; i<contents.length; i++) {
    if (fileName.equals (contents[i]))
      return (new File(f, contents[i]).getAbsolutePath()) ;
  }
  i = 0 ;
  while (i < contents.length) & (found.equals ("Not found"))) {
    File child = new File (f, contents[i]) ;
    if (child.isDirectory())
      found = search (child, fileName);
    i++ ;
  }    
  return found ;
}
Java uses the File object's list method to return an array of Strings, listing the contents of a directory. If the File does not represent a directory, the list method returns a null value. This will cause the application to throw a NUllPointerException, which can be handled by using a try-catch block.
If one of the files in the directory matches the filename specified by the user, the method returns a string, representing the absolute path to the target file.

Painting Swing components

Painting GUI components

In Java, components are rendered on screen in a process known as painting. Although this is usually handled automatically, there are occasions when you need to trigger repainting, or modify the default painting for a component.



The core painting mechanism is based on the Abstract Windowing Toolkit (AWT). In newer versions of Java, Swing painting mechanisms are based on and extend the functionality of AWT mechanisms.
Components can be heavyweight or lightweight. A heavyweight component has its own native screen peer. For a lightweight component to exist there must be a heavyweight further up the containment hierarchy. So lightweight components are more efficient. Swing components tend to be lightweight.

Painting for lightweight and heavyweight components differs slightly.
Painting is triggered when a GUI element is launched or altered in any way. This can be caused by
  • a system event
  • an application event
a system event
System-triggered painting operations are caused when a system requests a component to be rendered onscreen for the first time, resized, or repaired.

If you open the Save As window in an application, then a system request is triggered.
an application event
Application-triggered painting events occur when the internal state of an application changes and requires components to be updated.

For example, if an item is selected, the application might send a request for the item to be highlighted.
Painting in AWT
When a paint request is triggered, AWT uses a callback mechanism to paint the lightweight and heavyweight components of a GUI.

You should place the code for rendering the component in the relevant overriding paint method of the java.awt.Component class. The method is invoked whenever a system or application request is triggered.
public void paint(Graphics g)
The paint method is not invoked directly. Instead, you call the repaint method to schedule a call to paint correctly.

The Graphics object parameter is pre-configured with the state required to draw and render a component. The Graphic parameter can be reconfigured to customize painting.

public void repaint()
public void repaint(long tm)
public void repaint(int x, int y, int width, int height)
public void repaint(long tm, int x, int y,
  int width, int height)

For complex components, you should specify the region to be rendered using the arguments of the repaint method. The updated region is referred to as the clip rectangle.

The whole component is repainted if no arguments are given.

public void repaint()
public void repaint(long tm)
public void repaint(int x, int y, int width, int height)
public void repaint(long tm, int x, int y,
  int width, int height)

You can use an overridden update method to handle application-triggered painting differently from system-triggered painting.

For application-triggered paint operations, AWT calls the update method. If the component doesn't override the update() method, the default update method paints heavyweight components by clearing the background and calling the paint method.

The process of updating specified areas of a component is known as incremental painting. Incremental painting is not supported by lightweight components.
Consider the code that is used to refresh the applet when a user types text. You first create the ke instance to represent the event of typing a key.

public void keyTyped(keyEvent ke) {
  msg += ke.getKeyChar();
  repaint();
}

You call the ke instance's getKeyChar method to determine the value of the typed key. You assign the value to a variable - msg in this case - using the += overloaded operator.

You then call the repaint method, which in turn calls the overridden paint method. The value of the key typed - msg - is passed to the paint method and the key character is painted onscreen.


Painting in Swing
Painting Swing components is based on the AWT callback method, so it supports the paint and repaint methods. Swing painting also extends the functionality of paint operations with a number of additional features.

The Swing API, RepaintManager, can be used to customize the painting of Swing components. In addition, Swing painting supports Swing structures, such as borders and double-buffering.

Double-buffering is supported by default. Removing double-buffering is not recommended.
Because lightweight components are contained within heavyweight components, the painting of lightweight components is triggered by the paint method of the heavyweight component.
When the paint method is called, it is translated to all lightweight components using the java.awt.Container class's paint method. This causes all defined areas to be repainted.
There are three customized callbacks for Swing components, which factor out a single paint method into three subparts. These are
  • paintComponent()
  • paintBorder()
  • paintChildren()
paintComponent()
You use the paintComponent method to call the UI delegate object's paint method. The paintComponent method passes a copy of the Graphics object to the UI delegate object's paint method. This protects the rest of the paint code from irrevocable changes.

You cannot call the paintComponent method if UI delegate is set to null.
paintBorder()
You use the paintBorder method to paint a component's border.
paintChildren()
You use the paintChildren method to paint a component's child components.
You need to bear several factors in mind when designing a Swing paint operation.

Firstly, application-triggered and system-triggered requests call the paint or repaint method of a Swing component, but never the update method. Also, the paint method is never called directly. You can trigger a future call to it by invoking the repaint method.

As with AWT components, it is good practice to define the clip rectangle using the arguments of the repaint method. Using the clip rectangle to narrow down the area to be painted makes the code more efficient.

You can customize the painting of Swing components using two properties, namely
  • opaque
  • optimizedDrawingEnabled
opaque
You use the opaque property to clear the background of a component and repaint everything contained within the paintComponent method. To do this, opaque must be set to true, which is the default. Setting opaque to true reduces the amount of screen clutter caused by repainting a component's elements.
optimizedDrawingEnabled
The optimizedDrawingEnabled property controls whether components can overlap. The default value of the optimizedDrawingEnabled property is true.
Setting either the opaque or the optimizedDrawingEnabled property to false is not advised unless absolutely necessary, as it causes a large amount of processing.

You use the paintComponent method for Swing component extensions that implement their own paint code. The scope of these component extensions need to be set in the paintComponent method.

The paintComponent method is structured in the same way as the paint method.

// Custom JPanel with overridden paintComponent method
class MyPanel extends JPanel {
 
public MyPanel(LayoutManager layout) {
  super (layout) ;
}
 
public void paintComponent(Graphics g) {
  // Start by clearing the current screen
  g.clearRect( getX(), getY(), getWidth(), getHeight()) ;
  g.setColor (Color.red) ;
  int[] x = {30, 127, 56, 355, 240, 315 } ;
  int[] y = {253, 15, 35, 347, 290, 265} ;
  //Draw complex shape on-screen and fill it
  g.drawPolygon (x, y, 5) ;
  g.fillPolygon (x, y, 5) ;
  }
}

Summary

Painting is the process of rendering components onscreen. Heavyweight components have matching native peers, whereas lightweight components rely on a heavyweight container to do their painting. Painting is triggered by requests. System-triggered requests occur when windows are launched, resized, or repaired. Application-triggered requests occur when the internal state of an application changes.

AWT uses a callback method to invoke an overridden version of the paint method of the java.awt.Component class. You define the area that requires painting, the clip rectangle, using the arguments of the repaint method. You can also override the update method for application-triggered paint operations.

Swing painting is based on AWT painting and then adds further functionality. Heavyweight containers translate the paint method to all the lightweight components contained within them. Swing painting has three customized callbacks and two properties that you use to customize the Swing painting operation.