Java_io体系之RandomAccessFile简介、走进源码及示例——20
Java_io體系之RandomAccessFile簡介、走進源碼及示例——20
?
RandomAccessFile
1、?????? 類功能簡介:
?
?????? 文件隨機訪問流、關心幾個特點:
?
1、他實現的接口不再是InputStream、OutputStream中的任何一個、而是實現的DataInput、DataOutput。這也注定了他可以對java基礎類型進行操作、而且是即可讀取、也可以寫入、關于這部分的方法大多數都是從DataInputStream、DataOutputStream那里蕩來的。
?
2、如其名、隨機流、這里的隨機并不是不可控制、不可預測的去訪問文件、而是可以通過指針的形式定位到具體的位置——“文件指針”、具體使用“文件指針”的方法:調用此流的seek(long n)方法來設置位置、使用此方法要注意的是如果傳入的n大于文件長度、此方法不會改變文件長度、只是當寫入下一個字節時會改變文件大小、即下一個寫入的字節是添加在n后的。如果n小于文件長度、則會從n位置開始覆蓋后面的file內容、
?
3、此流既可以讀取文件、也可以寫入文件、也可具有只讀功能、但是沒有只寫功能、具體是哪種類型是在構造方法中指定的——String mode;具體的區別上面有說明。。
?
???????????????? 這里把實例放在了前面、因為源碼和方法所占篇幅太長、有興趣的可繼續往下看。
?
2、?????? 實例演示:
?
?
package com.chy.io.original.test;import java.io.File; import java.io.IOException; import java.io.RandomAccessFile;public class RandomAccessFileTests {private static final File file = new File("D:\\rsf.txt");/*** 向文件中寫入內容*/public static void testRandomAccessFileWriter() throws IOException{//要先將已有文件刪除、避免干擾。if(file.exists()){file.delete();}RandomAccessFile rsfWriter = new RandomAccessFile(file, "rw");//不會改變文件大小、但是他會將下一個字符的寫入位置標識為10000、也就是說此后只要寫入內容、就是從10001開始存、rsfWriter.seek(10000);printFileLength(rsfWriter); //result: 0//會改變文件大小、只是把文件的size改變、并沒有改變下一個要寫入的內容的位置、這里注釋掉是為了驗證上面的seek方法的說明內容//rsfWriter.setLength(10000);printFileLength(rsfWriter); //result: 0//每個漢子占3個字節、寫入字符串的時候會有一個記錄寫入字符串長度的兩個字節rsfWriter.writeUTF("陳華應"); printFileLength(rsfWriter); //result: 10011//每個字符占兩個字節rsfWriter.writeChar('a');rsfWriter.writeChars("abcde");printFileLength(rsfWriter); //result: 10023//再從“文件指針”為5000的地方插一個長度為100、內容全是'a'的字符數組//這里file長依然是10023、因為他是從“文件指針”為5000的地方覆蓋后面的200個字節、下標并沒有超過文件長度rsfWriter.seek(5000);char[] cbuf = new char[100];for(int i=0; i?
3、 RandomAccessFile API簡介:
A:構造方法
RandomAccessFile(File file, String mode) 創建從中讀取和向其中寫入(可選)的隨機訪問文件流,該文件由 File 參數指定。 RandomAccessFile(String name, String mode) 從中讀取和向其中寫入(可選)的隨機訪問文件流,該文件具有指定名稱。 補充一:mode的取值有下面四種情況"r" 以只讀方式打開。調用結果對象的任何 write 方法都將導致拋出 IOException。
"rw" 打開以便讀取和寫入。
"rws" 打開以便讀取和寫入。相對于 "rw","rws" 還要求對“文件的內容”或“元數據”的每個更新都同步寫入到基礎存儲設備。
"rwd" 打開以便讀取和寫入,相對于 "rw","rwd" 還要求對“文件的內容”的每個更新都同步寫入到基礎存儲設備。
補充二:關于文件的“元數據”
The definition of metadata is "data about other data." With a file system, the data is contained in its files and directories, and the metadata tracks information about each of these objects: Is it a regular file, a directory,or a link? What is its size, creation date, last modified date, file owner, group owner, and access permissions?
補充三:"rw" "rws" "rwd"之間的區別
當操作的文件是存儲在本地的基礎存儲設備上時(如硬盤, NandFlash等),"rws" 或 "rwd", "rw" 才有區別。
當模式是 "rws" 并且 操作的是基礎存儲設備上的文件;那么,每次“更改文件內容[如write()寫入數據]” 或 “修改文件元數據(如文件的mtime)”時,都會將這些改變同步到基礎存儲設備上。
當模式是 "rwd" 并且 操作的是基礎存儲設備上的文件;那么,每次“更改文件內容[如write()寫入數據]”時,都會將這些改變同步到基礎存儲設備上。
當模式是 "rw" 并且 操作的是基礎存儲設備上的文件;那么,關閉文件時,會將“文件內容的修改”同步到基礎存儲設備上。至于,“更改文件內容”時,是否會立即同步,取決于系統底層實現。
一般使用前兩個就ok。
B:一般方法
void close() 關閉此隨機訪問文件流并釋放與該流關聯的所有系統資源。 FileChannel getChannel() 返回與此文件關聯的唯一 FileChannel 對象。 FileDescriptor getFD() 返回與此流關聯的不透明文件描述符對象。 long getFilePointer() 返回此文件中的當前偏移量。 long length() 返回此文件的長度。 int read() 從此文件中讀取一個數據字節。 int read(byte[] b) 將最多 b.length 個數據字節從此文件讀入 byte 數組。 int read(byte[] b, int off, int len) 將最多 len 個數據字節從此文件讀入 byte 數組。 boolean readBoolean() 從此文件讀取一個 boolean。 byte readByte() 從此文件讀取一個有符號的八位值。 char readChar() 從此文件讀取一個字符。 double readDouble() 從此文件讀取一個 double。 float readFloat() 從此文件讀取一個 float。 void readFully(byte[] b) 將 b.length 個字節從此文件讀入 byte 數組,并從當前文件指針開始。 void readFully(byte[] b, int off, int len) 將正好 len 個字節從此文件讀入 byte 數組,并從當前文件指針開始。 int readInt() 從此文件讀取一個有符號的 32 位整數。 String readLine() 從此文件讀取文本的下一行。 long readLong() 從此文件讀取一個有符號的 64 位整數。 short readShort() 從此文件讀取一個有符號的 16 位數。 int readUnsignedByte() 從此文件讀取一個無符號的八位數。 int readUnsignedShort() 從此文件讀取一個無符號的 16 位數。 String readUTF() 從此文件讀取一個字符串。 void seek(long pos) 設置到此文件開頭測量到的文件指針偏移量,在該位置發生下一個讀取或寫入操作。 void setLength(long newLength) 設置此文件的長度。 int skipBytes(int n) 嘗試跳過輸入的 n 個字節以丟棄跳過的字節。 void write(byte[] b) 將 b.length 個字節從指定 byte 數組寫入到此文件,并從當前文件指針開始。 void write(byte[] b, int off, int len) 將 len 個字節從指定 byte 數組寫入到此文件,并從偏移量 off 處開始。 void write(int b) 向此文件寫入指定的字節。 void writeBoolean(boolean v) 按單字節值將 boolean 寫入該文件。 void writeByte(int v) 按單字節值將 byte 寫入該文件。 void writeBytes(String s) 按字節序列將該字符串寫入該文件。 void writeChar(int v) 按雙字節值將 char 寫入該文件,先寫高字節。 void writeChars(String s) 按字符序列將一個字符串寫入該文件。 void writeDouble(double v) 使用 Double 類中的 doubleToLongBits 方法將雙精度參數轉換為一個 long,然后按八字節數量將該 long 值寫入該文件,先定高字節。 void writeFloat(float v) 使用 Float 類中的 floatToIntBits 方法將浮點參數轉換為一個 int,然后按四字節數量將該 int 值寫入該文件,先寫高字節。 void writeInt(int v) 按四個字節將 int 寫入該文件,先寫高字節。 void writeLong(long v) 按八個字節將 long 寫入該文件,先寫高字節。 void writeShort(int v) 按兩個字節將 short 寫入該文件,先寫高字節。 void writeUTF(String str) 使用 modified UTF-8 編碼以與機器無關的方式將一個字符串寫入該文件。4、 源碼分析
?
package com.chy.io.original.code;import java.io.Closeable; import java.io.EOFException; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.UTFDataFormatException; import java.nio.channels.FileChannel;import sun.nio.ch.FileChannelImpl;/*** 隨機訪問文件流、既可以對文件進行讀取、也可以對文件進行寫入、還可以寫入java基礎類型、不再是InputStream或者OutputStream的子類、* 而是實現了DataOutput、DataInput、通過這兩個接口也可以看出、此類具有將java基礎類型寫入文件或者讀取到程序中的功能、關于寫入/讀取文件基礎類型* 的操作大多數都是剽竊DataInputStream/DataOutputStream的。*/public class RandomAccessFile implements DataOutput, DataInput, Closeable {java.io.RandomAccessFileprivate FileDescriptor fd;private FileChannel channel = null;private boolean rw;//標識此文件是否既可以讀又可以寫//標識不同mode對應的值private static final int O_RDONLY = 1;private static final int O_RDWR = 2;private static final int O_SYNC = 4;private static final int O_DSYNC = 8;/*** 使用指定的文件、模式構造RandomAccessFile、初始化參數、打開到文件的連接*/public RandomAccessFile(String name, String mode)throws FileNotFoundException{this(name != null ? new File(name) : null, mode);}/*** 使用指定的文件、模式構造RandomAccessFile、初始化參數、打開到文件的連接*/public RandomAccessFile(File file, String mode)throws FileNotFoundException{String name = (file != null ? file.getPath() : null);int imode = -1;if (mode.equals("r"))imode = O_RDONLY;else if (mode.startsWith("rw")) {imode = O_RDWR;rw = true;if (mode.length() > 2) {if (mode.equals("rws"))imode |= O_SYNC;else if (mode.equals("rwd"))imode |= O_DSYNC;elseimode = -1;}}if (imode len) {newpos = len;}seek(newpos);/* return the actual number of bytes skipped */return (int) (newpos - pos);}// 'Write' primitives/*** 在當前“文件指針”標示的地方寫入一個字節*/public native void write(int b) throws IOException;/*** 將b的一部分寫入到文件中*/private native void writeBytes(byte b[], int off, int len) throws IOException;/*** 將b寫入到文件中*/public void write(byte b[]) throws IOException {writeBytes(b, 0, b.length); }/*** 將b的一部分寫入到文件中*/public void write(byte b[], int off, int len) throws IOException {writeBytes(b, off, len);}// 'Random access' stuff/*** 返回當前文件的偏移量、即“文件描述符”的位置*/public native long getFilePointer() throws IOException;/*** 設置“文件指針”的偏移量、從文件的開頭開始計數、如果pos大于文件的長度、也不會改變文件的大小、* 文件的大小只有在當“文件指針”指向文件最后的時候、再向文件中寫入字節才會擴展。*/public native void seek(long pos) throws IOException;/*** 返回文件的字節數*/public native long length() throws IOException;/*** 設置文件長度:* if(newLength > originalLength)* 擴展文件長度、新增加的長度使用默認值填充;* else* 截取源文件的前originalLength字節、如果源文件的偏移量大于newLength、則將源文件的偏移量設為newLength;*/public native void setLength(long newLength) throws IOException;/*** 關閉此流、釋放與此流有關的所有資源*/public void close() throws IOException {if (channel != null)channel.close();close0();}// 一些方法是從DataInputStream/DataOutputStream中剽竊來的。。。/*** 讀取一個boolean型數據*/public final boolean readBoolean() throws IOException {int ch = this.read();if (ch >> 8) & 0xFF);write((v >>> 0) & 0xFF);//written += 2;}/*** 將一個char寫入文件*/public final void writeChar(int v) throws IOException {write((v >>> 8) & 0xFF);write((v >>> 0) & 0xFF);//written += 2;}/*** 將一個int寫入文件*/public final void writeInt(int v) throws IOException {write((v >>> 24) & 0xFF);write((v >>> 16) & 0xFF);write((v >>> 8) & 0xFF);write((v >>> 0) & 0xFF);//written += 4;}/*** 將一個long寫入文件*/public final void writeLong(long v) throws IOException {write((int)(v >>> 56) & 0xFF);write((int)(v >>> 48) & 0xFF);write((int)(v >>> 40) & 0xFF);write((int)(v >>> 32) & 0xFF);write((int)(v >>> 24) & 0xFF);write((int)(v >>> 16) & 0xFF);write((int)(v >>> 8) & 0xFF);write((int)(v >>> 0) & 0xFF);//written += 8;}/*** 將一個long寫入文件*/public final void writeFloat(float v) throws IOException {writeInt(Float.floatToIntBits(v));}/*** 將一個double寫入文件。*/public final void writeDouble(double v) throws IOException {writeLong(Double.doubleToLongBits(v));}/*** 將一個字符串轉換成一串有序字節寫入*/public final void writeBytes(String s) throws IOException {int len = s.length();byte[] b = new byte[len];s.getBytes(0, len, b, 0);writeBytes(b, 0, len);}/*** 將一個字符串以一串有序字符寫入文件中*/public final void writeChars(String s) throws IOException {int clen = s.length();int blen = 2*clen;byte[] b = new byte[blen];char[] c = new char[clen];s.getChars(0, clen, c, 0);for (int i = 0, j = 0; i >> 8);b[j++] = (byte)(c[i] >>> 0);}writeBytes(b, 0, blen);}/*** 調用DataOutputStream的 writeUTF(String str, DataOutput out) 將一個字符串寫入文件。*/public final void writeUTF(String str) throws IOException {DataOutputStream.writeUTF(str, this);}private static native void initIDs();private native void close0() throws IOException;static {initIDs();}}?
?
更多IO內容:java_io 體系之目錄
總結
以上是生活随笔為你收集整理的Java_io体系之RandomAccessFile简介、走进源码及示例——20的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux网络编程中tcp_server
- 下一篇: Hark的数据结构与算法练习之基数排序