史上最全IO流詳解,看着一篇足矣

一:要了解IO,首先了解File類

 File類裏面的部分常量,方法java

No.windows

方法或常量數組

類型app

描述dom

1ide

public static final String pathSeparator函數

常量編碼

表示路徑的分隔符(windows是「;」)spa

2線程

public static final String separator

常量

表示路徑的分隔符(windows是「\」)

3

public File(String pathname)

構造

建立File類對象,傳入完整路徑

4

public boolean createNewFile()throws IOException

普通

建立新文件

5

public boolean delete()

普通

刪除文件

6

public boolean exists()

普通

判斷文件是否存在

7

public boolean isDirectory()

普通

判斷給定的路徑是否在一個目錄

8

public long length()

普通

返回文件的大小

9

public String[] list()

普通

列出指定目錄的所有內容,只是名稱

10

public File[] listFiles()

普通

列出指定目錄的所有內容,會有路徑

11

Public Boolean mkdir()

普通

建立一個目錄

12

Public Boolean renameTo(File dest)

普通

爲已有的文件重命名

 二:對於File類的基本操做

  a.在E盤建立一個hello.txt文件

File file=new File("e:"+File.separator+"hello.txt");
//不存在則建立新文件
if(!file.exists()){
  file.createNewFile();
}

  b.刪除剛剛建立的hello.txt文件

File f=new File("e:"+File.separator+"hello.txt"); 
//若是存在則刪除
if(f.exists()){
  f.delete();
}

  c.若是此文件存在,則刪除,若是不存在,則建立

File f=new File("e:"+File.separator+"hello.txt");
if(f.exists()){
  f.delete();
}else{
  try {
    f.createNewFile();
  } catch (IOException e) {
    e.printStackTrace();
  }
}

  d.建立文件夾,使用mkdir()方法;

File f=new File("e:"+File.separator+"hello");
f.mkdir();//建立文件夾

  f.列出指定目錄的所有文件,使用File裏面的2個方法

    public String[] list()

    public File[] listFiles()

//列出e盤下面全部的文件名(使用的是public String[] list())

  File f=new File("e:"+File.separator);
  String[] str=f.list();
  for(String s:str){
  System.out.println(s);
  }

  

//列出e盤下面全部文件的全路徑
File f = new File("E:" + File.separator);
File[] files = f.listFiles();
for (File file : files) {
	System.out.println(file);
}

  

  g.判斷一個路徑是否是文件夾(目錄)

File f=new File("e:"+File.separator);
if(f.isDirectory()){
    System.out.println(f.getPath()+"是目錄");
}else{
    System.out.println(f.getPath()+"不是目錄");
}

  h.列出一個路徑下面的所有文件,包括子文件下面的全部文件(使用遞歸)

public static void main(String[] args) {
    File f = new File("E:" + File.separator);
    print(f);
}
public static void print(File f) {
if (f != null) {//判斷是否是空
   if (f.isDirectory()) {//判斷是否是目錄 File[] files = f.listFiles(); if (files != null) { for (File file : files) { print(file); } } } else { System.out.println(f); } } }

  

 三:隨機流

  File類是針對文件自己進行操做,而要對文件內容進行操做,則可使用RandomAccessFile類(隨機讀寫流)

  構造函數(public RandomAccessFile(File file,String mode)throws FileNotFoundException)

  mode:模式,總共有3種模式

    r:讀

    w:寫

    rw:讀寫,若是文件不存在則會自動建立

  1.寫入

File f = new File("e:" + File.separator+"test.txt");
RandomAccessFile raf=new RandomAccessFile(f,"rw");//讀寫模式,若是該路徑不存在會自動建立(RandomAccessFile的更多操做請看源碼)
String name1="mm";
int age1 =20;
String name2="gg";
int age2=30;
//寫入操做 raf.writeBytes(name1); raf.writeInt(age1); raf.writeBytes(name2); raf.writeInt(age2); raf.close();

  2.讀取

File f = new File("E:" + File.separator+"test.txt");
RandomAccessFile raf=new RandomAccessFile(f,"r");//以讀模式打開
raf.skipBytes(6);//跳過第一我的的信息(第一我的的姓名+年齡+中間的空格爲6個字節)
byte[] bs=new byte[3];
for(int i=0;i<bs.length;i++){
    bs[i]=raf.readByte();
}
String name2=new String(bs);
int age2=raf.readInt();
System.out.println(name2+"  "+age2);

raf.seek(0);//指針回到文件開頭,讀取第二我的的信息
for(int i=0;i<bs.length;i++){
    bs[i]=raf.readByte();
}
String name1=new String(bs);
int age1=raf.readInt();
System.out.println(name1+"  "+age1);

  注意:java默認字符編碼的是unicode,佔兩個字節,可是在String換轉byte[]時用的getBytes()默認用的編碼進行轉換,那麼就會佔3個字節

四:字節流和字符流

   1.首先看下流的概念:在程序中全部的數據都是以流的方式進行傳輸或保存的,程序須要數據的時候要使用輸入流讀取數據,而當程序須要將一些數據保存起來的時候,就要    使用輸出流完成,程序中的輸入輸出都是以流的形式保存的,流中保存的實際上全都是字節文件

  2.字節流和字符流:在java.io包中操做文件內容的主要有兩大類:字節流、字符流,兩類都分爲輸入和輸出操做。在字節流中輸出數據主要是使用OutputStream完成,輸入使的 是InputStream,在字符流中輸出主要是使用Writer類完成,輸入流主要使用Reader類完成。(這四個都是抽象類

    java中提供了專用於輸入輸出功能的包Java.io,其中包括:
         InputStream,OutputStream,Reader,Writer
         InputStream 和OutputStream,兩個是爲字節流設計的,主要用來處理字節或二進制對象,
         Reader和 Writer.兩個是爲字符流(一個字符佔兩個字節)設計的,主要用來處理字符或字符串.

  3.對於字節流和字符流的理解(重點,看懂此處對於字節流和字符流有很大的幫助):

    a.字符流處理的單元爲2個字節的Unicode字符,分別操做字符、字符數組或字符串,而字節流處理單元爲1個字節,操做字節和字節數組。因此字符流是由Java虛擬機將字 節轉化爲2個字節的Unicode字符爲單位的字符而成的,因此它對多國語言支持性比較好!若是是音頻文件、圖片、歌曲,就用字節流好點,若是是關係到中文(文本)的,用字符流好點

    b.全部文件的儲存是都是字節(byte)的儲存,在磁盤上保留的並非文件的字符而是先把字符編碼成字節,再儲存這些字節到磁盤。在讀取文件(特別是文本文件)時,  也是一個字節一個字節地讀取以造成字節序列

    c.字節流可用於任何類型的對象,包括二進制對象,而字符流只能處理字符或者字符串,字節流提供了處理任何類型的IO操做的功能,但它不能直接處理Unicode字符,而字  符流就能夠

    d.字節流是最基本的,全部的InputStrem和OutputStream的子類都是,主要用在處理二進制數據,它是按字節來處理的 但實際中不少的數據是文本,又提出了字符流的概      念,它是按虛擬機的encode來處理,也就是要進行字符集的轉化 這兩個之間經過 InputStreamReader,OutputStreamWriter來關聯,其實是經過byte[]和String來關聯在實際開發中出現的漢字問題實際上都是在字符流和字節流之間轉化不統一而形成的 

    e.Reader類的read()方法返回類型爲int :做爲整數讀取的字符(佔兩個字節共16位),範圍在 0 到 65535 之間 (0x00-0xffff),若是已到達流的末尾,則返回 -1.inputStream的read()雖然也返回int,但因爲此類是面向字節流的,一個字節佔8個位,因此返回 0 到 255 範圍內的 int 字節值。若是由於已經到達流末尾而沒有可用的字節,則返回值-1。所以對於不能用0-255來表示的值就得用字符流來讀取!好比說漢字.

  4.操做流程

    1 使用File類打開一個文件

    2 經過字節流或字符流的子類,指定輸出的位置

    3 進行讀/寫操做

    4 關閉輸入/輸出

    IO操做屬於資源操做,必定要記得關閉

   5.字節流操做

    a.字節輸入流:OutputStream

     OutputStream是整個IO包中字節輸出流的最大父類,此類的定義以下:

     public abstract class OutputStream extends Object implements Closeable,Flushable

     從以上的定義能夠發現,此類是一個抽象類,若是想要使用此類的話,則首先必須經過子類實例化對象,那麼若是如今要操做的是一個文件,則可使用:                                        FileOutputStream類。經過向上轉型以後,能夠爲OutputStream實例化

       Closeable表示能夠關閉的操做,由於程序運行到最後確定要關閉

                 Flushable:表示刷新,清空內存中的數據

                 FileOutputStream類的構造方法以下:

                 public FileOutputStream(File file)throws FileNotFoundException

      寫數據:

File f = new File("e:" + File.separator+hello.txt");
OutputStream out=new FileOutputStream(f);//若是文件不存在會自動建立
String str="Hello World";
byte[] b=str.getBytes();
out.write(b);//由於是字節流,因此要轉化成字節數組進行輸出
out.close();

    也能夠一個字節一個字節進行輸出,以下:

File f = new File("e:" + File.separator+"hello.txt");
OutputStream out=new FileOutputStream(f);//若是文件不存在會自動建立
String str="Hello World";
byte[] b=str.getBytes();
for(int i=0;i<b.length;i++){
    out.write(b[i]);
}
out.close();

  

   以上輸出只會進行覆蓋,若是要追加的話,請看FileOutputStream類的另外一個構造方法:

   public FileOutputStream(File file,boolean append)throws FileNotFoundException

   在構造方法中,若是將append的值設置爲true,則表示在文件的末尾追加內容。

File f = new File("e:" + File.separator+"hello.txt");
OutputStream out=new FileOutputStream(f,true);//追加內容
//\r\n爲換行 String str="\r\nHello World"; byte[] b=str.getBytes(); for(int i=0;i<b.length;i++){ out.write(b[i]); } out.close();

 

 

    b.字節輸入流:InputStream

    既然程序能夠向文件中寫入內容,則就能夠經過InputStream從文件中把內容讀取進來,首先來看InputStream類的定義:

    public abstract class InputStream extends Object implements Closeable

    與OutputStream類同樣,InputStream自己也是一個抽象類,必須依靠其子類,若是如今是從文件中讀取,就用FileInputStream來實現。

    觀察FileInputStream類的構造方法:

    public FileInputStream(File file)throws FileNotFoundException

      讀文件:

File f = new File("e:" + File.separator+"hello.txt");
InputStream in=new FileInputStream(f);
byte[] b=new byte[1024];
int len=in.read(b);
in.close();
System.out.println(new String(b,0,len));

  但以上方法是有問題的,用不用開闢這麼大的一個字節數組,明顯是浪費嘛,咱們能夠根據文件的大小來定義字節數組的大小,File類中的方法:public long length()

File f = new File("e:" + File.separator+"hello.txt");
InputStream in=new FileInputStream(f);
byte[] b=new byte[(int) f.length()];
in.read(b);
in.close();
System.out.println(new String(b));

  一個字節一個字節讀入

File f = new File("e:" + File.separator+"hello.txt");
InputStream in=new FileInputStream(f);
byte[] b=new byte[(int) f.length()];
for(int i=0;i<b.length;i++){
    b[i]=(byte) in.read();
}
in.close();
System.out.println(new String(b));

  但以上狀況只適合知道輸入文件的大小,不知道的話用以下方法:

File f = new File("e:" + File.separator+"hello.txt");
InputStream in=new FileInputStream(f);
byte[] b=new byte[1024];
int temp=0;
int len=0;
while((temp=in.read())!=-1){//-1爲文件讀完的標誌
    b[len]=(byte) temp;
    len++;
}
in.close();
System.out.println(new String(b,0,len));

  

  6.字符流操做

    a.Writer自己是一個字符流的輸出類,此類的定義以下:

       public abstract class Writer extends Object implements Appendable,Closeable,Flushable

       此類自己也是一個抽象類,若是要使用此類,則確定要使用其子類,此時若是是向文件中寫入內容,因此應該使用FileWriter的子類。

       FileWriter類的構造方法定義以下:

       public FileWriter(File file)throws IOException

       字符流的操做比字節流操做好在一點,就是能夠直接輸出字符串了,不用再像以前那樣進行轉換操做了。

    b.寫文件

File f = new File("e:" + File.separator+"hello.txt");
Writer out=new FileWriter(f);
String str="Hello World";
out.write(str);
out.close();

  在默認狀況下再次輸出會覆蓋,追加的方法也是在構造函數上加上追加標記

File f = new File("e:" + File.separator+"hello.txt");
Writer out=new FileWriter(f,true);//追加
String str="\r\nHello World";
out.write(str);
out.close();

  字符輸入流:Reader

  Reader是使用字符的方式從文件中取出數據,Reader類的定義以下:

  public abstract class Reader extends Objects implements Readable,Closeable

  Reader自己也是抽象類,若是如今要從文件中讀取內容,則能夠直接使用FileReader子類。

  FileReader的構造方法定義以下:

  public FileReader(File file)throws FileNotFoundException

  以字符數組的形式讀取出數據:

File f = new File("e:" + File.separator+"hello.txt");
Reader input=new FileReader(f);
char[] c=new char[1024];
int len=input.read(c);
input.close();
System.out.println(new String(c,0,len));

  也能夠用循環方式,判斷是否讀到底:

File f = new File("e:" + File.separator+"hello.txt");
Reader input=new FileReader(f);
char[] c=new char[1024];
int temp=0;
int len=0;
while((temp=input.read())!=-1){
    c[len]=(char) temp;
    len++;
}
input.close();
System.out.println(new String(c,0,len));

  

   7.總結:字節流與字符流的區別

    a.字節流在操做的時候自己是不會用到緩衝區(內存)的,是與文件自己直接操做的,而字符流在操做的時候是使用到緩衝區的

    b.字節流在操做文件時,即便不關閉資源(close方法),文件也能輸出,可是若是字符流不使用close方法的話,則不會輸出任何內容,說明字符流用的是緩衝區,而且可使用flush方法強制進行刷新緩衝區,這時才能在不close的狀況下輸出內容

  8.使用場景:在全部的硬盤上保存文件或進行傳輸的時候都是以字節的方法進行的,包括圖片也是按字節完成,而字符是隻有在內存中才會造成的,因此使用字節的操做是最多  的。(例:若是要java程序實現一個拷貝功能,應該選用字節流進行操做(可能拷貝的是圖片),而且採用邊讀邊寫的方式(節省內存)。)

 五:字節流和字符流轉換

   OutputStreamWriter和InputStreamReader

   OutputStreamWriter:是Writer的子類,將輸出的字符流變爲字節流,即:將一個字符流的輸出對象變成字節流的輸出對象。

   InputStreamReader:是Reader的子類,將輸入的字節流變爲字符流,即:將一個字節流的輸入對象變成字符流的輸入對象。

  OutputStreamWriter的構造方法:

    public OutputStreamWriter(OutputStream out)

    例如,將字節的文件輸出流,以字符的形式輸出

File f = new File("e:" + File.separator+"hello.txt");
Writer out=new OutputStreamWriter(new FileOutputStream(f));
out.write("Hello World!!!");
out.close();

  讀得時候也能夠用字符流形式讀取字節流的對象

File f = new File("e:" + File.separator+"hello.txt");
Reader input=new InputStreamReader(new FileInputStream(f));
char[] c=new char[1024];
int len=input.read(c);
input.close();
System.out.println(new String(c,0,len));

  FileWriter和FileReader的說明

  從JDK文檔中能夠知道FileOutputStream是OutputStream的直接子類。FileInputStream也是InputStream的直接子類,可是在字符流文件的兩個操做類卻有一些特殊,FileWriter並不直接是Writer的子類,而是OutputStreamWriter的子類,而FileReader也不直接是Reader的子類,而是InputStreamReader的子類,那麼從這兩個類的繼承關係就能夠清楚的發現,不論是使用字節流仍是字符流實際上最終都是以字節的形式操做輸入輸出流的。也就是說,傳輸或者從文件中讀取數據的時候,文件裏真正保存的數據永遠是字節。

六:內存操做流

  ByteArrayInputStream和ByteArrayOutputStream

  以前所講解的程序中,輸出和輸入都是從文件中來得,固然,也能夠將輸出的位置設置在內存之上,此時就要使用ByteArrayInputStream、ByteArrayOutputStream來完成輸入輸出功能了

  ByteArrayInputStream的主要功能將內容輸入到內存之中

  ByteArrayOutputStream的主要功能是將內存中的數據輸出

  

  ByteArrayInputStream類的定義:

 

  public class ByteArrayInputStream extends InputStream

 

  構造方法:

 

  public ByteArrayInputStream(byte[] buf)

 

  接受一個byte數組,實際上內存的輸入就是在構造方法上將數據傳入到內存中。

 

  ByteArrayOutputStream:輸出就是從內存中寫出數據

 

  public void write(int b)

 

  

String str="HELLO WORlD!!!";
InputStream input=new ByteArrayInputStream(str.getBytes());
OutputStream output=new ByteArrayOutputStream();
int temp=0;
while((temp=input.read())!=-1){
    output.write(Character.toLowerCase(temp));
}
input.close();
output.close();
System.out.println(output.toString());

 

七:管道流

  

  管道流的主要做用是能夠進行兩個線程間的通信,分爲管道輸出流(PipedOutputStream)、管道輸入流(PipedInputStream),若是想要進行管道輸出,則必需要把輸出流連在輸入流之上,在PipedOutputStream類上有以下的一個方法用於鏈接管道:

  public void connect(PipedInputStream snk)throws IOException

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

class Send implements Runnable{

    private PipedOutputStream pos;//管道輸出流
    public Send(){
        pos=new PipedOutputStream();
    }
    @Override
    public void run() {
        String str="Hello World!";
        try {
            pos.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            pos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public PipedOutputStream getPos() {
        return pos;
    }
}

class Receive implements Runnable{

    private PipedInputStream pis;//管道輸入流
    public Receive(){
        pis=new PipedInputStream();
    }
    @Override
    public void run() {
        byte[] b=new byte[1024];
        int len=0;
        try {
            len=pis.read(b);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            pis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(new String(b,0,len));
    }
    public PipedInputStream getPis() {
        return pis;
    }
}

public class Test23 {
    public static void main(String[] args) {
        Send send=new Send();
        Receive receive=new Receive();
        try {
            send.getPos().connect(receive.getPis());//鏈接管道
        } catch (IOException e) {
            e.printStackTrace();
        }
        new Thread(send).start();//啓動線程
        new Thread(receive).start();//啓動線程
    }
}

  

 八:打印流

在整個IO包中,打印流是輸出信息最方便的類,主要包含字節打印流(PrintStream)和字符打印流(PrintWrite)。打印流提供了很是方便的打印功能,能夠打印任何的數據類型,例如:小數、整數、字符串等等。

使用PrintStream輸出信息:

File f = new File("e:" + File.separator+"hello.txt");
PrintStream output=new PrintStream(new FileOutputStream(f));
output.println("Hello World!");
output.print("1+1="+2);
output.close();

也就是說此時,其實是將FileOutputStream類的功能包裝了一下,這樣的設計在java中稱爲裝飾設計。

File f = new File("e:" + File.separator+"hello.txt");
PrintStream output=new PrintStream(new FileOutputStream(f));
String name="Jim";
int age=20;
float score=90.5f;
char sex='M';
output.printf("姓名:%s 年齡:%d 成績:%f 性別:%c", name,age,score,sex);
output.close();

你要是以爲%s %d %f %c太麻煩,能夠全用%s代替

 

九:BufferReader和Scanner

若是想要接收任意長度的數據,並且避免亂碼產生,就可使用BufferedReader

public class BufferedReader extends Reader

由於輸入的數據有可能出現中文,因此,此處使用字符流完成。BufferedReader是從緩衝區之中讀取內容,全部的輸入的字節數據都將放在緩衝區之中。

System.in自己表示的是InputStream(字節流),如今要求接收的是一個字符流,須要將字節流變成字符流才能夠,因此要用InputStreamReader

BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
String str=reader.readLine();
System.out.println(str);

  

在JDK1.5以後Java提供了專門的輸入數據類,此類能夠完成BufferedReader類的功能,也能夠方便的對輸入數據進行驗證,此類存放在java.util包中

使用Scanner接收鍵盤的輸入數據:

Scanner s=new Scanner(System.in);
String str=s.next();
System.out.println(str);

比直接使用BufferedReader更加方便,可是這個程序是有問題的,若是輸入的字符串中存在空格,那麼就會截止,若是咱們要接收空格的下,將分隔符變成「\n」。

Scanner s=new Scanner(System.in);
s.useDelimiter("\n");//使用分隔符
String str=s.next();
System.out.println(str);
相關文章
相關標籤/搜索