1. 程式人生 > >java i/o操作

java i/o操作

1. I/O介紹:

中I/O操作主要是指使用Java進行輸入,輸出操作. Java所有的I/O機制都是基於資料流進行輸入輸出,這些資料流表示了字元或者位元組資料的流動序列。Java.io是大多數面向資料流的輸入/輸出類的主要軟體包。此外,Java也對塊傳輸提供支援,在核心庫 java.nio中採用的便是塊IO。流IO的好處是簡單易用,缺點是效率較低。塊IO效率很高,但程式設計比較複雜。 Java.io包中包含了流式I/O所需要的所有類。在java.io包中有四個基本類:InputStream、OutputStream及Reader、Writer。 Java的IO模型設計非常優秀,它使用Decorator模式,按功能劃分Stream,您可以動態裝配這些Stream,以便獲得您需要的功能。例如,您需要一個具有緩衝的檔案輸入流,則應當組合使用FileInputStream和BufferedInputStream。
這裡寫圖片描述

io流的四個基本類
java.io包中包含了流式I/O所需要的所有類。在java.io包中有四個基本類:InputStream、OutputStream及Reader、Writer類,它們分別處理位元組流和字元流:
這裡寫圖片描述

一、java io的開始:檔案

public class Demo {

    public static void main(String[] args){

        File f = new File("e:\\file");

        if(f.isDirectory()){
            System.out
.println(f.getPath()); } } }

程式碼中isDirectory()方法是判斷檔案是資料夾還是一個檔案,getPath()方法是列印檔案(這裡指的是file資料夾)的路徑。
檔案刪除

import java.io.File;

public class Demo11 {

    public static void main(String[] args) {

        File f = new File("f:\\demo.txt");

        f.delete();
        if(boo){
            System.out
.println("成功刪除檔案"); } } }

File類獲取目錄子目錄

import java.io.File;
/**
 * 獲取一個目錄下的所有子項
 * @author Administrator
 */
public class FileDemo {
    public static void main(String[] args){
        /*
         * 檢視當前專案根目錄下的所有子項
         */
        File dir = new File(".");
        //首先判斷是否為一個目錄
        if(dir.isDirectory()){
            //獲取當前目錄下的所有子項
            File[] subs = dir.listFiles();
            for(File sub : subs){
                String name = sub.getName();
                //目錄是沒有長度的
                long length = sub.length();
                System.out.println(name+":"+length);
            }
        }
    }
}

FileFilter類

import java.io.File;
import java.io.FileFilter;

/**
 * listFiles方法支援檔案過濾器
 * 
 * FileFilter介面,實現該介面需要實現抽象方法: boolean accept(File f)該方法要求我們定義過濾條件
 * listFiles方法會將當前目錄下滿足accept方法的子項返回
 * @author Administrator
 */
public class FileDemo2 {
    public static void main(String[] args){
        File dir = new File(".");
        if(dir.isDirectory()){
            //建立過濾器例項
            FileFilter filter = new MyFilter();
            //使用過濾器過濾子項
            File[] subs  = dir.listFiles(filter);
            for(File sub : subs){
                System.out.println(
                                sub.getName());
            }
        }
    }
}
class MyFilter implements FileFilter{
    public boolean accept(File file) {
        System.out.println(
                    "正在過濾:"+file.getName());
        return file.getName().startsWith(".");
    }
} 

建立多級目錄下的一個檔案

import java.io.File;
import java.io.IOException;

/**
 * 建立多級目錄下的一個檔案
 * @author Administrator
 *
 */
public class FileDemo3 {
    public static void main(String[] args) throws IOException{      
        File file = new File(
                "a"+File.separator+
                "b"+File.separator+
                "c"+File.separator+
                "d"+File.separator+
                "e"+File.separator+
                "f"+File.separator+
                "g"+File.separator+
                "h.txt"
                );
        /*
         * 建立檔案時,應首先判斷當前檔案所在的
         * 目錄是否存在,因為若不存在,會丟擲
         * 異常的。
         */
        /*
         * File getParentFile()
         * 獲取當前檔案或目錄所在的父目錄
         */
        File parent = file.getParentFile();
        if(!parent.exists()){
            parent.mkdirs();
        }
        if(!file.exists()){
            file.createNewFile();
            System.out.println("檔案建立完畢");
        }

    }
}

RandomAccessFile用於讀寫檔案資料的類

mport java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException{
        /*
         *  對專案跟目錄下一個名為demo.dat
         *  的檔案內容進行讀寫 
         */
        RandomAccessFile raf
            = new RandomAccessFile("demo.dat","rw");        
//      File file = new File("demo.dat");
//      RandomAccessFile raf2= new RandomAccessFile(file,"rw");
        int num = 97;
        raf.write(num);     
        raf.close();// 使用IO後,一定要記得關閉
    }
}
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo2 {
    public static void main(String[] args) throws IOException{
            RandomAccessFile raf= new RandomAccessFile("demo.dat","r");
            int i = raf.read();
            System.out.println(i);
            //再讀取一個位元組
            i = raf.read();
            System.out.println(i);
            //再讀取一個位元組
            i = raf.read();
            System.out.println(i);
            raf.close();
    }
}

使用RandomAccessFile完成複製操作

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo3 {
    public static void main(String[] args) throws IOException{      
        /*
         * 1:建立一個RandomAccessFile用於讀取待複製的檔案
         * 2:建立一個RandomAccessFile用於將原檔案的中資料寫入該檔案
         * 3:迴圈從原檔案中讀取每一個位元組並寫入目標檔案中
         * 4:關閉兩個RandomAccessFile      
         */
        long start = System.currentTimeMillis();
        RandomAccessFile src= new RandomAccessFile("src.jpg","r");  
        RandomAccessFile des= new RandomAccessFile("copy.jpg","rw");
        int d = -1;
        while( (d = src.read()) != -1 ){
            des.write(d);
        }
        System.out.println("拷貝完畢");
        src.close();
        des.close();
        long end = System.currentTimeMillis();
        System.out.println("耗時:"+(end-start)+"ms");
    }
}

使用RandomAccessFile批量寫出一組位元組

import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo4 {
    public static void main(String[] args) throws IOException{
            RandomAccessFile raf= new RandomAccessFile("test.txt","rw");
            String str = "我愛北京天安門";
            /* String的getBytes()方法:將當前字串按照當前系統預設的字符集轉換為對應的位元組。*/
            byte[] buf = str.getBytes("gbk");
            raf.write(buf);
            raf.close();
    }
}

使用RandomAccessFile讀取一個位元組陣列的資料

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
public class RandomAccessFileDemo5 {
    public static void main(String[] args) throws IOException{
            RandomAccessFile raf= new RandomAccessFile("test.txt","r");
            /*int read(byte[] buf)一次嘗試從檔案中讀取buf陣列length個位元組並從該陣列的第一個位置處起存放實際讀取到的位元組。返回值為實際讀取到的位元組數*/
            byte[] buf = new byte[50];
            int len = raf.read(buf);
            System.out.println(len);
            System.out.println(Arrays.toString(buf));           
            /*從位元組陣列轉換為對應的字串*/
            String str = new String(buf,"GBK");
            System.out.println(str.trim());
            raf.close();
    }
}

使用RandomAccessFile基於快取形式複製檔案

import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo6 {
    public static void main(String[] args) throws IOException{
            RandomAccessFile src= new RandomAccessFile("src.jpg","r");      
            RandomAccessFile des= new RandomAccessFile("copy.jpg","rw");
            long start = System.currentTimeMillis();
            byte[] buf = new byte[1024*10];
            int len = -1;
            /*int read(byte[] buf)若返回值為-1,表示沒有資料可讀了*/
            while((len = src.read(buf))!=-1){
                /*void write(byte[] b,int offset,int len)該方法的作用是將給定的位元組陣列中offset處開始,連續len個位元組寫出*/
                    des.write(buf,0,len);
            }
            long end = System.currentTimeMillis();
            System.out.println("耗時:"+(end-start));
            src.close();
            des.close();
    }
}

使用RandomAccessFile向檔案中寫入基本型別資料

import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo7 {
    public static void main(String[] args) throws IOException{
            RandomAccessFile raf= new RandomAccessFile("raf.dat","rw");
            int num = Integer.MAX_VALUE;
            //連續寫4個位元組,將int值寫出
            raf.writeInt(num);
            raf.writeDouble(1.4);
            raf.writeLong(1234l);
            raf.close();
    }
}

使用RandomAccessFile讀取基本型別資料

import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo8 {
    public static void main(String[] args) throws IOException{
        RandomAccessFile raf= new RandomAccessFile("raf.dat","r");
        int i = raf.readInt();
        System.out.println(i);
        double d = raf.readDouble();
        System.out.println(d);
        long l = raf.readLong();
        System.out.println(l);
        raf.close();
    }
}

檢視RandomAccessFile的指標位置

import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException{
        RandomAccessFile raf= new RandomAccessFile("raf.dat","rw");
        /*
         * long getFilePointer()
         * 獲取當前RAF的指標位置
         */
        long p = raf.getFilePointer();
        System.out.println(p);//0
        raf.write(97);//寫一個位元組
        System.out.println(raf.getFilePointer());//1
        raf.writeInt(1);//連續寫4個位元組
        System.out.println(raf.getFilePointer());//5
        /*
         * 若想從檔案的某個地方讀取位元組
         * 需要先將指標移動到這個位置
         * void seek(long position)
         */
        raf.seek(0);
        //通過raf讀取一個位元組
        int n = raf.read();
        System.out.println(n);
        System.out.println(raf.getFilePointer());//1
        raf.close();
    }
}
import java.io.IOException;
import java.io.RandomAccessFile;
/**
 * int skipBytes(int n)
 * 該方法會嘗試跳過n個位元組,返回值為實際
 * 跳過的位元組數
 */
public class RandomAccessFileDemo2 {
    public static void main(String[] args) throws IOException{
        RandomAccessFile raf= new RandomAccessFile("raf.dat","r");//跳過1個位元組
        raf.skipBytes(1);
        int i = raf.readInt();
        System.out.println(i);
        raf.close();
        }
}

位元組流InputStream/OutputStream

1. InputStream抽象類

InputStream 為位元組輸入流,它本身為一個抽象類,必須依靠其子類實現各種功能,此抽象類是表示位元組輸入流的所有類的超類。 繼承自InputStream 的流都是向程式中輸入資料的,且資料單位為位元組(8bit);

InputStream是輸入位元組資料用的類,所以InputStream類提供了3種過載的read方法.Inputstream類中的常用方法:
  (1) public abstract int read( ):讀取一個byte的資料,返回值是高位補0的int型別值。若返回值=-1說明沒有讀取到任何位元組讀取工作結束。
  (2) public int read(byte b[ ]):讀取b.length個位元組的資料放到b陣列中。返回值是讀取的位元組數。該方法實際上是呼叫下一個方法實現的
  (3) public int read(byte b[ ], int off, int len):從輸入流中最多讀取len個位元組的資料,存放到偏移量為off的b陣列中。
  (4) public int available( ):返回輸入流中可以讀取的位元組數。注意:若輸入阻塞,當前執行緒將被掛起,如果InputStream物件呼叫這個方法的話,它只會返回0,這個方法必須由繼承InputStream類的子類物件呼叫才有用,
  (5) public long skip(long n):忽略輸入流中的n個位元組,返回值是實際忽略的位元組數, 跳過一些位元組來讀取
  (6) public int close( ) :我們在使用完後,必須對我們開啟的流進行關閉.
  這裡寫圖片描述
- 1) FileInputStream把一個檔案作為InputStream,實現對檔案的讀取操作
- 2) ByteArrayInputStream:把記憶體中的一個緩衝區作為InputStream使用
- 3) StringBufferInputStream:把一個String物件作為InputStream
- 4) PipedInputStream:實現了pipe的概念,主要線上程中使用
- 5) SequenceInputStream:把多個InputStream合併為一個InputStream

2.OutputStream抽象類

  OutputStream提供了3個write方法來做資料的輸出,這個是和InputStream是相對應的。
  1. public void write(byte b[ ]):將引數b中的位元組寫到輸出流。
  2. public void write(byte b[ ], int off, int len) :將引數b的從偏移量off開始的len個位元組寫到輸出流。
  3. public abstract void write(int b) :先將int轉換為byte型別,把低位元組寫入到輸出流中。
  4. public void flush( ) : 將資料緩衝區中資料全部輸出,並清空緩衝區。
  5. public void close( ) : 關閉輸出流並釋放與流相關的系統資源。
  這裡寫圖片描述
  
- 1) ByteArrayOutputStream:把資訊存入記憶體中的一個緩衝區中
- 2) FileOutputStream:把資訊存入檔案中
- 3) PipedOutputStream:實現了pipe的概念,主要線上程中使用
- 4) SequenceOutputStream:把多個OutStream合併為一個
流結束的判斷:方法read()的返回值為-1時;readLine()的返回值為null時。

3. 檔案輸入流: FileInputStream類

FileInputStream可以使用read()方法一次讀入一個位元組,並以int型別返回,或者是使用read()方法時讀入至一個byte陣列,byte陣列的元素有多少個,就讀入多少個位元組。在將整個檔案讀取完成或寫入完畢的過程中,這麼一個byte陣列通常被當作緩衝區,因為這麼一個byte陣列通常扮演承接資料的中間角色。
這裡寫圖片描述
作用:開啟檔案,從檔案讀資料到記憶體的類。
使用方法(1)
File fin=new File(“d:/abc.txt”);
FileInputStream in=new FileInputStream( fin);
使用方法(2)
FileInputStream in=new FileInputStream(“d: /abc.txt”);
程式舉例:將fos.dat程式的內容顯示在顯示器上
這裡寫圖片描述

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

public class FisDemo {
    public static void main(String[] args) throws IOException{
        FileInputStream fis= new FileInputStream("fos.dat");        
        int i = fis.read();
        System.out.println(i);//97
        byte[] buf = new byte[21];
        int len = fis.read(buf);
        String str = new String(buf,"UTF-8");
        System.out.println(str);
        fis.close();
    }
}

4.檔案輸出流:FileOutputStream類

  作用:用來處理以檔案作為資料輸出目的資料流,或者說是從記憶體區讀資料入檔案
FileOutputStream類用來處理以檔案作為資料輸出目的資料流。
  建立一個檔案流物件有兩種方法:
  方式1:
   File f=new File (“d:/myjava/write.txt “);
FileOutputStream out= new FileOutputStream (f);
  方式2:
  FileOutputStream out=new FileOutputStream(“d:/myjava/write.txt “);
  方式3:建構函式將 FileDescriptor()物件作為其引數。
  FileDescriptor() fd=new FileDescriptor();
  FileOutputStream f2=new FileOutputStream(fd);
  方式4:建構函式將檔名作為其第一引數,將布林值作為第二引數。
  FileOutputStream f=new FileOutputStream(“d:/abc.txt”,true);
  注意: (1)檔案中寫資料時,若檔案已經存在,則覆蓋存在的檔案;
  (2)的讀/寫操作結束時,應呼叫close方法關閉流。
程式舉例:使用鍵盤輸入一段文章,將文章儲存在檔案fos.dat中
這裡寫圖片描述

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FosDemo {
    public static void main(String[] args) throws IOException{
        FileOutputStream fos= new FileOutputStream("write.txt");
        fos.write(97);
        String str = "天安門上太陽升";
        byte[] buf = str.getBytes("UTF-8");
        fos.write(buf);
        fos.close();
    }
}

5. FileInputStream流和FileOutputStream的應用

package day02;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyDemo {
    public static void main(String[] args) throws IOException{
        FileInputStream fis= new FileInputStream("src.jpg");        
        FileOutputStream fos= new FileOutputStream("copy2.jpg");        
        byte[] buf = new byte[10240];
        int len = -1;
        while((len=fis.read(buf))!=-1){
            fos.write(buf,0,len);
        }
        System.out.println("複製完畢");
        fis.close();
        fos.close();
    }
}

6. 緩衝輸入輸出流 BufferedInputStream/ BufferedOutputStream

這裡寫圖片描述
計算機訪問外部裝置非常耗時。訪問外存的頻率越高,造成CPU閒置的概率就越大。為了減少訪問外存的次數,應該在一次對外設的訪問中,讀寫更多的資料。為此,除了程式和流節點間交換資料必需的讀寫機制外,還應該增加緩衝機制。緩衝流就是每一個數據流分配一個緩衝區,一個緩衝區就是一個臨時儲存資料的記憶體。這樣可以減少訪問硬碟的次數,提高傳輸效率。

BufferedInputStream:當向緩衝流寫入資料時候,資料先寫到緩衝區,待緩衝區寫滿後,系統一次性將資料傳送給輸出裝置。

BufferedOutputStream :當從向緩衝流讀取資料時候,系統先從緩衝區讀出資料,待緩衝區為空時,系統再從輸入裝置讀取資料到緩衝區。
1)將檔案讀入記憶體:
將BufferedInputStream與FileInputStream相接

FileInputStream in=new FileInputStream( “file1.txt ” );

BufferedInputStream bin=new BufferedInputStream( in);

2)將記憶體寫入檔案:
將BufferedOutputStream與 FileOutputStream相接

FileOutputStreamout=new FileOutputStream(“file1.txt”);

BufferedOutputStream bin=new BufferedInputStream(out);

3)鍵盤輸入流讀到記憶體
將BufferedReader與標準的資料流相接
InputStreamReader sin=new InputStreamReader (System.in) ;
BufferedReader bin=new BufferedReader(sin);
例子:
BufferedOutputStream

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class BosDemo {
    public static void main(String[] args) throws IOException{
        FileOutputStream fos= new FileOutputStream("bos.txt");
        BufferedOutputStream bos= new BufferedOutputStream(fos);                
        String str = "偉大領袖毛主席";
        byte[] buf = str.getBytes("UTF-8");
        bos.write(buf);
        /* 強制將當前緩衝流中的緩衝區中的資料全部寫出,無論緩衝區是否被裝滿*/
        bos.flush();
        bos.close();//close時,也會自動呼叫一次flush
    }
}

BufferedInputStream/ BufferedOutputStream加速檔案拷貝

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyDemo2 {
    public static void main(String[] args)throws IOException {
        FileInputStream fis= new FileInputStream("src.AVI");
        BufferedInputStream bis= new BufferedInputStream(fis);
        FileOutputStream fos= new FileOutputStream("copy2.AVI");
        BufferedOutputStream bos= new BufferedOutputStream(fos);
        int d = -1;
        while ((d = bis.read()) != -1) {
            bos.write(d);
        }
        System.out.println("複製完畢");
        /* 關閉流時,只關閉最外層的高階流即可*/
        bis.close();
        bos.close();
    }
}

7. 字元流Writer/Reader

Java中字元是採用Unicode標準,一個字元是16位,即一個字元使用兩個位元組來表示。為此,JAVA中引入了處理字元的流。

1. Reader抽象類
用於讀取字元流的抽象類。子類必須實現的方法只有 read(char[], int, int) 和 close()。但是,多數子類將重寫此處定義的一些方法,以提供更高的效率和/或其他功能。
這裡寫圖片描述
1) FileReader :與FileInputStream對應
主要用來讀取字元檔案,使用預設的字元編碼,有三種建構函式:
   (1)將檔名作為字串 :FileReader f=new FileReader(“c:/temp.txt”);
   (2)建構函式將File物件作為其引數。
   File f=new file(“c:/temp.txt”);
   FileReader f1=new FileReader(f);
   (3) 建構函式將FileDescriptor物件作為引數
   FileDescriptor() fd=new FileDescriptor()
   FileReader f2=new FileReader(fd);
2) CharArrayReader:與ByteArrayInputStream對應
  3) StringReader : 與StringBufferInputStream對應
  4) InputStreamReader
   從輸入流讀取位元組,在將它們轉換成字元:Public inputstreamReader(inputstream is);
  5) FilterReader: 允許過濾字元流 protected filterReader(Reader r);
  6) BufferReader :接受Reader物件作為引數,並對其新增字元緩衝器,使用readline()方法可以讀取一行。 Public BufferReader(Reader r);
2. Writer抽象類
寫入字元流的抽象類。子類必須實現的方法僅有 write(char[], int, int)、flush() 和 close()。但是,多數子類將重寫此處定義的一些方法,以提供更高的效率和/或其他功能。 其子類如下:
這裡寫圖片描述
3 .InputStream與Reader差別 OutputStream與Writer差別
InputStream和OutputStream類處理的是位元組流,資料流中的最小單位是位元組(8個bit)
Reader與Writer處理的是字元流,在處理字元流時涉及了字元編碼的轉換問題

import java.io.*;  
public class EncodeTest {  
    private static void readBuff(byte [] buff) throws IOException {  
       ByteArrayInputStream in =new ByteArrayInputStream(buff);  
        int data;  
        while((data=in.read())!=-1)   System.out.print(data+"  ");  
        System.out.println();     in.close();     }  

   public static void main(String args[]) throws IOException {  
       System.out.println("記憶體中採用unicode字元編碼:" );  
       char   c='好';  
       int lowBit=c&0xFF;     int highBit=(c&0xFF00)>>8;  
       System.out.println(""+lowBit+"   "+highBit);  
       String s="好";  
       System.out.println("本地作業系統預設字元編碼:");  
       readBuff(s.getBytes());  
       System.out.println("採用GBK字元編碼:");  
       readBuff(s.getBytes("GBK"));  
       System.out.println("採用UTF-8字元編碼:");        
       readBuff(s.getBytes("UTF-8"));      }  
} 

這裡寫圖片描述
Reader類能夠將輸入流中採用其他編碼型別的字元轉換為Unicode字元,然後在記憶體中為其分配記憶體
Writer類能夠將記憶體中的Unicode字元轉換為其他編碼型別的字元,再寫到輸出流中。

BufferedReader緩衝字元輸入流可以以行為單位讀取字串

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

public class BufferReaderDemo {
    public static void main(String[] args) throws IOException{
        FileInputStream fis= new FileInputStream("pw.txt");     
        InputStreamReader isr= new InputStreamReader(fis,"UTF-8");      
        BufferedReader br= new BufferedReader(isr);
        String str = null;
        while((str=br.readLine())!=null){
            System.out.println(str);
        }
        br.close();
    }
}

InputStreamReader字元輸入流用於讀取字元資料的流

package day03;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class ISRDemo {
    public static void main(String[] args)throws IOException{
        FileInputStream fis= new FileInputStream("osw.txt");

        InputStreamReader isr= new InputStreamReader(fis,"UTF-8");
        int d = -1;
        while((d = isr.read())!=-1){
            char c = (char)d;
            System.out.print(c);
        }
        isr.close();
    }
}



OutStream

FileInputStream和FileOutputStream

FileInputStream


import java.io.FileInputStream;
import java.io.IOException;
/**
 * FileInputStream 節點流用於從檔案中讀取位元組的流
 */
public class FisDemo {
    public static void main(String[] args) throws IOException{
        FileInputStream fis= new FileInputStream("fos.dat");        
        int i = fis.read();
        System.out.println(i);//97

        byte[] buf = new byte[21];
        int len = fis.read(buf);
        String str = new String(buf,"UTF-8");
        System.out.println(str);

        fis.close();
    }
}