RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,它提供了众多的方法来访问文件内容,它既可以读取文件内容,也可以向文件输出数据。与普通的输入/输出流不同的是,RandomAccessFile支持“随机访问”的方式,程序可以直接跳转到文件的任意地方来读写数据。
由于RandomAccessFile可以自由访问文件的任意位置,所以如果只需要访问文件部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择。
RandomAccessFile方法虽然多,但它有一个最大的局限,就是只能读写文件,不能读写其它IO节点。
RandomAccessFile对象也包含了一个记录指针,用以标识当前读写的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会向后移动n个字节。除此之外,RandomAccessFile可以自由移动该记录指针。RandomAccessFile包含了两个方法来操作文件记录指针。
Constructor | Description |
---|---|
RandomAccessFile(File file, String mode) |
Creates a random access file stream to read from, and optionally to write to, the file specified by the
File argument. 4种mode: (1)"r":只读模式打开指定文件。如果试图对该RandomAccessFile执行写入方法,都将抛出IOException异常;
(2)"rw":以读、写方式打开指定文件。如果文件尚不存在,则尝试创建该文件;
(3)"rws":以读、写方式打开指定文件。相对于"rw"模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备;
(4)"rwd":以读、写方式打开指定文件。相对于"rw"模式,还要求对文件内容的每个更新都同步写入到底层存储设备。
|
RandomAccessFile(String name, String mode) |
Creates a random access file stream to read from, and optionally to write to, a file with the specified name.
|
Modifier and Type | Method | Description |
---|---|---|
void |
close() |
Closes this random access file stream and releases any system resources associated with the stream.
|
FileChannel |
getChannel() |
Returns the unique
FileChannel object associated with this file. |
FileDescriptor |
getFD() |
Returns the opaque file descriptor object associated with this stream.
|
long |
getFilePointer() |
Returns the current offset in this file.(返回文件记录指针的当前位置)
|
long |
length() |
Returns the length of this file.
|
int |
read() |
Reads a byte of data from this file.
|
int |
read(byte[] b) |
Reads up to
b.length bytes of data from this file into an array of bytes. |
int |
read(byte[] b, int off, int len) |
Reads up to
len bytes of data from this file into an array of bytes. |
boolean |
readBoolean() |
Reads a
boolean from this file. |
byte |
readByte() |
Reads a signed eight-bit value from this file.
|
char |
readChar() |
Reads a character from this file.
|
double |
readDouble() |
Reads a
double from this file. |
float |
readFloat() |
Reads a
float from this file. |
void |
readFully(byte[] b) |
Reads
b.length bytes from this file into the byte array, starting at the current file pointer. |
void |
readFully(byte[] b, int off, int len) |
Reads exactly
len bytes from this file into the byte array, starting at the current file pointer. |
int |
readInt() |
Reads a signed 32-bit integer from this file.
|
String |
readLine() |
Reads the next line of text from this file.
|
long |
readLong() |
Reads a signed 64-bit integer from this file.
|
short |
readShort() |
Reads a signed 16-bit number from this file.
|
int |
readUnsignedByte() |
Reads an unsigned eight-bit number from this file.
|
int |
readUnsignedShort() |
Reads an unsigned 16-bit number from this file.
|
String |
readUTF() |
Reads in a string from this file.
|
void |
seek(long pos) |
Sets the file-pointer offset, measured from the beginning of this file, at which the next read or write occurs.(将文件记录指针定位到pos位置)
|
void |
setLength(long newLength) |
Sets the length of this file.
|
int |
skipBytes(int n) |
Attempts to skip over
n bytes of input discarding the skipped bytes. |
void |
write(byte[] b) |
Writes
b.length bytes from the specified byte array to this file, starting at the current file pointer. |
void |
write(byte[] b, int off, int len) |
Writes
len bytes from the specified byte array starting at offset off to this file. |
void |
write(int b) |
Writes the specified byte to this file.
|
void |
writeBoolean(boolean v) |
Writes a
boolean to the file as a one-byte value. |
void |
writeByte(int v) |
Writes a
byte to the file as a one-byte value. |
void |
writeBytes(String s) |
Writes the string to the file as a sequence of bytes.
|
void |
writeChar(int v) |
Writes a
char to the file as a two-byte value, high byte first. |
void |
writeChars(String s) |
Writes a string to the file as a sequence of characters.
|
void |
writeDouble(double v) |
Converts the double argument to a
long using the doubleToLongBits method in class Double , and then writes that long value to the file as an eight-byte quantity, high byte first. |
void |
writeFloat(float v) |
Converts the float argument to an
int using the floatToIntBits method in class Float , and then writes that int value to the file as a four-byte quantity, high byte first. |
void |
writeInt(int v) |
Writes an
int to the file as four bytes, high byte first. |
void |
writeLong(long v) |
Writes a
long to the file as eight bytes, high byte first. |
void |
writeShort(int v) |
Writes a
short to the file as two bytes, high byte first. |
void |
writeUTF(String str) |
Writes a string to the file using modified UTF-8 encoding in a machine-independent manner.
|
1 package com.zyjhandsome.io; 2 3 import java.io.*; 4 5 public class RandomAccessFileTest { 6 7 public static void main(String[] args) { 8 // TODO Auto-generated method stub 9 try { 10 RandomAccessFile raf = new RandomAccessFile("D:\zhaoyingjun\eclipse-workspace\CollectionTest\src\com\zyjhandsome\io\RandomAccessFileTest.java", "r"); 11 // 获取RandomAccessFile对象文件指针的位置,初始位置是0 12 System.out.println("RandomAccessFile的文件指针的初始位置:" + raf.getFilePointer()); 13 // 移动raf文件的文件记录指针的位置 14 raf.seek(300); 15 byte[] bbuf = new byte[1024]; 16 // 用于保存实际读取的字节数 17 int hasRead = 0; 18 // 使用循环来重复“取水”过程 19 // while ( (hasRead = raf.read(bbuf)) > 0 ) 20 // { 21 // // 取出“竹简”中水滴(字节),将字节数组转换成字符串输入 22 // System.out.print(new String(bbuf, 0, hasRead)); 23 // } 24 // 第二种写法 25 while ( (hasRead = raf.read()) > 0 ) 26 { 27 // 取出“竹简”中水滴(字节),将字节数组转换成字符串输入 28 System.out.print((char)hasRead); 29 } 30 } catch (FileNotFoundException e) { 31 // TODO Auto-generated catch block 32 e.printStackTrace(); 33 } catch (IOException e) { 34 // TODO Auto-generated catch block 35 e.printStackTrace(); 36 } 37 } 38 }
1 RandomAccessFile的文件指针的初始位置:0 2 me\io\RandomAccessFileTest.java", "r"); 3 // ????RandomAccessFile???ó??????????????????????????0 4 System.out.println("RandomAccessFile??????????????????????" + raf.getFilePointer()); 5 // ????raf???????????????????????? 6 raf.seek(300); 7 byte[] bbuf = new byte[1024]; 8 // ????±?????????????×????? 9 int hasRead = 0; 10 // ???????·???????°?????±???? 11 // while ( (hasRead = raf.read(bbuf)) > 0 ) 12 // { 13 // // ?????°???ò?±???????¨×?????????×?????×é×?????×?·??????? 14 // System.out.print(new String(bbuf, 0, hasRead)); 15 // } 16 // ????????·¨ 17 while ( (hasRead = raf.read()) > 0 ) 18 { 19 // ?????°???ò?±???????¨×?????????×?????×é×?????×?·??????? 20 System.out.print((char)hasRead); 21 } 22 } catch (FileNotFoundException e) { 23 // TODO Auto-generated catch block 24 e.printStackTrace(); 25 } catch (IOException e) { 26 // TODO Auto-generated catch block 27 e.printStackTrace(); 28 } 29 } 30 }
下面程序示范了如何向指定文件后追加内容,为了追加内容,程序应该先将记录指针移动到文件最后,然后开始向文件中输出内容。
1 package com.zyjhandsome.io; 2 3 import java.io.*; 4 5 public class AppendContent { 6 7 public static void main(String[] args) { 8 // TODO Auto-generated method stub 9 try { 10 RandomAccessFile raf = new RandomAccessFile("D:\zhaoyingjun\else\Test\AppendContent.txt", "rw"); 11 // 将记录指针移动到AppendContent.txt文件的最后 12 raf.seek(raf.length()); 13 // raf.writeChars("追加的内容! "); // 会出现乱码 14 // raf.writeChars("Hello, world "); // 15 raf.write("追加的内容! ".getBytes()); 16 } catch (FileNotFoundException e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } catch (IOException e) { 20 // TODO Auto-generated catch block 21 e.printStackTrace(); 22 } 23 } 24 }
RandomAccessFile依然不能向文件的指定位置插入内容,如果直接将文件记录指针移动到中间某位置后开始输出,则新输出的内容会覆盖文件中原有的内容。如果需要向指定位置插入内容,程序需要先把插入点后面的内容读入缓冲区,等把需要插入的数据写入文件后,再将缓冲区的内容追加到文件后面。
1 package com.zyjhandsome.io; 2 3 import java.io.*; 4 5 public class InsertContent { 6 7 public static void insert(String fileName, long pos, String insertContent) throws IOException 8 { 9 File tmp = File.createTempFile("tmp", null); 10 tmp.deleteOnExit(); 11 try { 12 RandomAccessFile raf = new RandomAccessFile(fileName, "rw"); 13 // 使用临时文件来保存插入点后的数据 14 FileOutputStream tmpOut = new FileOutputStream(tmp); 15 FileInputStream tmpIn = new FileInputStream(tmp); 16 raf.seek(pos); 17 // --------下面代码将插入点后的内容读入临时文件中保存-------- 18 byte[] bbuf = new byte[64]; 19 // 用于保存实际读取的字节数 20 int hasRead = 0; 21 // 使用循环方式读取插入点后的数据 22 while ( (hasRead = raf.read()) > 0 ) 23 { 24 tmpOut.write(hasRead); 25 } 26 // --------下面代码用于插入内容-------- 27 // 把文件记录指针重新定位到pos位置 28 raf.seek(pos); 29 // 追加需要插入的内容 30 raf.write(insertContent.getBytes()); 31 // --------追加临时文件中的内容-------- 32 while ( (hasRead = tmpIn.read()) > 0) 33 { 34 raf.write((char)hasRead); 35 } 36 } catch (Exception e) { 37 // TODO Auto-generated catch block 38 e.printStackTrace(); 39 } 40 } 41 42 public static void main(String[] args) throws IOException { 43 // TODO Auto-generated method stub 44 insert("D:\zhaoyingjun\eclipse-workspace\CollectionTest\src\com\zyjhandsome\io\InsertContent.java", 45, "//插入的内容 "); 45 } 46 }
输出结果(查看InsertContent.java文件):
1 package com.zyjhandsome.io; 2 3 import java.io//插入的内容 4 .*; 5 6 public class InsertContent { 7 8 public static void insert(String fileName, long pos, String insertContent) throws IOException 9 { 10 File tmp = File.createTempFile("tmp", null); 11 tmp.deleteOnExit(); 12 try { 13 RandomAccessFile raf = new RandomAccessFile(fileName, "rw"); 14 // 使用临时文件来保存插入点后的数据 15 FileOutputStream tmpOut = new FileOutputStream(tmp); 16 FileInputStream tmpIn = new FileInputStream(tmp); 17 raf.seek(pos); 18 // --------下面代码将插入点后的内容读入临时文件中保存-------- 19 byte[] bbuf = new byte[64]; 20 // 用于保存实际读取的字节数 21 int hasRead = 0; 22 // 使用循环方式读取插入点后的数据 23 while ( (hasRead = raf.read()) > 0 ) 24 { 25 tmpOut.write(hasRead); 26 } 27 // --------下面代码用于插入内容-------- 28 // 把文件记录指针重新定位到pos位置 29 raf.seek(pos); 30 // 追加需要插入的内容 31 raf.write(insertContent.getBytes()); 32 // --------追加临时文件中的内容-------- 33 while ( (hasRead = tmpIn.read()) > 0) 34 { 35 raf.write((char)hasRead); 36 } 37 } catch (Exception e) { 38 // TODO Auto-generated catch block 39 e.printStackTrace(); 40 } 41 } 42 43 public static void main(String[] args) throws IOException { 44 // TODO Auto-generated method stub 45 insert("D:\zhaoyingjun\eclipse-workspace\CollectionTest\src\com\zyjhandsome\io\InsertContent.java", 45, "//插入的内容 "); 46 } 47 }