文件是计算机对信息的存储组织形式,使用计算机,不可能不与文件打交道,显然,作为程序开发者,对于与文件的交互的开发具有重要的意义。
    输入和输出是一个程序重要的功能,Java的应用程序和Java Applet往往经常要通过输入和输出来读写数据。
    在Java中,我们其实可以从两个方面来看,输入——需要 "数据源",输出——需要 "目标",而且,Java中似乎都是以字节流序列的流来对待。
    事实上,Java中所有的IO机制都是基于数据流的!
    1  流的概念
    Java所有的I/O机制都是基于数据流的,这些数据流表示了字符或者字节数据的流动序列。
    流是一个很形象的概念,当程序需要读取数据时,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接,则这就是“输入流”,(注意:开启数据源,事实上,下文要写入时,也要先开启目的地)。类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流,这就是“输出流”,这时你就可以想像数据好像在这其中“流”动一样。
    Java中的流分为两种:
    一种是字节流,另一种是字符流
    分别由四个抽象类来表示(每种流包括输入和输出各两种,所以一共四个):
    InputStream    OutputStream    Reader    Writer
    2  Java的I/O库
    Java中的字节流是用于处理字节的输入和输出的,包括读写二进制数据等方面的内容。
        InputStream  OutputStream
    而Java中的字符流则用于处理字符的输入和输出, 采用的是Unicode编码(这点比C/C++改进了,C/C++中采用的是ASCII码,因此,在其中时,字符是1个字节,而在这里,Unicode编码,一个字符是两个字节,这样,所有的文字都可以表示了),可以实现国际化。
     

Reader  Writer 

     (1)InputStream 

         1)abstract int read() 

         2)int read(byte[] b) 

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

         4)long skip(long n) 

         5)int available() 

         6)void close() 

         7)void mark(int readlimit) 

         8)void reset() 

         9)boolean markSupported() 

     (2)OutputStream 

         1)abstract void write(int b) 

         2)void write(byte[] b) 

         3)void write(byte[] b,int off,int len) 

         4)void close() 

         5)void flush() 

     (3)Reader Writer 

         public abstract int read() throws IOException 

         public abstract void write() throws IOException


    基本流
    1. 键盘输入和格式化输出
    它有3个内置的标准流对象,它们是:
        1)标准输入流System.io:用于程序的输入,通常用来读取用户从键盘的输入。
        2)标准输出流System.out:用于程序的输出,通常用来在屏幕上显示信息。
        3)标准出错流System.err:用于显示出错信息。
    <1>.基本的键盘输入
    (1)方法一:使用System.in对象的方法read()来读取键盘的输入 见例10。1
    (2)方法二:可以通过java.io包中提供的流类接收键盘的输入  见例10。2

    (3)可以通过控制台类Console类来实现从键盘输入;控制台类Console不属于Java的标准类库,它属于corejava包  见例10。3

         下面的程序,我在Ubuntu下而运行有问题,可能是所说的没导入包corejava,而用的openJDK 1.6.0里没有吧

          

import corejava.Console;

	public class StringSample {
		public static void main(String args[]){
			String yourname;

			Yourname=Consolr.readLine("Please input your name");
			System.out.println("hello "+yourname);
		}
}

          于是,我改为下面的:


        

/*
由控制台类来读取和输出字符串,但是注意:要导入包corejava.Console
*/
import java.io.Console;//corejava.Console;
public class StringSample{
	public static void main(String args[]){
		String urName;
		//urName=Console.readLine("Please input ur name");
		Console cons=System.console();
		urName=cons.readLine("Please input ur name:");
		System.out.println("hello "+urName);
	}
}




    <2>.格式化输出


    1)输出方法:用System.out内置的标准输出对象来输出到标准设备(一般是显示器) 见例10。3


    2)可以控制显示格式,在java.text包中的NumberFromat类就可以控制输出的格式 见例10。5


    3)用户还可以创建自己的格式


    4)用Console类格式化输出


    2.读和写字节


     (1).InputStream类的抽象方法


     (2).OutputStream类的抽象方法


    (3).available方法


数据流


    数据流支持所有Java中的基本类型。


    可以通过分别实现了DataOutput和DataInput两个接口的DataOutputStream和DataInputStream类中的方法对基本数据进行读写


    注意:原来,DataOutput和DataInput是接口!并且,DataOutputStream和DataInputStream类实现了它们。


    DataInput接口


    1)boolean readBoolean():读入一个布尔值。


    2)byte readByte():读入一个8位字节。


    3)char readChar():读入一个16位的字符。


    4)double readDouble():读入一个64位double字符。


    5)float readFloat():读入一个32位float字符。


    6)void readFully(byte b):读字节,直到读所有字节才封锁,参数b为读入数据的缓冲区。//注意:这里的封锁意味着什么?


    7)void readFully(byte[] b,int off,int len):读字节,直到读所有字节才封锁,参数b为读入数据的缓冲区,off为数据的起始偏移量,len为写的字节数。


    8)int readInt():读一个32位整数。


    9)String readLine():读入一行以一个\n,\r,\r\n或EOF结束的字符串,返回一个字符串,该字符串包含转换为单位码字符的行中的所有字节。


    10)long readLong():读入一个64位的长整数。


    11)short readShort():读入一个16位的短整数。


    12)String readUTF():读入一个UTF格式的字符串。


    13)int skipByte(int n):跳过若干个字节,直到跳过所有的字节才封锁,n为跳过的字节。


    2  Java.DataOutput接口


    1)void writeBoolean(boolean b):写一个布尔值。


    2)void writeByte(byte b):写一个8位字节。


    3)void writeChar(char c):写一个16位字符。


    4)void writeChars(String s):写入字符串的所有字符。


    5)void writeFloat(float f):写32位float数。


    6)void writeDouble(double d):写64位double数。


    7)void writeInt(int I):写32位整数。


    8)void writeLong(long l):写64位长整数。


    9)void writeShort(short s):写16位短整数。


    10)void writeUTF(String s):写一个UTF格式的字符串  


过滤流


    对于某些流来说(比如FileInputStream),它可从文件或一些更特殊的地方读入字节数据。


    对另一些流来说(比如DataInputStream以及PrintWriter),它们则可将字节“组装”成更有用的数据类型。


    Java程序源必须综合运用这两种流,将其合并成所谓的“过滤流”,


    方法是将一个现成的流传递给另一个流的构造函数。


    -read——DataInputStream-read——ZipInputStream-read——FileInputStream


文件流


    在Java中,文件流是用得比较广泛的一种流形式,它以磁盘文件为输入或输出的原始数据和目的。


    在Java中,把文件看成是一个字符(字节)的序列。根据数据的组织形式,可将文件分为文本文件和二进制文件。


    在文本文件中,每一个字节存放一个ASCII码,代表一个字符。


    二进制文件是把内存中的数据按其在内存中的存储形式原样输出到磁盘文件上存放。


    文件流也就根据所针对的文件类型的不同而分为文本流和二进制流。


    

在Java的I/O库中,抽象类Reader和Writer只能用来对文本文件进行操作,而
    抽象类InputStream和OutputStream 可以对文本文件或二进制文件进行操作


    1  二进制文件的读写


        (1).二进制文件的写


    二进制文件的写通常要用到DataOutputStream类


        格式如下:


    FileOutputStream out=new FileOutputStream(“路径和文件名”);


    DataOutputStream dos=new DataOutputStream(“out”);


        或


    DataOutputStream dos=new DataOutputStream(


        new FielOutputStream(“路径和文件名”));


    然后可以用DataOutputStream实现的方法向文件写入数据


    dos.writeDouble(…);         dos.writeInt(…)

import java.io.*;

public class FileOutputDemo {
	public static void main(String args[]){
		FileOutputStream out;
		DataOutputStream p;

		try {
			out=new FileOutputStream("myfile.dat");
			p = new DataOutputStream(out);
			p.writeDouble(3);
			p.writeDouble(4);
			p.writeDouble(5);
			p.close();
		}catch(Exception e){
			System.err.println ("Error writing to file");
		}
	}
}




        (2).二进制文件的读


    二进制形式文件的读,通常要用到DataInputStream类


    格式如下:


        FileInputStream in=new FileInputStream(“路径和文件名“);


              DataInputStream dis=new DataInputStream(“in”);


    当然也可以写成:


        DataInputStream dis=new DataInputStream(


                       new FileInputStream(“路径和文件名“));


    然后用数据流的方法读入文件中的数据,如:


        double d=dis.readDouble();


        int i=dis.readInt();

import java.io.*;

class FileInputDemo {
    public static void main(String args[]){
    	if (args.length == 1){
    	    try{
    	    	FileInputStream fstream = new FileInputStream(args[0]);
    	    	DataInputStream in = new DataInputStream(fstream);
    	    	while (in.available()!=0){/*注意这里的available方法*/
    	    		System.out.println(String.valueOf(in.readDouble()));//in的readDouble()方法
    	    	}
    	    	in.close();
    	    }catch(Exception e){
				System.out.println("File input error");
			}
		}else
			System.out.println("Invalid parameters");
	}
}




    2  文本文件的读写


    在Java中,采用的是Unicode字符。也就是说“1234”这个字符串的字符编码是00 31 00 32 00 33 00 34


    Java提供了一个过滤流,可以用来弥补Unicode编码和本机操作系统采用的字符编码间不同造成的问题


    如


    FileInputStream fis=new FileInputStream(“myfile.txt”);


    InputStreamReader isr=new InputStreamReader(fis);


        或    


    InputStreamReader isr=new InputStreamReader(


    new FileInputStream(“myfile.txt”));


        或


    FileReader fr=new FileReader(“myfile.txt”)


    (1).写文本文件


        1)FileOutputStream 方法是:


        FileOutputStream out  = new FileOutputStream("myfile.txt");  


          PrintStream p = new PrintStream( out );


        用 p.println() 来写入数据,然后用 p.close() 关闭输入     见例10。9

import java.io.*;

public class FileOutputDemo{
	public static void main(String args[]){
		FileOutputStream out;
		PrintStream p;
		try{
			out = new FileOutputStream("myfile.txt");
			p = new PrintStream( out );
			p.println ("This is written to a file");
			p.close();
		}catch (Exception e){
			System.err.println ("Error writing to file");
		}
	}
}



    2)用 FileWriter 方法是:


        FileWriter fw = new FileWriter("mydata.txt");


        PrintWriter out = new PrintWriter(fw); 


    用out.print 或 out.println往文件中写入数据,写完后要用out.close() 关闭输出,用fw.close() 关闭文件 见例10。10

import java.io.*;

public class FileWriteTest{
	public static void main (String[] args){
		FileWriteTest t = new FileWriteTest();
		t.WriteMyFile();
	}
	void WriteMyFile(){
		try {
			FileWriter fw = new FileWriter("mydata.txt");
			PrintWriter out = new PrintWriter(fw);
			out.print("hi,this will be wirte into the file!");
			out.close();
			fw.close();
		}catch(IOException e){
			System.out.println("Uh oh, got an IOException error!");
			e.printStackTrace();
		}
	}
}




    2.读文本文件


    1) 用FileInputStream 方法是:


        FileInputStream fstream =  new FileInputStream(args[0]);


        DataInputStream in = new DataInputStream(fstream);


    用 in.readLine() 来得到数据,用 in.close() 关闭输入流 见例10。11


    2)用FileReader 来读取文件的常用方法是:


        FileReader fr = new FileReader("mydata.txt");


        BufferedReader br = new BufferedReader(fr);


    用br.readLing() 来读出数据,然后用br.close() 关闭缓存,用fr.close() 关闭文件 见例10。12 例10。13

import java.io.*;

public class FileReadTest{
	public static void main(String[] args){
		FileReadTest t = new FileReadTest();
		t.readMyFile();
	}
	void readMyFile(){
		String record = null;
		int recCount = 0;
		try{
			FileReader fr = new FileReader("mydata.txt");
			BufferedReader br = new BufferedReader(fr);
			record = new String();
			while((record = br.readLine()) != null){
				recCount++;
				System.out.println(recCount + ": " + record);
			}
			br.close();
			fr.close();
		}catch(IOException e){
			System.out.println("Uh oh, got an IOException error!");
			e.printStackTrace();
		}
	}
}




对象流


    要以对象数据为单位进行读写,如果要想保存对象数据,首先需要打开一个ObjectOutputStream对象,格式如下:


    ObjectOutputStream out=new ObjectOutputStream(


          new FileOutputStream(“employee.dat”);


    现在要想保存一个对象,只需使用ObjectOutputStream提供的writeObject方法就可以了,如下所示:


    Employee harry = new Employee(“Harry Hacker”,35000,new Date(1989,10,1))


    out.writeObject(harry);

import java.io.*;
import java.util.*;

public class ObjectFileTest{
	public static void main(String[] args){
		try{
			Employee[] staff = new Employee[3];
         	staff[0] = new Employee("Harry Hacker",35000,new Date(1989,10,1));
        	staff[1] = new Manager("Carl Cracker", 75000,new Date(1987,12,15));
         	staff[2] = new Employee("Tony Tester", 38000,new Date(1990,3,15));
      		int i;
      		
      		System.out.println("Before writeObject:");
      		for(i=0;i<staff.length;i++)
      			staff[i].print();
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.dat"));
         	out.writeObject(staff);
         	out.close();

         	ObjectInputStream in =  new
            ObjectInputStream(new FileInputStream("employee.dat"));
        	Employee[] newStaff = (Employee[])in.readObject();
        	
         	for (i = 0; i < newStaff.length; i++)
            	newStaff[i].raiseSalary(100);
            System.out.println("After readObject:");
         	for (i = 0; i < newStaff.length; i++)
            	newStaff[i].print();
      	}
      	catch(Exception e){
      		System.out.print("Error: " + e);
         	System.exit(1);
      	}
   	}
}

class Employee implements Serializable{
	private String name;
   	private double salary;
   	private Date hireDay;
   	
	public Employee(String n, double s, Date d){
		name = n;
      	salary = s;
      	hireDay = d;
   	}
   	public Employee(){}
   	public void print(){
   		System.out.println(name + " " + salary + " " + hireYear());
   	}
   	public void raiseSalary(double byPercent){
   		salary *= 1 + byPercent / 100;
   	}
   	public int hireYear(){
   		return hireDay.getYear();
   	}
}

class Manager extends Employee{
	private String secretaryName;
	
	public Manager(String n, double s, Date d){
		super(n, s, d);
		secretaryName = "";
   	}
	public Manager(){}
   	public void raiseSalary(double byPercent){  
      	Date today = new Date();
      	double bonus = 0.5 * (today.getYear()+1900 - hireYear());
      	super.raiseSalary(byPercent + bonus);
   	}
   	public void setSecretaryName(String n){
   		secretaryName = n;
   	}
  	public String getSecretaryName(){
  		return secretaryName;
   	}
}






    要想读回对象,首先要打开一个ObjectInputStream对象:


    ObjectInputStream in=new ObjectInputStream(


        new FileInputStream(“employee.dat”);


    然后,按对象当初写入的顺序,用readObject方法取得对象:



    Employee e1=(Employee)in.readObject();