第十五章

資訊流


15.1 資訊流

兩種儲存資料的方式

  注意: 本章討論的類別都在 java.io.

文字格式

二進格式

從磁碟檔讀取文字資料

從磁碟讀一字元的程式碼

FileReader reader = new FileReader ("input.txt");
int next = reader.read()
char c;
if (next != -1)
   c = (char)next();

   ...

reader.close()

寫一字元到磁碟的程式碼

FileWriter writer = new FileWriter("output.txt");
  ...
char c='';
  ...
writer.write(c);
  ...
write.close();

從磁碟檔讀取二進資料

從磁碟讀一位元的程式碼


FileInputStream inputStream = new FileInputStream("input.dat");
int next = inputStream.read();
byte b;
if (next != -1)
   b = (byte)next;

      ...

inputStream.close();

寫一位元到磁碟的程式碼


FileOutputStream output = new FileOutputStream("output.txt");
  ...
byte b = 0;
  ...
output.write(b);
  ...
write.close();

15.2 文字檔的讀寫

寫文字檔

讀文字檔

15.3 File Dialogs

File 類別

JFileChooser 對話視窗

使用 JFileChooser 讓使用者得以透過檔案對話視窗提供檔案名稱

使用 JFileChooser 的程式碼


JFileChooser chooser new JFileChooser();
FileReader in = null;
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
{
    File selectedFile = chooser.getSelectedFile();
    in = new FileReader(selectedFile);
}

  注意: JFileChooser 類別在 java.io.

15.4 Encryption

To encrypt a file means to scramble it so that it is readable only to those who know the encryption method and the secret keyword.

To use Caesar cipher

Caesar Cipher

To Encrypt Binary Data


int next - in.read();
if (next == -1)
   done = true;
else
{
   byte b = (byte)next;
   byte c = encrypt(b);    //call the method to encrypt the byte
   out.write(c)
}

File Encryptor.java


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;

/**
   An encryptor encrypts files using the Caesar cipher.
   For decryption, use an encryptor whose key is the
   negative of the encryption key.
*/
public class Encryptor
{
   /**
      Constructs an encryptor.
      @param aKey the encryption key
   */
   public Encryptor(int aKey)
   {
      key = aKey;
   }

   /**
      Encrypts the contents of a file.
      @param inFile the input file
      @param outFile the output file
   */
   public void encryptFile(File inFile, File outFile)
      throws IOException
   {
      InputStream in = null;
      OutputStream out = null;

      try
      {
         in = new FileInputStream(inFile);
         out = new FileOutputStream(outFile);
         encryptStream(in, out);
      }
      finally
      {
         if (in != null) in.close();
         if (out != null) out.close();
      }
   }

   /**
      Encrypts the contents of a stream.
      @param in the input stream
      @param out the output stream
   */
   public void encryptStream(InputStream in, OutputStream out)
      throws IOException
   {
      boolean done = false;
      while (!done)
      {
         int next = in.read();
         if (next == -1) done = true;
         else
         {
            byte b = (byte)next;
            byte c = encrypt(b);
            out.write(c);
         }
      }
   }

   /**
      Encrypts a byte.
      @param b the byte to encrypt
      @return the encrypted byte
   */
   public byte encrypt(byte b)
   {
      return (byte)(b + key);
   }

   private int key;
}


File EncrytorTest.java


import java.io.File;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

/**
   A program to test the Caesar cipher encryptor.
*/
public class EncryptorTest
{
   public static void main(String[] args)
   {
      try
      {
         JFileChooser chooser = new JFileChooser();
         if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) System.exit(0);

         File inFile = chooser.getSelectedFile();
         if (chooser.showSaveDialog(null) != JFileChooser.APPROVE_OPTION) System.exit(0);
         File outFile = chooser.getSelectedFile();
         String input = JOptionPane.showInputDialog("Key");
         int key = Integer.parseInt(input);
         Encryptor crypt = new Encryptor(key);
         crypt.encryptFile(inFile, outFile);
      }
      catch (NumberFormatException exception)
      {
         System.out.println("Key must be an integer: " + exception);
      }
      catch (IOException exception)
      {
         System.out.println("Error processing file: " + exception);
      }
      System.exit(0);
   }
}




15.5 Command Line Arguments

 

Example of Command Line Arguments

Java MyProgram -d file.txt

class MyProgram
{
   public static void main(String[] args)
   {
      ...
   }
}
args[0] "-d"
args[1] "file.txt"

 

File Crypt.java


import java.io.File;
import java.io.IOException;

/**
   A program to run the Caesar cipher encryptor with
   command line arguments.
*/
public class Crypt
{
   public static void main(String[] args)
   {
      boolean decrypt = false;
      int key = DEFAULT_KEY;
      File inFile = null;
      File outFile = null;

      if (args.length < 2 || args.length > 4) usage();

      try
      {
         for (int i = 0; i < args.length; i++)
         {
            if (args[i].charAt(0) == '-')
            {
               // it is a command line option
               char option = args[i].charAt(1);
               if (option == 'd')
                  decrypt = true;
               else if (option == 'k')
                  key = Integer.parseInt(args[i].substring(2));
            }
            else
            {
               // it is a file name
               if (inFile == null)
                  inFile = new File(args[i]);
               else if (outFile == null)
                  outFile = new File(args[i]);
               else usage();
            }
         }
         if (decrypt) key = -key;
         Encryptor crypt = new Encryptor(key);
         crypt.encryptFile(inFile, outFile);
      }
      catch (NumberFormatException exception)
      {
         System.out.println("Key must be an integer: " + exception);
      }
      catch (IOException exception)
      {
         System.out.println("Error processing file: " + exception);
      }
   }

   /**
      Prints a message describing proper usage and exits.
   */
   public static void usage()
   {
      System.out.println
         ("Usage: java Crypt [-d] [-kn] infile outfile");
      System.exit(1);
   }

   public static final int DEFAULT_KEY = 3;
}


15.6 物件資訊流

Reading a Coin Object from a File


ObjectInputStream in = new ObjectInputStream(new FilInputStream("coins.dat"));
Coin c = (Coin)in.readObject();

Write and Read an ArrayList to a File

Write

ArrayList a = new ArrayList();
//add many objects to the array list
out.writeObject(a);

Read

ArrayList a = (ArrayList)in.readObject();

Serializable


class Coin implements Serializable
{
   ...
}

File PurseTest.java


import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.swing.JOptionPane;

/**
   This program tests serialization of a Purse object.
   If a file with serialized purse data exists, then it is
   loaded. Otherwise the program starts with a new purse.
   More coins are added to the purse. Then the purse data
   are saved.
*/
public class PurseTest
{
   public static void main(String[] args)
      throws IOException, ClassNotFoundException
   {
      Purse myPurse;

      File f = new File("purse.dat");
      if (f.exists())
      {
         ObjectInputStream in = new ObjectInputStream
            (new FileInputStream(f));
         myPurse = (Purse)in.readObject();
         in.close();
      }
      else myPurse = new Purse();

      // add coins to the purse
      myPurse.add(new Coin(NICKEL_VALUE, "nickel"));
      myPurse.add(new Coin(DIME_VALUE, "dime"));
      myPurse.add(new Coin(QUARTER_VALUE, "quarter"));

      double totalValue = myPurse.getTotal();
      System.out.println("The total is " + totalValue);

      ObjectOutputStream out = new ObjectOutputStream
         (new FileOutputStream(f));
      out.writeObject(myPurse);
      out.close();
   }

   private static double NICKEL_VALUE = 0.05;
   private static double DIME_VALUE = 0.1;
   private static double QUARTER_VALUE = 0.25;
}


15.7 Random and Sequential Access

RandomAccessFile

File BankDataTest.java


import java.io.IOException;
import java.io.RandomAccessFile;
import javax.swing.JOptionPane;

/**
   This program tests random access. You can access existing
   accounts and add interest, or create a new accounts. The
   accounts are saved in a random access file.
*/
public class BankDataTest
{
   public static void main(String[] args)
      throws IOException
   {
      BankData data = new BankData();
      try
      {
         data.open("bank.dat");

         boolean done = false;
         while (!done)
         {
            String input = JOptionPane.showInputDialog(
               "Account number or " + data.size()
               + " for new account");
            if (input == null) done = true;
            else
            {
               int pos = Integer.parseInt(input);

               if (0 <= pos && pos < data.size()) // add interest
               {
                  SavingsAccount account = data.read(pos);
                  System.out.println("balance="
                     + account.getBalance() + ",interest rate="
                     + account.getInterestRate());
                  account.addInterest();
                  data.write(pos, account);
               }
               else // add account
               {
                  input = JOptionPane.showInputDialog("Balance");
                  double balance = Double.parseDouble(input);
                  input = JOptionPane.showInputDialog("Interest Rate");
                  double interestRate = Double.parseDouble(input);
                  SavingsAccount account
                     = new SavingsAccount(interestRate);
                  account.deposit(balance);
                  data.write(data.size(), account);
               }
            }
         }
      }
      finally
      {
         data.close();
         System.exit(0);
      }
   }
}

File BankData.java


import java.io.IOException;
import java.io.RandomAccessFile;

/**
   This class is a conduit to a random access file
   containing savings account data.
*/
public class BankData
{
   /**
      Constructs a BankData object that is not associated
      with a file.
   */
   public BankData()
   {
      file = null;
   }

   /**
      Opens the data file.
      @param filename the name of the file containing savings
      account information.
   */
   public void open(String filename)
      throws IOException
   {
      if (file != null) file.close();
      file = new RandomAccessFile(filename, "rw");;
   }

   /**
      Gets the number of accounts in the file.
      @return the number of accounts.
   */
   public int size()
      throws IOException
   {
      return (int)(file.length() / RECORD_SIZE);
   }

   /**
      Closes the data file.
   */
   public void close()
      throws IOException
   {
      if (file != null) file.close();
      file = null;
   }

   /**
      Reads a savings account record.
      @param n the index of the account in the data file
      @return a savings account object initialized with the file data
   */
   public SavingsAccount read(int n)
      throws IOException
   {
      file.seek(n * RECORD_SIZE);
      double balance = file.readDouble();
      double interestRate = file.readDouble();
      SavingsAccount account = new SavingsAccount(interestRate);
      account.deposit(balance);
      return account;
   }

   /**
      Writes a savings account record to the data file
      @param n the index of the account in the data file
      @param account the account to write
   */
   public void write(int n, SavingsAccount account)
      throws IOException
   {
      file.seek(n * RECORD_SIZE);
      file.writeDouble(account.getBalance());
      file.writeDouble(account.getInterestRate());
   }

   private RandomAccessFile file;

   public static final int DOUBLE_SIZE = 8;
   public static final int RECORD_SIZE
      = 2 * DOUBLE_SIZE;
}