Java筆記 - IO流 - 其他類

RandomAccessFile隨機訪問文件

RandomAccessFile是Object的子類。一般IO流都是成對出現的,但是RandomAccessFile和打印流、序列流一樣都是單獨存在的。
特點:
1. 和打印流序列流不同的是RandomAccessFile既可以讀也可以寫。
2. RandomAccessFile的內部其實是一個byte類型的數組,數組可以延長,該數組存在一個指向數組的索引,稱之爲文件指針。
3. 可以通過getFilePointer方法獲取指針的位置,通過seek方法設置指針的位置。
4. 它可以對數組進行讀和寫,數組是byte類型的,所以RandomAccessFile類其實是對字節輸出流和字節輸入流進行了封裝
5. RandomAccessFile對象的源和目的只能是文件。

RandomAccessFile raf = new RandomAccessFile("E:\\raf.txt","rw");
raf.write("張三".getBytes());
raf.writeInt(97);
raf.write("李四".getBytes());
raf.write(98);
raf.close();

輸出結果:

張三   a李四b

這裏是a和b是因爲記事本把寫進去的97和98解析了,不管怎麼解析,最底層的97和98是不變的,所以這裏沒有問題。而如果我們修改代碼
raf.write(609);
輸出結果卻也是a。因爲int類型是4個字節,它只寫最低位的字節。如果我們想寫原字節,就要用writeInt方法, 所以a前面有3個空格。
並且如果使用RandomAccessFile創建文件,文件不存在,則創建,文件存在,則不創建。這和一般的輸出流不一樣,其他的輸出流都是不管文件存在不存在都會創建。如果文件存在,繼續寫入數據,就會把原數據覆蓋。

RandomAccessFile raf = new RandomAccessFile("E:\\raf.txt","rw");
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println("name="+name);
System.out.println("age="+age);

raf.close();

輸出結果:

name=張三
age=97

在讀age的時候我們不能拿數組讀,讀完轉成String然後打印出來,因爲age應該是一個int類型的值,不能用String類型。所以需要一個專門讀int類型值的方法readInt(),讀完就是97了。

操作指針讀寫

設置指針:seek
獲取指針:getFilePointer
因爲內部其實是一個數組,所以指針位置從0開始。

RandomAccessFile raf = new RandomAccessFile("E:\\raf.txt","rw");

raf.seek(8);
raf.write("王五".getBytes());
raf.writeInt(99);
System.out.println("指針位置在"+raf.getFilePointer()) ;
raf.close();

輸出結果:

指針位置在16
//記事本中內容:張三   a王五c,覆蓋掉了李四,但是張三依然保留。

PipedInputStream和PipedOutputStream管道流

管道流的主要作用就是可以進行兩個線程之間的通訊,一個線程作爲管道輸出流,一個線程作爲管道輸入流。它不同於其他的輸入輸出流,管道輸出流只能連接到管道輸入流。不建議對這兩個對象使用單線程,因爲這兩個輸入輸出流是相互關聯的。如果恰好先執行的是輸入流,而輸出流還沒有往外寫數據,read方法是一個阻塞式方法,這時候就會死鎖。

public static void main(String[] args) throws IOException {

    PipedInputStream input = new PipedInputStream();
    PipedOutputStream output = new PipedOutputStream();

    input.connect(output);

    new Thread(new Input(input)).start();
    new Thread(new Output(output)).start();

}

//管道輸入流線程
class Input implements Runnable{

    private PipedInputStream in;
    Input(PipedInputStream in){
        this.in = in;
    }
    public void run(){
        try {
            byte[] buf = new byte[1024];
            int len = in.read(buf);

            String s = new String(buf,0,len);

            System.out.println("s="+s);
            in.close();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

//管道輸出流線程
class Output implements Runnable{
    private PipedOutputStream out;
    Output(PipedOutputStream out){
        this.out = out;
    }
    public void run(){
        try {
            Thread.sleep(5000);
            out.write("hi,管道來了!".getBytes());
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
}

輸出結果:

hi,管道來了!

DateInputStream和DateOutputStream

DataInputStream和DataOutputStream都是Java中輸入輸出流的裝飾類。數據輸出流允許應用程序以適當方式將基本 Java 數據類型寫入輸出流中。然後,應用程序可以使用數據輸入流將數據讀入。
這兩個流對象也要對應着使用。
這兩個流對象中的writeInt、readInt等方法其實在RandomAccessFile類和ObjectInputStream、ObjectOutputStream類中也都存在,但是這些方法的使用場景不同,一個是專門用來隨機訪問文件的,一個是專門用來對對象序列化的。
如果只想操作Java的基本數據類型,就可以使用DateInputStream和DateOutputStream。

DataOutputStream dos = new DataOutputStream(new FileOutputStream("G:\\datastreamdemo.txt"));
dos.writeUTF("你好");
dos.close();

DataInputStream dis = new DataInputStream(new FileInputStream("G:\\datastreamdemo.txt"));
String str = dis.readUTF();
System.out.println(str);
dis.close();

輸出結果:

你好

ByteArrayInputStream和ByteArrayOutputStream

這兩個是操作字節數組的流對象,他們的源和目的都是內存,所以不需要調用系統的底層資源,不需要關流。
ByteArrayOutputStream:
此類實現了一個輸出流,其中的數據被寫入一個 byte 數組。緩衝區會隨着數據的不斷寫入而自動增長。可使用 toByteArray() 和 toString() 獲取數據。
ByteArrayInputStream :
包含一個內部緩衝區,該緩衝區包含從流中讀取的字節。內部計數器跟蹤 read 方法要提供的下一個字節。

ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write("abcd".getBytes());

byte[] buf = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(buf);

int ch = 0;
while((ch = bis.read())!=-1){
    System.out.println(ch);
}

輸出結果:

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