Java(9-1)輸入與輸出(二)

上節我們關注了 文本形式的讀入和寫出的操作(UTF-8編碼)。 這回,我們要看看在Java中如何對文件以 010101 二進制的形式 來進行讀寫 。

Part 1.1 DataInput 和 DataOutput接口的介紹

DataOutput接口中定義了用二進制格式讀取,數組、字符、boolean值和字符串的方法; 例如,writeInt總是將一個正數寫出爲4字節的二進制數量值,而不管他有多少位,writeDouble總是將一個double值寫出爲8字節的二進制數量值。 這樣子會比解析文本要快!

writeByte 讀取一個字節
writeInt  讀取四個字節(一般說)
...

而爲了都會數據,可以使用DataInput接口中定義的一些類似的方法

readInt ...
readByte ...
...

DataInputStream類實現了DataInput接口,爲了從文件中讀入二進制數據,可以將DataInputStream與某個字節源相結合,例如FileInputStream

DataInputStream in = new DataInputStream(new FileInputStream("employee.dat"));

與此類似,要想寫出二進制數據,我們可以使用實現了DataOutput接口的DataOutputStream類:

DataOutputStram out = new DataOutputStream(new FileOutputStream("employee.dat"));

Part 2.1 隨機訪問文件(可用於多線程複製文件)

RandomAccessFile類可以在文件中的任何位置查找或寫入數據。磁盤文件都是隨機訪問的,但是網絡套接字通信的輸入\輸出劉不是!你可以打開一個隨機訪問文件只用於讀入或者同時用於讀寫,你可以通過字符串 r 或 rw 作爲構造器的第二個參數來指定這個選項。

RandomAccessFile in = new RandomAccessFile("employee.dat","r");
RandomAccessFile inOut = new RandomAccess("employee.dat","rw");

當你將已有文件作爲RandomAccessFile打開時,這個文件並不會刪除。

隨機訪問文件有一個表示下一個將被讀入或寫出的字節所處位置的文件指針,seek方法可用來將這個文件指針設置到文件的任意字節位置,seek的參數是一個long型的整數,他的值位於0到文件的字節長度之間 。

getFilePointer方法將放回文件指針當前的位置。

RandomAccessFile類同時實現了DataInput和DataOutput接口。爲了讀寫,我們可以使用前面說過的 readInt writeInt 之類的方法 。

下面的代碼是以二進制的形式進行讀和寫:

package readAndwriteBy10;

import java.io.*;
import TextFileTest.Employee;

public class ReadWrite10 {
    /**
     * java二進制形式寫出數據
     */
    public void wirteBinary() {  
        try {  
            DataOutputStream os = new DataOutputStream(  
                    new BufferedOutputStream(new FileOutputStream(  
                            "E:\\data.dat")));  
            os.writeInt(1001);  
            os.writeByte(520);  
            os.writeBoolean(true);  
            os.writeFloat(10.0f);  
            os.writeLong(100l);  
            os.writeUTF("讀寫二進制文件");  

            os.flush();  
            os.close();  

        } catch (IOException e) {  

        }  
    }  
    /**
     * java以二進制形式讀入數據
     */
    public void readBinary() {  
        try {  
            DataInputStream is = new DataInputStream(  
                    new BufferedInputStream(new FileInputStream(  
                            "E:\\data.dat")));  
            System.out.println(is.readInt());  
            System.out.println(is.readByte());  
            System.out.println(is.readBoolean());  
            System.out.println(is.readFloat());  
            System.out.println(is.readLong());  
            System.out.println(is.readUTF());  

            is.close();  
        } catch (IOException e) {  

        }  
    }  
}

下面的代碼是,應用隨機訪問文件類,來寫的一個多線程複製文件程序

package mastercn;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;


public class CopyFile implements Runnable {
    //來源文件
    private String sourceFileName;
    //目標文件
    private String targetFileName;
    //分塊總數
    private int blockCount;
    //開始COPY的塊序號
    private int blockNo;
    //緩存大小
    private int maxBuffSize=1024*1024;
    /**
     * 將sourceFileName文件分blockCount塊後的第blockNo塊複製至sourceFileName
     * @param sourceFileName 來源文件全名
     * @param targetFileName 目標文件全名
     * @param blockCount 文件分塊COPY數
     * @param blockNo 開始COPY的塊序號
     */
    public CopyFile(String sourceFileName,String targetFileName,int blockCount,int blockNo)
    {
        this.sourceFileName=sourceFileName;
        this.targetFileName=targetFileName;
        this.blockCount=blockCount;
        this.blockNo=blockNo;
    }
    public void run() {
        //得到來源文件
        File file=new File(sourceFileName);
        //得到來源文件的大小
        long size=file.length();
        //根據文件大小及分塊總數算出單個塊的大小
        long blockLenth=size/blockCount;
        //算出當前開始COPY的位置
        long startPosition=blockLenth*blockNo;
        //實例化緩存
        byte[] buff=new byte[maxBuffSize];
        try{
            //從源文件得到輸入流
            InputStream inputStream=new FileInputStream(sourceFileName);
            //得到目標文件的隨機訪問對象
            RandomAccessFile raf=new RandomAccessFile(targetFileName,"rw");
            //將目標文件的指針偏移至開始位置
            raf.seek(startPosition);
            //當前讀取的字節數
            int curRedLength;
            //累計讀取字節數的和
            int totalRedLength=0;
            //將來源文件的指針偏移至開始位置
            inputStream.skip(startPosition);
            //依次分塊讀取文件
            while((curRedLength=inputStream.read(buff))>0 && totalRedLength<blockLenth)
            {
                //將緩存中的字節寫入文件?目標文件中
                raf.write(buff, 0, curRedLength);
                //累計讀取的字節數
                totalRedLength+=curRedLength;
            }
            //關閉相關資源
            raf.close();
            inputStream.close();
        }catch(Exception ex)
        {
            ex.printStackTrace();
        }
    }

}
 ExpandedBlockStart.gif
package mastercn;

public class Test {

    /**
     * @param args
     */
    //來源文件
    private static String sourceFile;
    //目標文件
    private static String targetFile;
    //分塊數
    private static int blockCount;

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //
        sourceFile=args[0];
        targetFile=args[1];
        blockCount=Integer.parseInt(args[2]);
        //記錄開始時間
        long beginTime=System.currentTimeMillis();
        //依次分塊進行文件COPY
        for(int i=0;i<blockCount;i++)
        {
            //實例化文件複製對象
            CopyFile copyFile=new CopyFile(sourceFile,targetFile,blockCount,i);
            //實例化線程
            Thread thread=new Thread(copyFile);
            //開始線程
            thread.start();
            try
            {
                //加入線程
                thread.join();
            }
            catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
        //計算耗時
        long endTime=System.currentTimeMillis();
        //輸出耗時
        System.out.println("共用時:"+(endTime-beginTime)+"ms");

    }
}

上面那段代碼轉載字`這裏 , 標叔 具體出處不詳。

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