最近很多小伙伴都在问RandomAccessFilejava这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展JavaI/O系统学习系列一:File和RandomAccessFile
最近很多小伙伴都在问RandomAccessFile java这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展Java I/O系统学习系列一:File和RandomAccessFile、JAVA IO - RandomAccessFile、JAVA IO - RandomAccessFile Seek学习、Java IO 4 : RandomAccessFile等相关知识,下面开始了哦!
本文目录一览:- RandomAccessFile java
- Java I/O系统学习系列一:File和RandomAccessFile
- JAVA IO - RandomAccessFile
- JAVA IO - RandomAccessFile Seek学习
- Java IO 4 : RandomAccessFile
RandomAccessFile java
RandomAccessFile 用来支持读写随机存取文件的类。提供“文件指针”,类似于游标和下标,使用getFilePointer()方法获得,利用seek()方法设置下标。
public RandomAccessFile(String name, String mode){}
mode:文件操作的模式,此参数有固定的输入字串:“r”,“rw”,“rws”,“rwd”
读取文件内容:
public int read(){};
读取文件数据的一个字节。一个字节以0-255的整数返回,返回-1表示到达文件的末尾。
public int read(byte b[], int off, int len){}
从文件中读取一定长度的字节,放入到参数1的数组中。返回-1表示到达文件的末尾。
public int read(byte b[]){}
从文件中读取b.length长度的字节,放入到参数b中。
public final String readLine(){}
读取文件的下一行内容
seek()方法:设置文件指针的偏移量。若偏移量超出了文件长度,不会改变文件长度。
public long length(){} 获取文件的长度
public void setLength(long newLength){} 设置文件的长度。若比原来的小,那多出来的文件要被切掉。
使用:
public static void readFile(String filename) throws Exception{
RandomAccessFile raf = new RandomAccessFile(filename, "rw");
raf.writeInt(1);
raf.writeChars("A");
}
Java I/O系统学习系列一:File和RandomAccessFile
I/O系统即输入/输出系统,对于一门程序语言来说,创建一个好的输入/输出系统并非易事。因为不仅存在各种I/O源端和想要与之通信的接收端(文件、控制台、网络链接等),而且还需要支持多种不同方式的通信(顺序、随机存取、缓冲、二进制、按字符、按行、按字等)。
Java类库的设计者通过创建大量的类来解决这个难题,比如面向字节的类(字节流,InputStream、OutputStream)、面向字符和基于Unicode的类(字节流,Reader、Writer)、nio类(新I/O,为了改进性能及功能)等。所以,在充分理解Java I/O系统以便正确地运用之前,我们需要学习相当数量的类。因此一开始可能会对Java I/O系统提供的如此多的类感到迷惑,不过在我们系统地梳理完整个Java I/O系统并将这部分知识与融入到自我的整个知识体系中后,我们就能很快消除这种迷惑。
在I/O这个专题里面,我会总结Java 中涉及到的大多数I/O相关类的用法,从传统I/O诸如:File、字节流、字符流、序列化到新I/O:nio。在本节中我会先总结File和RandomAccessFile的相关知识,按照如下顺序:
File
RandomAccessFile
总结
1. File
1.1 File简介常用方法
根据官方文档的解释,Java中的File类是文件和目录路径的抽象,用户通过File直接执行与文件或目录相关的操作。我的理解就是File类的作用是用来指代文件或者目录的,通过File的抽象我们可以很方便的操作文件或目录,无需关心操作系统的差异。官方文档是这样描述的:
An abstract representation of file and directory pathnames.
User interfaces and operating systems use system-dependent pathname strings to name files and directories. This class presents an abstract, system-independent view of hierarchical pathnames.
用户接口和操作系统通过系统相关的路径名来命名文件和目录。而File类提供了一个抽象地、系统无关的视角来描述分层次路径名。File代表抽象路径名,有两个部分组成:
- 一个可选的系统相关的前缀,比如磁盘驱动器说明符(disk-drive specifier),unix系统中是“/”而windows系统中则是“\”;
- 0或多个字符串名称组成的序列;
关于File的用法,我觉得直接通过示例来学习会比较高效:
public class FileDemo {
public static void main(String[] args) throws IOException {
File dir = new File("f:/dirDemo");
System.out.println("dir exists: " + dir.exists());
dir.mkdirs();
System.out.println("dir exists: " + dir.exists());
if(dir.isFile()) {
System.out.println("dir is a file.");
}else if(dir.isDirectory()) {
System.out.println("dir is a directory");
}
File file = new File("f:/dirDemo/fileDemo");
System.out.println(
"\n Absolute path: " + file.getAbsolutePath() +
"\n Can read: " + file.canRead() +
"\n Can write: " + file.canWrite() +
"\n getName: " + file.getName() +
"\n getParent: " + file.getParent() +
"\n getPath: " + file.getPath() +
"\n length: " + file.length() +
"\n lastModified: " + file.lastModified() +
"\n isExist: " + file.exists());
file.createNewFile();
System.out.println("is file exist: " + file.exists());
if(file.isFile()) {
System.out.println("file is a file.");
}else if(file.isDirectory()) {
System.out.println("file is a directory");
}
System.out.println();
for(String filename : dir.list()) {
System.out.println(filename);
}
}
}
输出结果:
dir exists: false
dir exists: true
dir is a directory
Absolute path: f:\dirDemo\fileDemo
Can read: false
Can write: false
getName: fileDemo
getParent: f:\dirDemo
getPath: f:\dirDemo\fileDemo
length: 0
lastModified: 0
isExist: false
is file exist: true
file is a file.
fileDemo
在这个简单demo中我们用到多种不同的文件特征查询方法来显示文件或目录路径的信息:
- getAbsolutePath(),获取文件或目录的绝对路径;
- canRead()、canWrite(),文件是否可读/可写;
- getName(),获取文件名;
- getParent(),获取父一级的目录路径名;
- getPath(),获取文件路径名;
- length(),文件长度;
- lastModified(),文件最后修改时间,返回时间戳;
- exists(),文件是否存在;
- isFile(),是否是文件;
- isDirectory(),是否是目录;
- mkdirs(),创建目录,会把不存在的目录一并创建出来;
- createNewFile(),创建文件;
- list(),可以返回目录下的所有File名,以字符数组的形式返回;
exists()方法可以返回一个File实例是否存在,这里的存在是指是否在磁盘上存在,而不是指File实例存在于虚拟机堆内存中。一个File类的实例可能表示一个实际的文件系统如文件或目录,也可能没有实际意义,仅仅只是一个File类,并没有关联实际文件,如果没有则exists()返回false。
1.2 File过滤器
list()方法返回的数组中包含此File下的所有文件名,如果想要获得一个指定的列表,比如,希望得到所有扩展名为.java的文件,可以使用“目录过滤器”(实现了FilenameFilter接口),在这个类里面可以指定怎样显示符合条件的File对象。我们把一个自己实现的FilenameFilter传入list(FilenameFilter filter)方法中,在这个被当做参数的FilenameFilter中重写其accept()方法,指定我们自己想要的逻辑即可,这其实是策略模式的体现。
比如我们只要获取当前项目跟目录下的xml文件:
public class XmlList {
public static void main(final String[] args) {
File file = new File(".");
String list;
list = file.list(new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
Pattern pattern = Pattern.compile("(.*)\\.xml");
return pattern.matcher(name).matches();
}
});
Arrays.sort(list,String.CASE_INSENSITIVE_ORDER);
for(String dirItem : list)
System.out.println(dirItem);
}
}
在这个例子中,我们用匿名内部类的方式给list()传参,accept()方法内部我们指定了正则过滤策略,在调用File的list()方法时会自动为此目录对象下的每个文件名调用accept()方法,来判断是否要将该文件包含在内,判断结果由accept()返回的布尔值来表示。
如上也只是罗列了一些个人认为File类较常用的方法,也只是一部分,若需要更详细信息请参考官方文档。
1.3 目录工具
接下来我们来看一个实用工具,可以获得指定目录下的所有或者符合要求的File集合:
public class Directory {
// local方法可以获得指定目录下指定文件的集合
public static File[] local(File dir,String regex) {
return dir.listFiles(new FilenameFilter() {
private Pattern pattern = Pattern.compile(regex);
@Override
public boolean accept(File dir, String name) {
return pattern.matcher(new File(name).getName()).matches();
}
});
}
public static File[] local(String dir,String regex) {
return local(new File(dir),regex);
}
// walk()方法可以获得指定目录下所有符合要求的文件或目录,包括子目录下
public static TreeInfo walk(String start,String regex) {
return recurseDirs(new File(start),regex);
}
public static TreeInfo walk(File start,String regex) {
return recurseDirs(start,regex);
}
public static TreeInfo walk(String start) {
return recurseDirs(new File(start),".*");
}
public static TreeInfo walk(File start) {
return recurseDirs(start,".*");
}
static TreeInfo recurseDirs(File startDir,String regex) {
TreeInfo treeInfo = new TreeInfo();
for(File item : startDir.listFiles()) {
if(item.isDirectory()) {
treeInfo.dirs.add(item);
treeInfo.addAll(recurseDirs(item,regex));
}else {
if(item.getName().matches(regex))
treeInfo.files.add(item);
}
}
return treeInfo;
}
public static class TreeInfo implements Iterable<File>{
public List<File> files = new ArrayList();
public List<File> dirs = new ArrayList();
@Override
public Iterator<File> iterator() {
return files.iterator();
}
void addAll(TreeInfo other) {
files.addAll(other.files);
dirs.addAll(other.dirs);
}
}
}
通过工具中的local()方法,我们可以获得指定目录下符合要求文件的集合,通过walk()方法可以获得指定目录下所有符合要求的文件或目录,包括其子目录下的文件,这个工具只是记录在这里以备不时之需。
2. RandomAccessFile
因为File类知识文件的抽象表示,并没有指定信息怎样从文件读取或向文件存储,而向文件读取或存储信息主要有两种方式:
- 通过输入输出流,即InputStream、OutputStream;
- 通过RandomAccessFile;
输入输出流的方式我们后面会专门总结,这也是Java I/O系统中很大的一块,本文会讲一下RandomAccessFile,因为它比较独立,和流的相关性不大。
RandomAccessFile是一个完全独立的类,其拥有和我们后面将总结的IO类型有本质不同的行为,可以在一个文件内向前和向后移动。我们来看一下其主要方法:
- void write(int d) 向文件中写入1个字节,写入的是传入的int值对应二进制的低8位;
- int read() 读取1个字节,并以int形式返回,如果返回-1则代表已到文件末尾;
- int read(byte[] data) 一次性从文件中读取字节数组总长度的字节量,并存入到该字节数组中,返回的int值代表读入的总字节数,如果返回-1则代表未读取到任何数据。通常字节数组的长度可以指定为1024*10(大概10Kb的样子,效率比较好);
- int read(byte[] data, int off, int len) 一次性从文件中读取最多len个字节,并存入到data数组中,从下标off处开始;
- void write(int b) 往文件中写入1个字节的内容,所写的内容为传入的int值对应二进制的低8位;
- write(byte b[]) 往文件中写入一个字节数组的内容;
- write(byte b[], int off, int len) 往文件中写入从数组b的下标off开始len个字节的内容;
- seek(long pos) 设置文件指针偏移量为指定值,即在文件内移动至新的位置;
- long getFilePointer() 获取文件指针的当前位置;
- void close() 关闭RandomAccessFile;
上面只是一部分方法,更多请参考官方文档。我们再来看一个简单demo学习一下:
public class RandomAccessFileDemo {
public static void main(String[] args) {
File file = new File("./test.txt");
if(!file.exists()) {
try {
file.createNewFile();
} catch (IOException e1) {
e1.printStackTrace();
}
}
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile("./test.txt","rw");
raf.write(1000);
raf.seek(0);
System.out.println(raf.read());
raf.seek(0);
System.out.println(raf.readInt());
} catch (FileNotFoundException e) {
System.out.println("file not found");
} catch (EOFException e) {
System.out.println("reachs end before read enough bytes");
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}finally {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
输出结果:
232
reachs end before read enough bytes
在RandomAccessFile的构造器中有两个参数,第一个是文件路径或者File,代表该RandomAccessFile要操作的文件,第二个是读写模式。如果操作的文件不存在,在模式为“rw”时会直接创建文件,如果是“r”则会抛出异常。
这是一个简单的例子,首先创建文件test.txt,然后创建一个和该文件关联的RandomAccessFile,指定读写模式为读写,调用write()写入1000,这里只会写入一个字节,跳到文件头部,读取1个字节,输出232(正好是1000对应二进制的低8位),再跳到文件头部,调用readInt()读取1个整数,这时候因为文件中只有1个字节,所以抛出EOFException异常,最后关闭RandomAccessFile。
如上例子我们学习了RandomAccessFile的基本用法,这里有一点需要注意,RandomAccessFile是基于文件指针从当前位置来读写的,并且写入操作是直接将插入点后面的内容覆盖而不是插入。如果我们想实现插入操作,则需要将插入点后面的内容先保存下来,再写入要插入的内容,最后将保存的内容添加进来,看下面的例子:
public class RandomAccessFileDemo {
public static void main(String[] args) throws IOException {
File file = new File("f:/test.txt");
file.createNewFile();
// 创建临时空文件用于缓冲,并指定在虚拟机停止时将其删除
File temp = File.createTempFile("temp", null);
temp.deleteOnExit();
RandomAccessFile raf = null;
try {
// 首先往文件中写入下面的诗句,并读取出来在控制台打印
raf = new RandomAccessFile(file,"rw");
raf.write("明月几时有,把酒问青天".getBytes());
raf.seek(0);
byte[] b = new byte[60];
raf.read(b, 0, 30);
System.out.println(new String(b));
// 接下来在诗句中间再插入一句诗
raf.seek(12);
FileOutputStream fos = new FileOutputStream(temp);
FileInputStream fis = new FileInputStream(temp);
byte[] buffer = new byte[10];
int num = 0;
while(-1 != (num = raf.read(buffer))) {
fos.write(buffer, 0, num);
}
raf.seek(12);
raf.write("但愿人长久,千里共婵娟。".getBytes());
// 插入完成后将缓冲的后半部分内容添加进来
while(-1 != (num = fis.read(buffer))) {
raf.write(buffer, 0, num);
}
raf.seek(0);
raf.read(b, 0, 60);
System.out.println(new String(b));
System.out.println();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
raf.close();
}
}
}
输出结果,插入诗句成功:
明月几时有,把酒问青天
明月几时有,但愿人长久,千里共婵娟。把酒问青天
3. 总结
本文是Java I/O系统系列第一篇,主要总结了File和RandomAccessFile的一些知识。
- File类是对文件和目录路径的抽象,用户通过File来直接执行与文件或目录相关的操作,无需关心操作系统的差异。
- RandomAccessFile类可以写入和读取文件,其最大的特点就是可以在任意位置读取文件(random access的意思),是通过文件指针实现的。
原文出处:https://www.cnblogs.com/volcano-liu/p/10885485.html
JAVA IO - RandomAccessFile
RandomAccessFile
The RandomAccessFile class in the Java IO API allows you to move around a file and read from it or write to it as you please.
Here is a thing the JavaDoc forgets to mention: The read() method increments the file pointer to point to the next byte in the file after the byte just read! This means that you can continue to call read() without having to manually move the file pointer.
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
public static void main(String args[]){
try{
RandomAccessFile file = new RandomAccessFile(
"c:\\work\\hello\\helloworld.txt", "rw");
file.writeBytes("hello world!");
file.writeChar(''A'');
file.writeInt(1);
file.writeBoolean(true);
file.writeFloat(1.0f);
file.writeDouble(1.0);
file.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
JAVA IO - RandomAccessFile Seek学习
JAVA IO - RandomAccessFile Seek学习
import java.io.RandomAccessFile;
public class RandomAccessFileReadTest {
public static void main(String args[]) {
try {
RandomAccessFile file = new RandomAccessFile(
"c:\\work\\hello\\helloworld.txt", "r");
for (int i = 0; i < 1000000; i++) {
file.writeBytes(i + " hello world!\r\n");
}
tail(file, 2);
file.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void tail(RandomAccessFile rf, int n) {
StringBuffer sb = new StringBuffer(4096);
try {
long length = -1;
length = rf.length() - 1;
for (long i = length; i >= 0; i--) {
rf.seek(i);
int c = rf.read();
if(c == ''\r''){
n--;
if(n < 0){
System.out.println(sb.reverse().toString());
break;
}
}
sb.append( ( char )c);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Java IO 4 : RandomAccessFile
RandomAccessFile:
认识:java输入/输出流体系中功能最丰富的文件内容访问类 既可以读取文件内容,也可以向文件传输数据,并且支持“随机访问“的方式,程序可以跳转到任意地方来读写数据。
特点:与OutputStream/Writer不同,RandomAccessFile允许自由定位记录指针,可以不从开始的地方输出,因此RandomAccessFile可以向已经存在的文件后追加内容,如果程序需要向已经存在的文件后追加内容,应该使用RandomAccessFile
局限:只能读写文件,不能读写其他IO节点
RandomAccessFile 两个方法操作文件记录指针
long getFilePointer() 返回文件记录指针的当前位置
void seek(long pos) 将文件记录指针定位到pos位置
RandomAccessFile类为用户提供了两种构造方法:两种方法一个意思,一个是File指定,一个是String指定文件名
RandomAccessFile(File file, String mode)
RandomAccessFile(String name, String mode)
mode的四个值如下:
public class File03 {
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile("D://demo/a.txt", "r");
//初始位置为0
System.out.println("RandomAccessFile文件指针初始位置:" + raf.getFilePointer());
raf.seek(10);
byte[] bbuf = new byte[1024];
int hasRead = 0;
while((hasRead = raf.read(bbuf)) > 0) {
System.out.println(new String(bbuf , 0 , hasRead));
}
}
}
往文件最后追加内容:
//往文件里面追加内容
RandomAccessFile raf = new RandomAccessFile("D://demo/a.txt", "rw");
raf.seek(raf.length());
raf.write("这是追加的内容".getBytes());
往文件中间指定的位置添加内容:
RandomAccessFile不能向文件指定的内容插入内容,如果直接插,要把指定指针后的内容先读入一个临时的地方存起来, 插入需要的内容后, 再去将临时存储的内容读过来。
/**
* 使用RandomAccessFile 向文件指定的位置添加内容
* @throws IOException
*/
public static void insert(String fileName , long pos , String insertContent) throws IOException {
File temp = File.createTempFile("temp", null);
temp.deleteOnExit(); //jvm 退出时删除临时文件
FileOutputStream tempOut = new FileOutputStream(temp);
FileInputStream tempIn = new FileInputStream(temp);
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
System.out.println(raf.length());
raf.seek(pos);
//将插入点后的内容读取到临时文件
byte[] bbuf = new byte[100];
int hasRead = 0;
while((hasRead = raf.read(bbuf)) > 0) {
tempOut.write(bbuf, 0, hasRead);
}
//重新回到插入点 , 将需要添加的内容添加到到文件
raf.seek(pos);
raf.write(insertContent.getBytes());
//将临时文件中的内容添加到原文件当中
while((hasRead = tempIn.read(bbuf)) > 0) {
raf.write(bbuf, 0, hasRead);
}
}
public static void main(String[] args) throws IOException {
insert("D://demo/a.txt", 10 , "这是追加到文件中间的内容");
}
我们今天的关于RandomAccessFile java的分享已经告一段落,感谢您的关注,如果您想了解更多关于Java I/O系统学习系列一:File和RandomAccessFile、JAVA IO - RandomAccessFile、JAVA IO - RandomAccessFile Seek学习、Java IO 4 : RandomAccessFile的相关信息,请在本站查询。
本文标签: