Java 输入/输出——处理流(RandomAccessFile)

  RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,它提供了众多的方法来访问文件内容,它既可以读取文件内容,也可以向文件输出数据。与普通的输入/输出流不同的是,RandomAccessFile支持“随机访问”的方式,程序可以直接跳转到文件的任意地方来读写数据。

  由于RandomAccessFile可以*访问文件的任意位置,所以如果只需要访问文件部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择。

  RandomAccessFile方法虽然多,但它有一个最大的局限,就是只能读写文件,不能读写其它IO节点。

  RandomAccessFile对象也包含了一个记录指针,用以标识当前读写的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会向后移动n个字节。除此之外,RandomAccessFile可以*移动该记录指针。RandomAccessFile包含了两个方法来操作文件记录指针。

Constructors 
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.
All Methods Instance Methods Concrete Methods 
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.
 package com.zyjhandsome.io;

 import java.io.*;

 public class RandomAccessFileTest {

     public static void main(String[] args) {
// TODO Auto-generated method stub
try {
RandomAccessFile raf = new RandomAccessFile("D:\\zhaoyingjun\\eclipse-workspace\\CollectionTest\\src\\com\\zyjhandsome\\io\\RandomAccessFileTest.java", "r");
// 获取RandomAccessFile对象文件指针的位置,初始位置是0
System.out.println("RandomAccessFile的文件指针的初始位置:" + raf.getFilePointer());
// 移动raf文件的文件记录指针的位置
raf.seek(300);
byte[] bbuf = new byte[1024];
// 用于保存实际读取的字节数
int hasRead = 0;
// 使用循环来重复“取水”过程
// while ( (hasRead = raf.read(bbuf)) > 0 )
// {
// // 取出“竹简”中水滴(字节),将字节数组转换成字符串输入
// System.out.print(new String(bbuf, 0, hasRead));
// }
// 第二种写法
while ( (hasRead = raf.read()) > 0 )
{
// 取出“竹简”中水滴(字节),将字节数组转换成字符串输入
System.out.print((char)hasRead);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
 RandomAccessFile的文件指针的初始位置:0
me\\io\\RandomAccessFileTest.java", "r");
// ????RandomAccessFile???ó??????????????????????????0
System.out.println("RandomAccessFile??????????????????????" + raf.getFilePointer());
// ????raf????????????????????????
raf.seek(300);
byte[] bbuf = new byte[1024];
// ????±?????????????×?????
int hasRead = 0;
// ???????·???????°?????±????
// while ( (hasRead = raf.read(bbuf)) > 0 )
// {
// // ?????°???ò?±???????¨×?????????×?????×é×?????×?·???????
// System.out.print(new String(bbuf, 0, hasRead));
// }
// ????????·¨
while ( (hasRead = raf.read()) > 0 )
{
// ?????°???ò?±???????¨×?????????×?????×é×?????×?·???????
System.out.print((char)hasRead);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

  下面程序示范了如何向指定文件后追加内容,为了追加内容,程序应该先将记录指针移动到文件最后,然后开始向文件中输出内容。

 package com.zyjhandsome.io;

 import java.io.*;

 public class AppendContent {

     public static void main(String[] args) {
// TODO Auto-generated method stub
try {
RandomAccessFile raf = new RandomAccessFile("D:\\zhaoyingjun\\else\\Test\\AppendContent.txt", "rw");
// 将记录指针移动到AppendContent.txt文件的最后
raf.seek(raf.length());
// raf.writeChars("追加的内容!\r\n"); // 会出现乱码
// raf.writeChars("Hello, world\r\n"); //
raf.write("追加的内容!\r\n".getBytes());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

  RandomAccessFile依然不能向文件的指定位置插入内容,如果直接将文件记录指针移动到中间某位置后开始输出,则新输出的内容会覆盖文件中原有的内容。如果需要向指定位置插入内容,程序需要先把插入点后面的内容读入缓冲区,等把需要插入的数据写入文件后,再将缓冲区的内容追加到文件后面。

 package com.zyjhandsome.io;

 import java.io.*;

 public class InsertContent {

     public static void insert(String fileName, long pos, String insertContent) throws IOException
{
File tmp = File.createTempFile("tmp", null);
tmp.deleteOnExit();
try {
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
// 使用临时文件来保存插入点后的数据
FileOutputStream tmpOut = new FileOutputStream(tmp);
FileInputStream tmpIn = new FileInputStream(tmp);
raf.seek(pos);
// --------下面代码将插入点后的内容读入临时文件中保存--------
byte[] bbuf = new byte[64];
// 用于保存实际读取的字节数
int hasRead = 0;
// 使用循环方式读取插入点后的数据
while ( (hasRead = raf.read()) > 0 )
{
tmpOut.write(hasRead);
}
// --------下面代码用于插入内容--------
// 把文件记录指针重新定位到pos位置
raf.seek(pos);
// 追加需要插入的内容
raf.write(insertContent.getBytes());
// --------追加临时文件中的内容--------
while ( (hasRead = tmpIn.read()) > 0)
{
raf.write((char)hasRead);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
insert("D:\\zhaoyingjun\\eclipse-workspace\\CollectionTest\\src\\com\\zyjhandsome\\io\\InsertContent.java", 45, "//插入的内容\r\n ");
}
}

  输出结果(查看InsertContent.java文件):

 package com.zyjhandsome.io;

 import java.io//插入的内容
.*; public class InsertContent { public static void insert(String fileName, long pos, String insertContent) throws IOException
{
File tmp = File.createTempFile("tmp", null);
tmp.deleteOnExit();
try {
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
// 使用临时文件来保存插入点后的数据
FileOutputStream tmpOut = new FileOutputStream(tmp);
FileInputStream tmpIn = new FileInputStream(tmp);
raf.seek(pos);
// --------下面代码将插入点后的内容读入临时文件中保存--------
byte[] bbuf = new byte[64];
// 用于保存实际读取的字节数
int hasRead = 0;
// 使用循环方式读取插入点后的数据
while ( (hasRead = raf.read()) > 0 )
{
tmpOut.write(hasRead);
}
// --------下面代码用于插入内容--------
// 把文件记录指针重新定位到pos位置
raf.seek(pos);
// 追加需要插入的内容
raf.write(insertContent.getBytes());
// --------追加临时文件中的内容--------
while ( (hasRead = tmpIn.read()) > 0)
{
raf.write((char)hasRead);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
insert("D:\\zhaoyingjun\\eclipse-workspace\\CollectionTest\\src\\com\\zyjhandsome\\io\\InsertContent.java", 45, "//插入的内容\r\n ");
}
}
上一篇:Spring MVC 急速集成 Shiro 实录


下一篇:Java 多线程 锁 存款 取款