Java IO流(InputStream/OutputSteam)

什麼是IO流?
 byte序列的讀寫,Java中的IO流是實現輸入/輸出的基礎.
1)
InputStream : 抽象類讀取數據的過程  包含讀取方法read();
  in 模仿了讀取小說的過程html

 簡單說  :  in是讀取文件的java

OutputStream:抽象了寫出數據的過程  包含寫出方法write();
 out模仿了寫筆記記錄的過程windows

 簡單說  : out是寫入文件的數組

 

基本的byte流
InputStream(抽象方法read())
 |--- FileInputStream(read()在文件上讀取)   節點流
 |
 |--- FilterInputStream 過濾器流,輸入流功能的擴展
 |   |--- DataInputStream(readInt())  基本類型數據的讀取
 |   |--- BufferedInputStream 提供讀取緩衝區管理
 | --- ObjectInputStream   過濾器流,依賴基本byte流,擴展對象的反序列化緩存

OutputStream(抽象方法write()) 
 |--- FileOutputStream(write()在文件上寫實現寫入)   節點流
 |
 |--- FilterOutputStream 過濾器流,輸出流功能的擴
 |    |--- DataOutputStream(writerInt())  基本類型數據的寫出
 |    |--- BufferedOutputStream 提供了輸出緩衝區管理
 | --- ObjectOutputStream 過濾器流,依賴基本byte流,擴展對象的序列化tomcat

注意:除節點流外都是過濾器流服務器

字符流,能夠處理字符編碼,底層依賴於byte流
Reader 讀取文本
     | --- InputStreamReader  過濾去,依賴基本byte輸入流
     |      實現文本編碼的解析
     |
     | --- BufferedReader 過濾器, 須要依賴Reader 實例
     |    提供了readLine()方法, 能夠在文本文件中讀取一行
     |    是經常使用的文本讀取方法   
Writer
     | --- OutputStreamWriter  過濾器,,依賴基本byte輸出流
     |        實現文本編碼
     | --- PrintWriter  過濾器,依賴於Writer 流
     |                       提供了輸出文本常有方法println()ide

 

2)  EOF =  End of File = -1 (文件讀到末尾會返回-1)性能

3)  輸入流的基本方法  
 InputStream in = new InputStream(file) / /file是文件名
 int b  = in.read();      讀取一個byte無符號填充到int底八位,-1是EOF
 int.read(byte[] buf)    讀取數據填充到buf中
 int.read(byte[] buf,int start,int size)  讀取數據填充到buf中
 in.close      關閉輸入流編碼

4)輸出流的基本方法:
 OutputStream out = new OutputStream(file) / /file是文件名
 out.write(int b)     寫出一個byte 到流 b 的底八位寫出
 out.write(byte[] buf)    將buf的一部分寫入流中
 out.write(byte[] buf, int start, int size)  將buf的一部分寫入流中
 out.flush()      清理緩存
 out.close

1.FileInputStream (read()在文件上讀取)   節點流
方法:  read()         從輸入流中讀取數據的下一個字節
     read(byte[] buf)  從輸入流中讀取必定數量的字節,並將其存儲在緩衝區數組 buf中 
     read(byte[] b, int off, int len) 將輸入流中最多 len 個數據字節讀入 byte 數組。

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStreamDemo {
 public static void main(String[] args) 
  throws IOException {
  String file = "out.txt";
  InputStream in = new FileInputStream(file);
  int b;
  while((b=in.read())!=-1){//read()方法
   System.out.print(Integer.toHexString(b) + " ");
  }
  in.close();
  
  in = new FileInputStream(file);
  //in.available() 能夠讀取的數據個數,小文件通常是文件長度
  byte[] buf = new byte[in.available()];
  in.read(buf);//read(byte[] buf)方法重載
  in.close();
  for (byte c : buf) {
   System.out.print(Integer.toHexString(c & 0xff) + " ");
   // c & 0xff --->將16進制寫成0xff的格式
   //ffffffd6---> d6
   //11111111 11111111 11111111 11010110  &對應相乘
   //00000000 00000000 00000000 11111111  0xff
   //00000000 00000000 00000000 11010110
  }
 }
}


2  FileOutputStream(write()在文件上寫實現寫入)   節點流
方法 :write(int b)  將指定的字節寫入此輸出流。
 write(byte[] buf)   將 b.length 個字節從指定的 byte 數組寫入此輸出流。
 write(byte[] b, int off, int len) 將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此輸出流。
例子

import java.io.*;

public class OutputStreamDemo {
 public static void main(String[] args) 
 throws IOException{
  String file = "out.txt";
  OutputStream out = new FileOutputStream(file);
  out.write(65);//在文件中是以16進制存儲的,對應0x41
  out.write(66);//0x42
  byte[] buf = {(byte)0xd6,(byte)0xd0};
  out.write(buf);
  out.flush();//刷出緩存,清理緩衝區,保證可靠寫 
  out.close();
 }
}


3.BufferedInputStream和BufferedOutputStream 的 用法

BufferedInputStream(FileInputStream in)
BufferedOutputStream(FileOutputStream out)
能夠提升性能
例子

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class BufferedStreamDemo {
 public static void main(String[] args) throws IOException {
  //BufferedInputStream普通寫法
  String file = "out.txt";
  InputStream ins = new FileInputStream(file);
  BufferedInputStream bufin= new BufferedInputStream(ins);
  int b;
  while((b=bufin.read())!=-1){
   System.out.println(Integer.toHexString(b));
  }
  //經常使用寫法,只要用到FileInputStream的地方均可以套一個BufferedInputStream用來提高性能
  BufferedInputStream in = new BufferedInputStream(
    new FileInputStream("out.txt"));
  
  //BufferedOutputStream
  BufferedOutputStream out = new BufferedOutputStream(
    new FileOutputStream("out.txt"));
  out.write(65);
 }
}

 

4.基本類型數據的寫出和讀入
DataOutputStream  方法:readInt()  readLong()  readBoolean()等
寫出(寫)

//例子
import java.io.*;
public class DataOutDemo {
 public static void main(String[] args)
  throws IOException{ 
  String file = "data.dat";//項目文件夾
  OutputStream out = new FileOutputStream(file);
  //DataOutputStream 實現基本類型數據的序列化
  //將基本類型數據拆開爲byte序列,寫入到out流中
  DataOutputStream dos = new DataOutputStream(out);
  dos.write(-2);
  dos.writeInt(-2);
  dos.writeLong(-2);
  dos.writeByte(-2);
  dos.writeDouble(-2);
  dos.writeShort(-2);
  dos.writeFloat(-2);
  dos.writeBoolean(true);
  dos.writeChar('中');
  dos.close();

 }
}

 

DataInputStream   方法:  writeInt()  writeChar() 等8種
讀入(讀)

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class DataInDemo {
 public static void main(String[] args) 
  throws IOException{
  
  String file = "data.dat";

  InputStream in = new FileInputStream(file);
  //DataInputStream 從基本流中讀取基本類型數據,實現基本
  //類型數據的反序列化
  DataInputStream dis = new DataInputStream(in);
  int b = dis.read();
  int i = dis.readInt();
  long l= dis.readLong();
  byte bx = dis.readByte();
  double d = dis.readDouble();
  short s = dis.readShort();
  float f = dis.readFloat();
  boolean bol = dis.readBoolean();
  char c = dis.readChar();
  dis.close();
  System.out.print( b +" ");//254  fe
  System.out.print(i+" ");
  System.out.print(l+" ");
  System.out.print(bx+" ");
  System.out.print(d+" ");
  System.out.print(s+" ");
  System.out.print(f+" ");
  System.out.print(bol+" ");
  System.out.print(c+" ");
  
 }
}

 

 

5 字符串的序列化(文字的編碼方案)
 從char序列到byte序列 的轉換,叫"編碼"
 1) String 字符串本質上是Char
 
 2)utf-16be 編碼-----將16位char從中間切開爲2個byte
     utf -16be是將 unicode char[] 序列化爲byte[]的編碼方案
     可以支持65535個字符編碼,英文浪費空間

 如:
 char[] = ['A',    'B',    '中']
  對應     0041,0042,4e2d

 utf-8:國際標準,是將unicode編碼爲byte序列的方案,採用變長編碼 1-N方案,其中英文1個byte,中文3個byte
   unicoded的" 中": 4e 2d = 01001110 00101101
    utf-8的"中":e4 b8 ad =11100100 10111000 10101101
        1110xxxx 10xxxxxx 10xxxxxx

 以0開頭的是英文(0-127)
 110表示連續2字節表示一個字符
 1110表示連續3字節表示一個字符
 每一個數據字節以10開頭

GBK: 中國標準,支持20000+中日韓文,英文編碼1byte,中文2byte
 與unicode不兼容,中文windows默認gbk

ISO8859-1:只支持255個英文字符,不支持中文(Sun服務器默認編碼,如tomcat等)

例子

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class CharIODemo {
 public static void main(String[] args) 
  throws IOException{
  String str = "ABCD中國";
  System.out.println(str);
  //Java 的字符是16位 Unicode值,而文件是8位Byte序列
  
  //GBK
  System.out.println("GBK編碼方案,對字符編碼");
  String file = "gbk.txt";
  OutputStream out = new FileOutputStream(file);//默認GBK編碼方案
  byte[] gbk = str.getBytes("GBK");
  out.write(gbk);
  out.close();
  IOUtils.print(file);
  //UTF-16BE,每一個編碼是2個字節
  System.out.println("UTF-16BE編碼方案,對字符編碼");
  file = "utf-16be.txt";
  out = new FileOutputStream(file);
  byte[] utf16be = str.getBytes("UTF-16BE");
  out.write(utf16be);
  out.close();
  IOUtils.print(file);
  
  //UTF-8,英文是1個字節,中文是3個字節
  System.out.println("UTF-8編碼方案,對字符編碼");
  file = "utf-8.txt";
  out = new FileOutputStream(file);
  byte[] utf8 = str.getBytes("UTF-8");//編碼string -> byte[]
  out.write(utf8);
  out.close();
  IOUtils.print(file);
  
  byte[] buf = IOUtils.read("utf-8.txt");
  //new String(buf,"UTF-8"),構造器能夠將 byte編碼序列
  //解碼爲 char序列(字符串)
  String s = new String(buf,"UTF-8");//解碼byte-> String
  System.out.println(s);
 }
}

 

6 字符流IO(Reader Writer)
1) 字符的處理,一次處理一個字符(unicode編碼)
2) 字符的底層仍然是基本的字節流
3) 字符流的基本實現
 InputStreamReader 完成byte流解析爲char流,按照編碼解析
 OutputStreamWriter 提供char流到byte流,按照編碼處理
4) 字符流的過濾器
    是字符讀寫的功能擴展,極大的方便了文本的讀寫操做
    BufferedReader : readLine()   一次讀取一行
    PrintWriter : println()  一次打印一行
5)讀取一個文本文件
 InputStream is = new FileInputStream("test.txt");
 Reader in = new InputStreamReader(is);
 BufferedReader reader = new BufferedReader(in);
 或者
 BufferedReader in = new BufferedReader(new FileReader(filename));

例子:

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class TestReaderDemo {
 public static void main(String[] args) 
  throws IOException{
  //Scanner BufferedReader都是流的功能擴展,是過濾器
  // 不能單獨使用,最終須要依賴於基本byte流(in)
  //Scanner 提供了nextLine()方法//Java5之後
  //BufferedReader 提供了 readLine()方法,讀取一行
  //readLine()讀取到文件末尾返回null
  
  //逐行讀取文本文件,顯示到系統控制檯
  //工做中經常使用
  String file = "in.txt"; //爲當前工做區workspace/項目名/in.txt
  BufferedReader in = new BufferedReader(
    new InputStreamReader(
      new BufferedInputStream(
        new FileInputStream(file)),"gbk"));
  String str;
  while((str = in.readLine()) != null){
   System.out.println(str);
  }
  in.close();
 }

 


6)寫出一個文本文件
 PrintWriter out = new PrintWriter(new FileWriter(new FileOutputStream(filename)));
 或者
 PrintWriter out = new PrintWriter(
     new OutputStreamWriter(
      new FileOutputStream(filename)))
例子

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner;

public class SyncWriteDemo {
 public static void main(String[] args) 
  throws IOException{
  Scanner in = new Scanner(System.in);
  String file = "sync.txt";
  PrintWriter out = new PrintWriter(file,"UTF-8");
  while(true){
   String str = in.nextLine();
   out.println(str);
   if("q".equalsIgnoreCase(str)){
    break;
   }
  }
  out.close();
 }
}

 

7)系統的默認編碼,中文通常是GBK
如何查看默認編碼?

String encoding = System.getProperty("file.encoding");

 


7 對象的IO序列化和深層複製

什麼是對象序列化:
 將對象Object轉換爲byte序列,反之叫作對象的反序列華
1)序列化流,是過濾流
 ObjectOutputStream   方法 writeObject()  對象的序列化
 ObjectInputStream     方法readObject()  對象的反序列化
2)序列化接口(Serializable)


   對象必須實現"序列化接口Serializable"才能進行序列化,不然將出現不能序列化的異常
 Serializable是一個空的接口,沒有任何方法 ,僅做爲序列化的一個標識


3)JavaBean 規範規定,Java類必須實現Serializable接口


   Java API中的類大可能是符合Java Bean規範的,基本都實現了Serializable


4) 對象的序列化能夠變相實現對象的深層複製
例子

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectIODemo {
 public static void main(String[] args) 
  throws Exception{
  String file = "obj.dat";
  ObjectOutputStream out = new ObjectOutputStream(
    new BufferedOutputStream(
      new FileOutputStream(file)));
  Foo foo =new Foo();
  out.writeObject(foo);//將foo引用的對象,序列化到文件中
  out.close();
  
  //讀出
  ObjectInputStream in = new ObjectInputStream(
    new BufferedInputStream(
      new FileInputStream(file)));
  Foo foo1 = (Foo)in.readObject();//對象反序列化
  in.close();
  System.out.println(foo1.name);

  System.out.println("深層複製:對象被複制,對象屬性也被複制");
  System.out.println(foo==foo1);//false 對象複製了(一層)
  System.out.println(foo.name == foo1.name);//false ,屬性被複制了(二層)
  //利用序列化 和 反序列化  能夠簡潔的實現 對象的深層複製
 }

}
class Foo implements Serializable{//Serializable沒有聲明方法
 String name = "Tom";
}

 


淺層複製與深層複製
1)java的默認規則是淺層複製,性能好,但隔離性差,如(clone(),Arrays.copyOf)
 淺層複製 : 對象的引用不一樣,但對象中屬性的引用相同
2)利用序列化能夠實現深層複製
 深層複製: 對象的引用不一樣,但對象中的屬性的引用也不相同

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class DeepcopyDemo {
 public static Object deepCope(Object obj){
  try{
   //1. 對象序列化
   // 緩衝流: 字節數組輸出流
   ByteArrayOutputStream buf =
    new ByteArrayOutputStream();
   //對象輸出流
   ObjectOutputStream out = 
    new ObjectOutputStream(
      new ByteArrayOutputStream());
   
   out.writeObject(obj);//序列化對象到buf中
   out.close();
   
   //2 .對象的反序列化
   byte[] ary = buf.toByteArray();
   ByteArrayInputStream bais = 
    new ByteArrayInputStream(ary);
   ObjectInputStream in = 
    new ObjectInputStream(bais);
   Object o = in.readObject();//從ary反序列化
   in.close();
   return o;
   
  }catch(Exception e){
   e.printStackTrace();
   throw new RuntimeException(e);
  }
 }
}

 

以上用到的ByteArrayInputStreamByteArrayOutputStream

下面有一個ByteArrayInputStream和ByteArrayOutputStream的例子

例子

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;

import com.tarena.day18.IOUtils;

public class ByteArrayIODemo {
 public static void main(String[] args) 
  throws IOException{
  byte[] ary = {1,-1,127,-128};
  //   {00000001, 11111111, 01111111, 10000000}
  ByteArrayInputStream in = new ByteArrayInputStream(ary);
  int b = in.read();//1 00000000 00000000 00000000 00000001
  System.out.println(b);
  b = in.read();
  System.out.println(b);//255   00000000 00000000 00000000 11111111
  b = in.read();   
  System.out.println(b);//127   00000000 00000000 00000000  01111111
  b = in.read();
  System.out.println(b);//128   00000000 00000000 00000000  10000000
  b = in.read();
  System.out.println(b);//-1    11111111  11111111  11111111  11111111
  in.close();
  
  ByteArrayOutputStream out = new ByteArrayOutputStream();//默認開闢32byte的數組做爲輸出目標
  //若是滿了就自動擴容
  //out:[0,0,0,0,0,0,0,.....]
  //
  out.write(1);//[1,0,0,0,0,0,....]
  out.write(-2);//[1,fe,0,0,0,0,0,....]
  out.write(-1);//[1,fe,ff,0,0,0,0,....]
  out.close();
  byte[] buf = out.toByteArray();//複製有效部分
  IOUtils.print(buf);//[01, fe, ff ]
 }

}


原文:http://www.cnblogs.com/hqr9313/archive/2012/04/23/2467294.html

相關文章
相關標籤/搜索