java數據流例子

    

    I/O流可謂是博大精深呀,今天總結一下今天所學到的東西吧:

首先理解一下I/O流的概念吧,Java的I/O流是實現輸入、輸出的基礎,它可以方便實現數據的輸入、輸出操作,Java中把不同的輸入、輸出流抽象地表述爲“流”,通過流的方式允許Java程序使用相同的方式來訪問不同的輸入、輸出流。InputStream和OutputStream是兩個處理字節流的基礎的類(且爲抽象類),而用於處理字符流的兩個基礎的類是Reader和Writer,所有其他的流類都是以這4個類爲基礎的。

按不同的方式可以把流分爲不同的類:

1.按照流的方向分爲輸入流和輸出流

輸入流:只能從中讀取數據,而不能向其中寫入數據(如InputStream、FileInputStream);

輸出流:只能向其中寫入數據,而不能向其中讀取數據(如OutputStream、FileOutputStream等);

2.按照流的角色分爲節點流和處理流

節點流:可以向一個特定的IO設備讀/寫數據的流,也稱作基礎流、低級流(FileInputStream、FileOutputStream)

處理流:實現對一個已存在的流的連接和封裝,通過所封裝的流的功能調用實現數據讀/寫功能的流,也稱作高級流、包裝流(如BufferedInputStream/BufferedOutputStream緩衝流DataInputStream/DataOutputStream數據流);它同時也是IO的精華—>基礎流中構造中參數是介質,而處理流中構造中參數是流。

下面看幾個實例吧:

第一部分:先看看基礎流吧!

實例一:InputStream和OutputStream

這兩個流是抽象類,提供了輸入/輸出處理的基本接口,並且實現了其中的一些方法,他們讀/寫流的方式是以字節爲單位進行的。

InputStream用於從源按照字節讀取數據,它定義了一下一些方法:

int read():從輸入流中讀取數據的下一個字節,並將它返回。如果遇到源的末尾,則返回-1,可以利用這一點判斷是否已經到了流的末尾;

int read(byte[] buffer):將數據讀入一個字節數組中,同時返回讀取的字節數。同樣如果遇到源的末尾,則返回-1;

int read(byte[] buffer,int offset,int length):將數據讀入一個字節數組,放到數組的offset指定的位置開始,並用length來指定讀取的最大字節數同樣如果遇到源的末尾,則返回-1;

void close():用於關閉該流,在使用完流以後,一定要記得使用此方法關閉,否則數據可能不會寫入文件;

void close():用於沖刷數據流,將數據寫入文件,close方法中會先執行此方法。

*注意一點:緩衝區是採用數據覆蓋的形式進行傳遞數據的。

下面看一個代碼:

package day11.io;
import java.io.*;
public class TestTestInputStream {
public static void main(String[] args) throws Exception {
int size;
InputStream is = new FileInputStream("E:\\test.txt");//input流需要先創建文件
System.out.println("可讀取 的字節:"+(size=is.available()));
byte[] t = new byte[200];
for(int i=0;i<size;i++){
t[i] = ((byte)is.read());
System.out.println(t[i]);
}
System.out.println();
OutputStream os = new FileOutputStream("E:\\test.txt");
byte[] c = new byte[200];
for(int j = 0;j<200;j++){
c[j] =(byte)(j);
os.write(c[j]);
}
os.close();
is.close();
}
}

    

上述代碼中用了try、catch直接處理了IO異常,調用read方法時,文件必須存在,調用write方法時會自動創建一個文件。

實例二:FileInputStream和FileOutputStream

他們分別是InputStream和OutputStream的子類,在生成FileInputStream和FileOutputStream類的對象時,如果指定的文件找不到,都會產生FileNotFoundException異常,因此必須捕獲或拋出異常。

下面看一個代碼:

package day11.io;
import java.io.*;
public class TestIo {
public static void main(String[] args) {
InputStream is = null;
OutputStream os = null;
try {
//使用read方法時,文件必須存在
//write方法會自動創建一個文件(如果沒有這個文件)
os = new FileOutputStream("D:\\2.txt");
os.write(98);
byte[] c = new byte[]{1,2,3};
os.write(c);
System.out.println();
is = new FileInputStream("D:\\2.txt");//會報錯java.io.FileNotFoundException:
int i = is.read();
System.out.println(i);
System.out.println(c.length);
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
is.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

    實例三:FileInputStream和FileOutputStream進行文件內容複製,利用write是可以創建文件的特點,複製出另一個內容一模一樣的文件,爲了提高複製效率,引進了數組,如果不寫flush() 和close(),那麼複製出的文件會變小,如果write中參數不加後面兩個,那麼複製出的文件會變大。下面看一下例子

    

package blog;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class TestCopy {
public static void main(String[] args) throws Exception {
File file1 = new File("E:\\test.txt");
File file2 = new File("E:\\tt.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
int i;
byte[] buff = new byte[8*1024];
while((i=fis.read(buff))!=-1){
fos.write(buff,0,i);
}
System.out.println("succees!");
System.out.println("file1的大小爲:"+file1.getUsableSpace()+" ");
System.out.println("file2的大小爲:"+file2.getUsableSpace()+" ");
//      file1.delete();完成了剪切功能
fis.close();
fos.close();
}
}

    輸出結果如下所示:

    

succees!
file1的大小爲:73930264576
file2的大小爲:73930264576

   程序結合了InputStream和OutputStream的用法,通過一個FileInputStream從一個文件中讀出文件內容,然後將它作爲FileOutputStream的輸出,寫入另一個文本文件,這樣就完成了複製。

第二部分:接下來看看高級數據流^_^

高級流是對基礎流進行了封裝,並有許多功能的擴展,下面介紹幾個常用的高級數據流:

1.BufferedInputStream和BufferedOutputStream

  實現了帶緩衝的過濾流,在讀寫的同事對數據進行緩存,這樣可以避免每次讀寫或發送數據時都要進行實際的物理讀寫操作,因此在輸入輸出時經常用到這兩個類。在用BufferOutputStream輸出時,數據先輸入緩衝區,緩衝區大小默認爲8K,當緩衝區滿時再寫入連接的輸出流,可以調用flush()方法來清空緩衝區。

看一個代碼理解一下:

實例四:

Buffered...有很多方法,在這裏就不一一列舉了,讀者可以查相應的api。

下面的方法複製了一個相同的文件:

package day11.io;
import java.io.*;
public class TestFileCopy {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\1.txt");
FileOutputStream fos = new FileOutputStream("D:\\2.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int i = 0;
//默認讀的是8K,要是緩衝取滿了會自動寫入文件裏的
while((i=bis.read())!=-1){
bos.write(i);
}
//      bos.flush();//沖刷緩衝區,強制將緩衝區中的內容寫入文件
//      bos.close();//關閉緩衝區在close之前會先flush的
}
}

    下面說一下System.setOut();方法,它可以控制輸出方式,即在控制檯輸出還是在文件中輸出。

package day11.io;
import java.io.*;
public class TestSISO {
public static void main(String[] args) throws IOException {
// 從控制檯讀一行
// Scanner是5.0之後提供的類。
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
//需要在控制檯路數數據然後直接在控制帶顯示;
System.out.println(s);
//PrintStream 中的println方法經常和BufferedReader的readLine()配合使用。
PrintStream ps = new PrintStream(new File("D:\\a.txt"));
System.out.println("控制檯輸出!");
System.setOut(ps);
System.out.println("文件中輸出!");
ps.print("I'm coming!");
ps.print(s);
}
}

    控制檯輸出如下:

wo
wo
控制檯輸出!

    文件中內容如下:

文件中輸出!
I'm coming!

    

2.DataInputStream和DataOutputStream

  它們同樣分別繼承自FilterInputStream和FilterOutputStream,可以用與計算機無關的格式讀寫Java的基本數據類型以及String對象,DataInputStream中對應的以read開頭,如readByte(),readDouble等等,write也同樣。

在上一個代碼的基礎上增加了此數據流的功能:

實例五:

package day11.io;
import java.io.*;
public class TestDataFlow {
public static void main(String[] args) throws IOException {
//Data數據流中包含了8種基本數據流的重載,可輸入8種,另外還可查看api還有別的
File file = new File("D:\\a.txt");
FileOutputStream fos = new FileOutputStream(file);
DataOutputStream dos = new DataOutputStream(fos);
BufferedOutputStream bos = new BufferedOutputStream(dos);
dos.writeChar('M');
dos.writeDouble(1.34154);
dos.writeUTF("家");
FileInputStream fis = new FileInputStream(file);
DataInputStream dis = new DataInputStream(fis);
BufferedInputStream bis = new BufferedInputStream(dis);
char a = dis.readChar();
double d = dis.readDouble();
String s = dis.readUTF();
System.out.println(a+" "+s+" "+d);
//只需要關閉外層的就可以啦,它會自動關閉內層的流
dis.close();
dos.close();
}
}
輸出如下:
M 家 1.34154

    

Data...數據流則比較人性化,多了很多方法,提供更多數據類型,writeUTF也提供了漢字的輸入~

3.ObjectInputStream和ObjectOutputStream

萬物皆OBJ,同樣數據流也有Object類型的,見聞知其意,即數據流中傳遞的是對象的類型,下面看個小例子:

實例六:

首先實體類如下:

package day11.io;
import java.io.Serializable;
public class Pet implements Serializable{
private String name;
private int age;
public Pet() {
super();
// TODO Auto-generated constructor stub
}
public Pet(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Pet [name=" + name + ", age=" + age + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pet other = (Pet) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

    實體類代碼中均未自動生成的方法,在寫這個的時候明確了一點概念:Collection和Serializable接口均無字段和方法,Compatable只有一個方法即compareTo(),然後寫一下爲其測試類,將對象的數據存入D:\\Pet.content的文件中,然後從中讀取Pet類的數據:

package day11.io;
import java.io.*;
public class TestPetOOSIOS {
public static void main(String[] args) throws Exception {
File file = new File("D:\\Student.content");
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Pet p1 = new Pet("七仔",5);
oos.writeObject(p1);
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Pet p2 = (Pet) ois.readObject();
System.out.println("MY Dog'name is "+p2.getName()+"! \r\nAnd his age is "+p2.getAge()+" years old!");
oos.close();
ois.close();
}
測試結果如下:
MY Dog'name is 七仔!
And his age is 5 years old!

    同樣還可定義另一個類讓其成爲本實體類的屬性,然後同樣也就可以傳遞這個類的數據流了

4.Reader和Writer

它處理的是字符類型的數據流,它也分高級流和低級流;

Reader與InputStream相同用於從流中讀取數據,它的方法如下:

int read():用於從流中讀出一個字符,並將其返回。

int read():將從流中讀出的字符放到字符數組buffer中,返回讀出的字符數。

Int read(char[] buffer,int offset,int length):將讀出的字符放到字符數組的指定offset開始的空間,每次最多讀出length個字符。

Void close():關閉Reader流,在使用完Reader流後,一定記得將其關閉。

Boolean ready():判斷流是否已經準備好被讀取。

其他等方法可查看api文檔。

Writer與OutputStream類似,用於向流中寫入數據,它的方法如下:

void write(int c)

void write(char[] buffer)

void write(char[] buffer,int offset,int length)

void write(String string)

void write(String string,int offset,int length)

均爲write方法的重載,意義同以上的read方法差不多

void close(),void flush()方法與以前的相同。

實例七:

package day11.io;
import java.io.*;
public class TestReader {
public static void main(String[] args) throws IOException {
File file = new File("D:\\a.txt");
FileReader fr = new FileReader(file);//同一下兩句的效果相同,但前提是保證是gbk編碼
//      FileInputStream fis = new FileInputStream(file);
//      InputStreamReader isr = new InputStreamReader(fis,"gbk");
char c = (char)fr.read();
System.out.println(c);
//注意輸入編碼格式要一致
FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
osw.write("中國");
for(int i=0;i<65535;i++){
osw.write(i);
}   fr.close();
osw.close();
}
}

    下面一個是用了Readre和Writer的方法

package day11.io;
import java.io.*;
public class TestBuffered {
public static void main(String[] args) throws IOException {
File file = new File("D:\\a.txt");//得先有這個文件
FileInputStream fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String str = null;
while((str = br.readLine())!=null){
System.out.println(str);
}
  FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos);
BufferedWriter bos = new BufferedWriter(osw);
bos.write("一二三四五");
bos.newLine();// 新起一行。
bos.write("六七八九十");
bos.flush();// 注意沖刷
bos.close();
br.close();
}
}

    在a.txt中輸出了幾乎所有的編碼。在這個學習中有明確了一點編碼小問題:對於漢字來說,gbk/gb2312佔兩個字節,utf-8佔三個字節。

I/O果然是個不同凡響的東西,內容好多,以後再慢慢聊吧,今天就到這樣了~晚安!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章