javaIO流

1.     Abstract:

Java将I/O分为高阶I/O与低阶I/O,高阶I/O在使用上提供更多的读写方法,如读写 int、double、String的资料型态,而低阶的I/O大部份只提供write、read的byte[]存取,因为程式大部份的资料都是以字串或 其它主要型态资料来运算,因此低阶的I/O在使用上不利於程式设计,所以Java将许多好用的方法全部集合成高阶I/O; 换言之,低阶I/O的主要工作是负责与媒体资料作存取,高阶I/O类别主要作资料型态的转换及提供一些特殊的功能。在使用Java I/O时要谨记的一个重要原则是,在建立一个I/O之前必需先用低阶I/O类别来存取媒体资料(如档案或pipe),之後再使用高阶I/O来控制低阶 I/O类别的动作,这种一层又一层的架构称I/O Chain。底下为Java的I/O架构图,第一个为以byte为单位的I/O,第二个则是以char为单位。

2.     File I/O:

A.     FileInputStream & FileOutputStream

FileInputStream是读取档案用的类别,其建构式有叁个:

public FileInputStream(String strFilename) throws FileNotFoundException

public FileInputStream(File fIn) throws FileNotFoundException

public FileInputStream(FileDescriptor fdObj)

   在这里我只讲第一个,这是最直觉的方式,如下的范例1,会一次从e:\test.txt读10个bytes,将读入的结果输出到标准输出设备,直到档案结 束。在这个范例中要注意的是,available会传回输入串流中还有多少个bytes,read则会根据buffer的大小来决定一次读几个 bytes,并将实际读到的byte数传回。

===== 范例 1 =====

import java.io.*;

public class FIn {

public FIn() {

    try {

      FileInputStream fis = new FileInputStream("e:/in.txt");

      while (fis.available() > 0) {

        byte[] b = new byte[10];

        int nResult = fis.read(b);

        if (nResult == -1) break;

        System.out.println(new String(b));

      }

      fis.close();

    }

    catch (IOException e) {

      e.printStackTrace();

    }

}

public static void main(String[] args) {

    FIn fIn = new FIn();

}

}

        FileOutputStream是写入档案用的类别,其建构式有四个:

                Public FileOutputStream(String strFilename) throws FileNotFoundException

                Public FileOutputStream(File fOut) throws FileNotFound Exception

                Public FileOutputStream(FileDescriptor fdObj)

public FileOutputStream(String name, boolean append) throws FileNotFoundException

        第四个和第一个的差别只在於当档案存在时,第一个会将原来的档案内容覆盖,第四个则可以选择覆盖或将新内容接在原内容後面。范例2以建构式一讲解如何写入 一个档案…在这个范例中要注意的是,fIn每个读10个bytes,但是最後一次不一定会读10个bytes,因此,fOut在write时,要指明要写 几个bytes到档案中,否则最後一次仍会写入10个bytes,因Java在new byte时会先将内容先填0,所以後面的几个bytes会是0。

===== 范例2 =====

import java.io.*;

public class FOut {

public FOut() {

    try {

      FileInputStream fIn = new FileInputStream("e:/in.txt");

      FileOutputStream fOut = new FileOutputStream("e:/out.txt");

      while (fIn.available() > 0) {

        byte[] b = new byte[10];

        int nResult = fIn.read(b);

        if (nResult == -1) break;

        fOut.write(b, 0, nResult);

      }

      fIn.close();

      fOut.close();

    }

    catch (IOException e) {

      e.printStackTrace();

    }

}

public static void main(String[] args) {

    FOut FOut1 = new FOut();

}

}

B.     FileReader & FileWriter

FileReader 和FileInputStream最大不同在於,FileInputStream读取的单位是byte,FileReader读取的单位是char。另外 要注意的是,在FileInputStream中以available来判断是否还有资料可读取,在FileReader中是以ready来判断,

但是,available是传回还有多少个bytes可以读取,ready则传回true或false,当传回true时表示,下次read时保证不会停顿,当传回false时,表示下次read时”可能”停顿,所谓可能是指不保证不会停顿。

Ps. 测试时,in.txt里放些中文字就可以看出以byte和以char为单位有什麽不同。

===== 范例 3 =====

import java.io.*;

public class chFIn {

public chFIn() {

    try {

      FileReader rdFile = new FileReader("e:/in.txt");

      while (rdFile.ready()) {

        char[] chIn = new char[10];

        int nResult = rdFile.read(chIn);

        if (nResult == -1) break;

        System.out.println(chIn);

      }

rdFile.close();

    }

    catch (IOException e) {

      e.printStackTrace();

    }

}

public static void main(String[] args) {

    chFIn chFIn1 = new chFIn();

}

}

        FileWriter和FileOutputStream的最大不同也在於写入单位的不同,FileOutputStream为byte,FileWriter为char。

===== 范例 4 =====

import java.io.*;

public class chFOut {

public chFOut() {

    try {

      FileReader rdFile = new FileReader("e:/in.txt");

      FileWriter wrFile = new FileWriter("e:/out.txt");

      while (rdFile.ready()) {

        char[] chIn = new char[10];

        int nResult = rdFile.read(chIn);

        if (nResult == -1) break;

        wrFile.write(chIn, 0, nResult);

      }

      rdFile.close();

      wrFile.close();

    }

    catch (IOException e) {

      e.printStackTrace();

    }

}

public static void main(String[] args) {

    chFOut chFOut1 = new chFOut();

}

}

C.     BufferedReader & BufferedWriter

File I/O是相当耗时的作业,通常电脑在做处理时,者会建立一个缓冲区,一次读取或写入一个区块,借由减少I/O次数,来节省时间 ,在Java中的BufferedReader和BufferedWriter就是提供这样的缓冲功能。

在 范例5中,我们将FileReader导向BufferedReader,将FileWriter导向BufferedWriter,来达到区块读取、写 入的目的。BufferedReader提供的readLine一次可以读取一行,当遇到档尾时,会传回null。BufferedWriter提供的 newLine会产生列尾符号,这个列尾符号随作业系统的不同而不同,在Windows上为\r\n,在Unix上为\n,在Mac上为\r,这个符号是 依据line.separator系统性质而来的。需注意的是,如果将BufferedWriter应用到网路程式时,绝对不要使用newLine,因为 绝大多数的网路协定都是以\r\n为列尾,不会因作业系统不同而异。

===== 范例 5 =====

import java.io.*;

public class bufIn {

public bufIn() {

    try {

      FileReader rdFile = new FileReader("e:/in.txt");

      BufferedReader brdFile = new BufferedReader(rdFile);

       FileWriter wrFile = new FileWriter("e:/out.txt");

      BufferedWriter bwrFile = new BufferedWriter(wrFile);

      String strLine;

      while ((strLine = brdFile.readLine()) != null) {

        bwrFile.write(strLine);

        bwrFile.newLine();

      }

      brdFile.close();

      bwrFile.close();

    }

    catch (IOException e) {

      e.printStackTrace();

    }

}

public static void main(String[] args) {

    bufIn bufIn1 = new bufIn();

}

}

D.     File

在档案处理方面,程式不只是要对档案做读、写,有时也需要得知档案的属性,或删除、移动、更名,有时则是要找出或列出某目录下的某些档案,针对这些运作,Java提供了File这个类别。底下的范例,说明如何使用File类别。

a.       如何得知档案属性:

在 范例6中需注意的是lastModified传回的最後更改时间是自1970/1/1 00:00:00算起的时间,单位为毫秒,所以要用Date将它转换成日期、时间; 另外getCanonicalPath和getAbsolutePath得到的值在Windows上会是一样的,在Unix可能就会不一样。

===== 范例 6 =====

import java.io.*;

import java.util.*;

public class FileSpy {

public FileSpy(String strFilename) {

    File fFile = new File(strFilename);

    if (fFile.exists()) {

      System.out.println("Name: " + fFile.getName());

      System.out.println("Absolute path: " + fFile.getAbsolutePath());

      try {

        System.out.println("Canonical path: " + fFile.getCanonicalPath());

      }

      catch (IOException e) {

        e.printStackTrace();

      }

      if (fFile.canWrite()) System.out.println(fFile.getName() + " is writable");

      if (fFile.canRead()) System.out.println(fFile.getName() + " is readable");

      if (fFile.isFile()) {

        System.out.println(fFile.getName() + " is a file");

      }

      else if (fFile.isDirectory()) {

        System.out.println(fFile.getName() + " is a directory");

      }

      else {

        System.out.println("What is this?");

      }

      long lngMilliseconds = fFile.lastModified();

      if (lngMilliseconds !=0) System.out.println("last modified at " + new Date(lngMilliseconds));

      long lngLen = fFile.length();

      if (lngLen !=0) System.out.println("size: " + lngLen);

    }

    else

      System.out.println("file not found");

}

public static void main(String[] args) {

    if (args.length == 1) {

      FileSpy fileSpy1 = new FileSpy(args[0]);

    }

    else

      System.out.println("Usage: java FileSpy Filename");

}

}

b.      建立、删除、移动、更名:

File 类别提供了createNewFile、renameTo、delete作为建立(createNewFile)、删除(delete)、移动、更名 (renameTo)之用,使用方式如下: (移动和更名都用renameTo,就如在Unix上档案搬移和更名都用mv一样)

===== 范例 7 =====

import java.io.*;

public class OperateFile {

public OperateFile() {

    //create new file

    File fNewFile = new File("C:/newfile.txt");

    try {

      if (fNewFile.exists() == false) {

        if (fNewFile.createNewFile() == true) {

          System.out.println("create c:/newfile.txt success");

        }

        else {

          System.out.println("create c:/newfile.txt fail");

        }

      }

      else {

        System.out.println("file already exists");

      }

    }

    catch (IOException e) {

      e.printStackTrace();

    }

//rename file

    File fRenameFile = new File("c:/renamefile.txt");

    fNewFile.renameTo(fRenameFile);

    //remove file

    File fRemoveFile = new File("d:/" + fRenameFile.getName());

    fRenameFile.renameTo(fRemoveFile);

    //delete file

    try {

      File fDelFile = new File(fRemoveFile.getCanonicalPath());

      fDelFile.delete();

    }

    catch (IOException e) {

      e.printStackTrace();

    }

}

public static void main(String[] args) {

    OperateFile operateFile1 = new OperateFile();

}

}

c.       找出某特定目录里的所有档案:

File类别提供的list和listFiles都可以列出某特定目录里的所有档案,其中list传回的是String[],listFiles传回的是File[],这两个函式都会传回所有的档案和目录。

===== 范例 8 =====

import java.io.*;

public class ListAllFiles {

public ListAllFiles(String strDir) {

    File fDir = new File(strDir);

    File[] fAllFiles = fDir.listFiles();

    for(int i=0; i

      if (fAllFiles.isFile())

        System.out.println("File: " + fAllFiles.getName());

      else

        System.out.println("Dir: " + fAllFiles.getName());

    }

}

public static void main(String[] args) {

    ListAllFiles listAllFiles1 = new ListAllFiles(args[0]);

}

}

3.     Network I/O:

Java对网路的支援只有TCP/IP和UDP/IP,提供的类别有URL、URLConnection、Socket、ServerSocket,在这里我只打算用ServerSocket、Socket为例,来说明Network I/O。

基本上,Java的I/O不管在任何的媒体上都是将它们视为stream,所以,网路I/O和档案I/O原理也是一致的,底下的两个程式分别为server socket及client socket。在看范例之前,可以再复习一下前面的abstract…

===== 范例 9 =====

import java.net.*;

import java.io.*;

public class myServer {

public myServer(String strPort) {

    int nPort = new Integer(strPort).intValue();

    try {

      ServerSocket ss = new ServerSocket(nPort);

      Socket s = ss.accept();

      OutputStream out = s.getOutputStream();

      PrintStream psOut = new PrintStream(out);

      String strResponse = "Hello " + s.getInetAddress() + " on port " + s.getPort() + "\r\n";

      strResponse += "This is " + s.getLocalAddress() + " on port " + s.getLocalPort() + "\r\n";

      psOut.print(strResponse);

      s.close();

      ss.close();

    }

    catch (IOException e) {

      e.printStackTrace();

    }

}

public static void main(String[] args) {

    myServer myServer1 = new myServer(args[0]);

}

}

===== 范例 10 =====

import java.net.*;

import java.io.*;

public class myClient {

public myClient(String strIP, String strPort) {

    int nPort = new Integer(strPort).intValue();

    try {

      Socket s = new Socket(strIP, nPort);

      InputStream in = s.getInputStream();

      BufferedInputStream bisIn = new BufferedInputStream(in);

      while (bisIn.available() > 0) {

        byte[] b = new byte[30];

        int nLen = bisIn.read(b);

        System.out.println(new String(b, 0, nLen));

      }

    }

    catch (UnknownHostException e) {

      e.printStackTrace();

    }

    catch (IOException e) {

      e.printStackTrace();

    }

}

public static void main(String[] args) {

    myClient myClient1 = new myClient(args[0], args[1]);

}

}

4.     Object Serialization:

A.     所谓Object Serialization就是把物件的”状态”储存成一系列的位元组,而这些位元组在稍候可用来恢复物件。更简单的说,Object Serialization是让物件可以以物件为储存单位。在Java中,任何物件要能Serialization,必须implements Serializable这个Interface,以下是一个简单的程式范例,可以将物件储存到e:\point.ser,或从e:\point.ser 将物件恢复原值。

===== 范例 11 =====

import java.io.*;

public class ThreeDPoint implements Serializable

{

private double m_dblX, m_dblY, m_dblZ;

public ThreeDPoint(double x, double y, double z)

{

    m_dblX = x;

    m_dblY = y;

    m_dblZ = z;

}

public void PrintXYZ()

{

    System.out.println("X: " + m_dblX);

    System.out.println("Y: " + m_dblY);

    System.out.println("Z: " + m_dblZ);

}

public static void main(String[] args)

{

    if (args[0].equalsIgnoreCase("w")) {

      ThreeDPoint threeDPoint1 = new ThreeDPoint(10 ,20, 30);

      try {

        FileOutputStream fout = new FileOutputStream("e:\\point.ser");

        ObjectOutputStream oout = new ObjectOutputStream(fout);

        oout.writeObject(threeDPoint1);

        oout.close();

         System.out.println("write:");

        threeDPoint1.PrintXYZ();

      }

      catch (Exception e) {

        e.printStackTrace();

      }

    }

    else if (args[0].equalsIgnoreCase("r")) {

      try {

        FileInputStream fin = new FileInputStream("e:\\point.ser");

        ObjectInputStream oin = new ObjectInputStream(fin);

        Object o = oin.readObject();

        ThreeDPoint threeDPoint1 = (ThreeDPoint) o;

        oin.close();

        System.out.println("read:");

        threeDPoint1.PrintXYZ();

      }

      catch (Exception e) {

      }

    }

} //end of main

}

B.     在Java中,一个实作某特定介面的类别,其子类别也因继承的原故而被视为实作了该介面,因此,许多没有明确宣告实作Serializable介面的类别,事实上也是可以被Serialization的。

C.     并非每个实作了Serializable介面的物件都可以被Serialization,如果这个物件继承图上的祖先,有其中一个是不可以被Serialization,那麽这个物件就不可以被Serialization。

5.     Formated I/O:

在Java 的I/O里,并没有所谓的型别,不管是int、long、double…最後都是以String输出,所以如果要让数字以特定格式输出,需透过Java提 供的两个类别java.text.NumberFormat和java.text.DecimalFormat将数字格式化後再输出。

范例12简 要说明NumberFormat如何使用,在开始使用NumberFormat时,应先用getInstance取得NumberFormat的实体,范 例12中的setMaximumIntegerDigits和setMinimumFractionDigits是用来设定整数和小数的位数,另外还有 setMinimumIntegerDigits和setMaximumFractionDigits也是同样功能。这些设定如有冲突,Java以最後设 定的为准。

===== 范例 12 =====

import java.text.*;

public class myFormat {

public myFormat() {

    NumberFormat nf = NumberFormat.getInstance();

    double dblNum = Math.PI;

   System.out.println(dblNum);

    nf.setMaximumIntegerDigits(5);

    nf.setMinimumFractionDigits(4);

    System.out.println("PI: " + nf.format(dblNum));

}

public static void main(String[] args) {

    myFormat myFormat1 = new myFormat();

}

}

另 一个类别DecimalFormat是继承NumberFormat的子类别,它提供了更强的格式化功能,透过设定pattern,可以使我们的输出更多 样化,至於Java提供的pattern有那些? 在API Document中有详细说明! 范例13仅举其一,说明DecimalFormat如何使用。

===== 范例 13 =====

import java.text.*;

public class myDecimalFormat {

public myDecimalFormat() {

    DecimalFormat df = new DecimalFormat("0000.000");

    double dblNum = 123.45;

    System.out.println("dblNum: " + dblNum);

    System.out.println("dblNum: " + df.format(dblNum));

}

public static void main(String[] args) {

    myDecimalFormat myDecimalFormat1 = new myDecimalFormat();

}

}

阅读(5388) |  评论(0)

你可能感兴趣的:(javaIO流)