1、描述:流是字節(jié)數(shù)據(jù)或字符數(shù)據(jù)序列。Java采用輸入流對(duì)象和輸出流對(duì)象來(lái)支持程序?qū)?shù)據(jù)的輸入和輸出。輸入流對(duì)象提供了數(shù)據(jù)從源點(diǎn)流向程序的管道,程序可以從輸入流對(duì)象讀取數(shù)據(jù);輸出流對(duì)象提供了數(shù)據(jù)從程序流向終點(diǎn)的管道,程序通過(guò)該管道把數(shù)據(jù)寫(xiě)到終點(diǎn)。所有的關(guān)于輸入/輸出的類(lèi)都包含在java.io的包中。
2、File類(lèi):它主要關(guān)心的是文件的具體屬性,而非內(nèi)容,定義了許多方法,實(shí)現(xiàn)對(duì)文件的創(chuàng)建、刪除等操作。
code:
import java.io.*;
public class Test
{
public static void main(String args[])throws Exception
{
File file1=new File("w1.txt");//在當(dāng)前目錄下
file1.createNewFile();//得到文件w1.txt
file1.mkdir();//得到目錄w1.txt
File file2=new File("D:\\javaprogram\\text\\w2.txt");//指定目錄
file2.createNewFile();//得到文件w2.txt
//用靜態(tài)字段separator獲得系統(tǒng)分隔符,保證程序通用性
File fDir=new File(File.separator);//作為字符是'\',作為File對(duì)象為當(dāng)前根目錄
String fStr="javaprogram"+File.separator+"text"+File.separator+"w3.txt";
File file3=new File(fDir,fStr);
file3.createNewFile();//得到文件w3.txt
file1.delete();
file2.delete();
file3.delete();
//delete()方法刪除文件,調(diào)用即刪除,而deleteOnExit()是在JVM終止時(shí)才刪除
//這樣就得以建立臨時(shí)文件以存儲(chǔ)臨時(shí)數(shù)據(jù),臨時(shí)文件保存在臨時(shí)文件夾
//要找臨時(shí)文件夾,請(qǐng)查看環(huán)境變量temp的設(shè)置
for(int i=0;i<5;i++)
{
File file=File.createTempFile("wang",".temp");
file.deleteOnExit();
}
Thread.sleep(3000);
//下面的一段程序?qū)?shí)現(xiàn),打印指定目錄下的.java文件的信息
File f=new File("d:\\javaprogram");
if(f.exists())//判斷文件是否存在
{
if(f.isDirectory())//判斷文件是目錄還是標(biāo)準(zhǔn)文件
{
//調(diào)用帶參數(shù)的listFiles()方法返回滿(mǎn)足特定過(guò)慮器的
//此抽象路徑名所表示目錄中的文件和目錄的抽象路徑名數(shù)組
File[] fname=f.listFiles(new FilenameFilter()
{
//匿名類(lèi)實(shí)現(xiàn)接口FilenameFileter的唯一方法
public boolean accept(File dir, String name)
{
return name.indexOf(".java")!=-1;
}
});
for(int i=0;i<fname.length;i++)
{
System.out.println(fname[i]);
}
}
}
else
{
System.out.println("文件夾不存在.");
}
}
}
3、字節(jié)流:
程序運(yùn)行中常的I/O操作包括向標(biāo)準(zhǔn)設(shè)備輸入輸出數(shù)據(jù)和文件輸入輸出。對(duì)于前者,java定義了三個(gè)直接使用的流對(duì)象:System.err(標(biāo)準(zhǔn)錯(cuò)誤輸出)、System.out(標(biāo)準(zhǔn)輸出)和System.in(標(biāo)準(zhǔn)輸入);對(duì)于后者,可以使用FileOutputStream和FileInputStream。
code:
import java.io.*;
public class Test
{
static final String file1="D:\\javaprogram\\w1.txt";
static final String file2="E:\\database\\w2.txt";
static final String file3="E:\\wmpub\\w3.txt";
public static void main(String args[])throws IOException
{
/*//關(guān)于System.in
int data;
while ((data=System.in.read())!=-1)//Ctrl+c結(jié)束輸入
{
System.out.write(data);
}*/
//下面的程序段用以向file1文件寫(xiě)入,把其內(nèi)容的一部分復(fù)制到file2
//再把file2文件完整地復(fù)制到file3,并打印出來(lái)
FileOutputStream fos1=new FileOutputStream(file1);
FileOutputStream fos2=new FileOutputStream(file2);
FileOutputStream fos3=new FileOutputStream(file3);
fos1.write("今天是2008年8月3號(hào),離北京奧運(yùn)會(huì)還有5天,心里非常激動(dòng)啊.".getBytes());
fos1.close();
FileInputStream fis1=new FileInputStream(file1);
fis1.skip(19);//跳過(guò)19個(gè)字節(jié)
byte[] buf=new byte[fis1.available()];
fis1.read(buf);
fis1.close();
System.out.println(new String(buf));
fos2.write(buf);
fos2.close();
FileInputStream fis2=new FileInputStream(file2);
while(fis2.available()>0)
{
byte[] b=new byte[fis2.available()];
int let=fis2.read(b);
if(let==-1)break;
fos3.write(b,0,let);
}
System.out.println("復(fù)制成功!");
fis2.close();
fos3.close();
//以下程序段實(shí)現(xiàn)了一個(gè)圖像文件的復(fù)制
FileInputStream a=new FileInputStream("4.jpg");
FileOutputStream b=new FileOutputStream("3.jpg");
byte c[]=new byte[a.available()];
a.read(c);
b.write(c);
a.close();
b.close();
}
}
4、字符流(FileWriter and FileReader)
import java.io.*;
public class Test
{
public static void main(String args[])
{
//本程序完成從控制臺(tái)讀入文件名,并實(shí)現(xiàn)復(fù)制
int length;
char buf[]=new char[100];
try
{
FileReader in=new FileReader(args[0]);
FileWriter out=new FileWriter(args[1]);
length=in.read(buf);
while(length!=-1)
{
out.write(buf,0,length);
//字符流讀取通過(guò)read()的返回值判斷是否讀到文件末尾
//我剛才忘記加這條語(yǔ)句,文件被一直寫(xiě),都死機(jī)了,重啟后一看,寫(xiě)了2.6G
length=in.read(buf);
}
in.close();
out.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
5、過(guò)濾流之一
Java利用過(guò)濾流可以在讀寫(xiě)數(shù)據(jù)的同時(shí)對(duì)數(shù)據(jù)進(jìn)行處理,以達(dá)到性能的改善,提高程序執(zhí)行效率。將過(guò)濾流和某個(gè)輸入流或輸出流(節(jié)點(diǎn)流)連接。連接是通過(guò)在過(guò)濾流的構(gòu)造方法中指定入口參數(shù)——節(jié)點(diǎn)流來(lái)實(shí)現(xiàn)的。
§BufferedInputStream:
FileInputStream fis=new FileInputStream("w1.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
byte[] buf=new byte[100];
int len=bis.read(buf,0,len);
System.out.println(new String(buf,0,len));
bis.close();
§BufferedOutputStream:
FileOutStream fos=new FileOutputStream("w2.txt");
BufferedOutputStream bos=new BufferedOutputStream(bos);
bos.write("好好學(xué)習(xí),天天向上".getBytes());
bos.flush();
bos.close();
也可以是匿名創(chuàng)建:如:BufferedOutputStream bos=new BufferedOutputStream(new FileInputStream("w2.txt"));
BufferedReader和BufferedWirter與此類(lèi)似,不過(guò)是分別指定Writer和Reader類(lèi)型的參數(shù)罷了。
一個(gè)實(shí)例程序:
import java.io.*;
public class Test
{
public static void main(String[] args)
{
try
{
FileInputStream in=new FileInputStream(args[0]);
BufferedInputStream bufIn=new BufferedInputStream(in);
int limit;
bufIn.mark(limit=bufIn.available());//在當(dāng)前位置打上標(biāo)記
for(int i=0;i<limit;i++)
System.out.print((char)(bufIn.read()));
System.out.println();
bufIn.reset();//reset緩沖區(qū)標(biāo)志
int c;
while((c=bufIn.read())>=0)System.out.print((char)c);
bufIn.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
5、過(guò)濾流之二基本類(lèi)型數(shù)據(jù)傳輸:DataInputStream和DataOutputStream
import java.io.*;
public class Test
{
public static void main(String args[])
{
try
{
DataOutputStream dos=new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(
"d://javaprogram//w.txt")));
dos.writeInt(5);
dos.writeUTF("你好");
dos.writeBoolean(true);
dos.writeDouble(3.1415926);
dos.writeBytes("ok!");
dos.writeChars("bye bye");
dos.close();
DataInputStream dis=new DataInputStream(
new BufferedInputStream(new FileInputStream(
"d://javaprogram//w.txt")));
//讀出的順序應(yīng)與寫(xiě)入的順序一致
System.out.println(dis.readInt());
System.out.println(dis.readUTF());
System.out.println(dis.readBoolean());
System.out.println(dis.readDouble());
byte b[]=new byte[3];
dis.readFully(b);
for(int j=0;j<3;j++)System.out.print((char)b[j]);
System.out.println();
StringBuffer st3=new StringBuffer();
for(int j=0;j<7;j++)st3.append(dis.readChar());
System.out.println(st3.toString());
dis.close();
}
catch (IOException e)
{
System.err.println(e.toString());
}
}
}
6、過(guò)濾流之三:I/O流的鏈接圖:
7、字節(jié)和Unicode字符的橋梁:InputStreamReader、OutputStreamWriter
code:
import java.io.*;
public class Test
{
public static void main(String[] args)throws IOException
{
//文件讀寫(xiě)
FileOutputStream fos=new FileOutputStream("w.txt");
OutputStreamWriter osw=new OutputStreamWriter(fos);
BufferedWriter bw=new BufferedWriter(osw);
bw.write("今天是2008年8月3日,離北京奧運(yùn)還有5天!");
bw.close();
FileInputStream fis=new FileInputStream("w.txt");
InputStreamReader isr=new InputStreamReader(fis);
BufferedReader br=new BufferedReader(isr);
System.out.println(br.readLine());
br.close();
//控制臺(tái)讀寫(xiě)
BufferedReader br1=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw1=new BufferedWriter(new OutputStreamWriter(System.out));
String strLine,str="";
while((strLine=br1.readLine())!=null)//Ctrl+c結(jié)束輸入
{
str+=strLine;
System.out.println(strLine);
}
br1.close();
bw1.write(str,0,str.length());
bw1.write((int)('\n')); //將回車(chē)符輸入bw1
bw1.flush();
bw1.close();
}
}
8、管道流:PipedInputStream、PipedOutputStream
作用:用于線(xiàn)程間的通信,一個(gè)線(xiàn)程的pipedInputStream對(duì)象從另一個(gè)線(xiàn)程的PipedOutputStream對(duì)象讀取輸入,要使管道流有用,必須同時(shí)構(gòu)造管道輸入流和管道輸出流。
例子(孫鑫老師的例子):
import java.io.*;
class Producer extends Thread
{
private PipedOutputStream pos;
public Producer(PipedOutputStream pos)
{
this.pos=pos;
}
public void run()
{
try
{
pos.write("Hello,welcome you!".getBytes());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
class Consumer extends Thread
{
private PipedInputStream pis;
public Consumer(PipedInputStream pis)
{
this.pis=pis;
}
public void run()
{
try
{
byte[] buf=new byte[100];
int len=pis.read(buf);
System.out.println(new String(buf,0,len));
pis.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
public class Test
{
public static void main(String args[])
{
PipedOutputStream pos=new PipedOutputStream();
PipedInputStream pis=new PipedInputStream();
try
{
pos.connect(pis);
new Producer(pos).start();
new Consumer(pis).start();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
9、PrintWriter類(lèi):創(chuàng)建的輸出流可以使用print和println方法,按Unicode字符形式輸出,輸出的數(shù)據(jù)可讀性較好。
§打印流建立文本文件:
PrintWriter out=new PrintWriter(new FileWriter(1.dat));
String str="天呢,我告訴你吧:";
char[] z={'北','京','奧','運(yùn)','會(huì)','在'};double g=2008;
out.println(st);out.print(z);out.print(g);out.println("年08月08日08時(shí)08分08秒");
out.close();
§打印流在屏幕上顯示文本
PrintWriter out=new PrintWriter(System.out);
其余同上,此處略
10、文件的隨機(jī)讀寫(xiě):RandomAccessFile
import java.io.*;
public class Test
{
public static void main(String args[])throws Exception
{
int lineNo;//讀到的行號(hào)
long fp;//文件指針
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
RandomAccessFile raf=new RandomAccessFile("w.txt","rw");
System.out.println("請(qǐng)輸入6個(gè)字符串");
int[] len=new int[12];
String[] str=new String[12];
for(int i=0;i<6;i++)
{
System.out.println("行號(hào)"+(i+1)+":");
str[i]=br.readLine();
len[i]=str[i].length();
raf.write((str[i]+"\n").getBytes());
}
while(true)
{
fp=0;
raf.seek(0);
System.out.println("你要顯示第幾行?"+"(1--6)");
lineNo=Integer.parseInt(br.readLine());
for(int i=1;i<lineNo;i++)
fp=fp+(long)len[i-1]+1;
raf.seek(fp);
System.out.println("第"+lineNo+"行"+":"+raf.readLine());
System.out.println("繼續(xù)嗎?"+"(y/n)");
if((br.readLine().equals("n")))break;
}
raf.seek(raf.length());
System.out.println("繼續(xù)寫(xiě)入6行數(shù)據(jù):");
for(int i=6;i<12;i++)
{
System.out.println("行號(hào)"+(i+1)+":");
str[i]=br.readLine();
len[i]=str[i].length();
raf.write((str[i]+"\n").getBytes());
}
System.out.println("打印12行數(shù)據(jù):");
raf.seek(0);
for(long i=0;i<raf.length();i=raf.getFilePointer())
{
System.out.println(raf.readLine());
}
raf.close();
}
}
11、文件的壓縮處理
實(shí)例:
import java.io.*;
import java.util.*;
//ZipInputStream和ZipOutputStream在包java.util.zip中
import java.util.zip.*;
public class Test
{
public static void main(String args[])throws Exception
{
//輸入若干文件名,將所有文件壓縮為w.zip
ZipOutputStream zos=new ZipOutputStream(
new BufferedOutputStream(new FileOutputStream("w.zip")));
for(int i=0;i<args.length;i++)
{
BufferedInputStream bis=new BufferedInputStream(
new FileInputStream(args[i]));
//將每個(gè)要壓縮的文件稱(chēng)為一個(gè)壓縮入口,使用ZipEntry生成壓縮入口對(duì)象
//使用putNextEntry(ZipEntry entry)將壓縮入口加入到壓縮文件
zos.putNextEntry(new ZipEntry(args[i]));
int b;
while((b=bis.read())!=-1)
zos.write(b);
bis.close();
}
zos.close();
//解壓縮文件并顯示
ZipInputStream zis=new ZipInputStream(
new BufferedInputStream(new FileInputStream("w.zip")));
ZipEntry z;
while((z=zis.getNextEntry())!=null)//獲得入口
{
System.out.println(z.getName());//顯示文件初始名
int x;
while((x=zis.read())!=-1)
System.out.write(x);
System.out.println();
}
zis.close();
}
}
12、編碼與解碼
import java.util.*;
import java.nio.charset.*;
public class Test
{
public static void main(String args[])throws Exception
{
//以下程序段打印當(dāng)前計(jì)算機(jī)所能處理的標(biāo)準(zhǔn) charset
//Charset類(lèi)位于java.nio.charset包中,此類(lèi)定義了用于創(chuàng)建解碼器和編碼器
//以及檢索與 charset 關(guān)聯(lián)的各種名稱(chēng)的方法。此類(lèi)的實(shí)例是不可變的。
//Charset.availableCharsets()返回一個(gè)映射
//Map是java.util包中的一個(gè)接口
Map m=Charset.availableCharsets();
//keySet()方法返回此映射中包含的鍵的 set 視圖
Set names=m.keySet();
//構(gòu)造迭代器訪(fǎng)問(wèn)諸元素
Iterator it=names.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
//Properties 類(lèi)位于java.util包中,表示了一個(gè)持久的屬性集
//System.getProperties()確定當(dāng)前的系統(tǒng)屬性。
Properties pps=System.getProperties();
pps.list(System.out);//打印屬性
//將系統(tǒng)文件的標(biāo)準(zhǔn)字符集改為:ISO-8859-1
//設(shè)置的字符集,只是當(dāng)前JVM上的字符集
pps.put("file.encoding","ISO-8859-1");
int data;
byte[] buf=new byte[100];
int i=0;
while((data=System.in.read())!='q')
{
buf[i]=(byte)data;
i++;
}
String str=new String(buf,0,1);
System.out.println(str);
//ISO-8859-1字符解碼為Unicode字符(java使用)
//Unicode字符編碼為GBK字符
//但并不是所有字符都能反編碼回來(lái),比如漢字將丟失高字節(jié)
String strGBK=new String(str.getBytes("ISO-8859-1"),"GBK");
System.out.println(strGBK);
}
}
13、對(duì)象序列化
對(duì)象的壽命常隨著對(duì)象的程序的終止而終止,倘若需要對(duì)對(duì)象的狀態(tài)進(jìn)行保存,需要時(shí)再恢復(fù)。我們把對(duì)象的這種能夠記錄自己狀態(tài)以便將來(lái)再生的能力,叫做對(duì)象的持續(xù)性(persistence)。對(duì)象通過(guò)寫(xiě)出描述自己狀態(tài)的值——對(duì)象轉(zhuǎn)化為字節(jié)流,來(lái)記錄自己的這個(gè)過(guò)程叫對(duì)象的序列化(serialization)。 一個(gè)對(duì)象要能夠?qū)崿F(xiàn)序列化,必須實(shí)現(xiàn)Serializable接口,或者Externalizable接口。
一個(gè)對(duì)象被序列化時(shí),只保存對(duì)象的非靜態(tài)成員變量,如果一個(gè)對(duì)象的成員變量是一個(gè)對(duì)象,那么這個(gè)對(duì)象的數(shù)據(jù)成員也會(huì)被保存。如果一個(gè)可序列化的對(duì)象包含對(duì)某個(gè)不可序列化的對(duì)象的引用,那么整個(gè)序列化操作將會(huì)失敗,并且會(huì)拋出一個(gè)NotSerializableException。但如果把這個(gè)引用標(biāo)記為transient,那么對(duì)象仍然可以序列化。
另外,對(duì)象序列化建立了一張對(duì)象網(wǎng),將當(dāng)前要序列化的對(duì)象中所持有的引用指向的對(duì)象都包含起來(lái)一起寫(xiě)入到文件,如果一次序列化幾個(gè)對(duì)象,它們中的相同內(nèi)容會(huì)被共享。
code:
import java.io.*;
public class Test
{
public static void main(String[] args) throws Exception
{
Employee e1=new Employee("zhangsan",25,3000.50);
Employee e2=new Employee("lisi",24,3200.40);
Employee e3=new Employee("wangwu",27,3800.55);
ObjectOutputStream oos=new ObjectOutputStream(
new FileOutputStream("w.dat"));
oos.writeObject(e1);
oos.writeObject(e2);
oos.writeObject(e3);
oos.close();
ObjectInputStream ois=new ObjectInputStream(
new FileInputStream("w.dat"));
Employee e;
String strSal;
for(int i=0;i<3;i++)
{
e=(Employee)ois.readObject();
//設(shè)置自已需要的輸出方式
//strSal=(e.salary==0)?"不告訴你":String.valueOf(e.salary);
//System.out.println(e.name+":"+e.age+":"+strSal);
System.out.println(e.name+":"+e.age+":"+e.salary);
}
ois.close();
}
}
class Employee implements Serializable
{
String name;
int age;
transient double salary;
transient Thread t=new Thread();
public Employee(String name,int age, double salary)
{
this.name=name;
this.age=age;
this.salary=salary;
}
//重寫(xiě)方法,完成需要的操作,如果不重寫(xiě),要想不寫(xiě)入某些數(shù)據(jù)可以標(biāo)記為transient
//本程序的數(shù)據(jù)salary就被標(biāo)記為transient,打印時(shí)輸出為0.0,如果是String將為null
/*private void writeObject(java.io.ObjectOutputStream oos)throws IOException
{
oos.writeUTF(name);
oos.writeInt(age);
//System.out.println("Write Object");
}
private void readObject(java.io.ObjectInputStream ois)throws IOException
{
name=ois.readUTF();
age=ois.readInt();
//System.out.println("Read Object");
}*/
}