本文将介绍JavaIO学习--RandomAccessFile的详细情况,特别是关于javarandomaccess的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时
本文将介绍Java IO学习--RandomAccessFile的详细情况,特别是关于java random access的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于FileChannel与RandomAccessFile io api、IO流之randomAccessFile、Java I/O系统学习系列一:File和RandomAccessFile、JAVA IO - RandomAccessFile的知识。
本文目录一览:- Java IO学习--RandomAccessFile(java random access)
- FileChannel与RandomAccessFile io api
- IO流之randomAccessFile
- Java I/O系统学习系列一:File和RandomAccessFile
- JAVA IO - RandomAccessFile
Java IO学习--RandomAccessFile(java random access)
1、什么是 随机访问文件流 RandomAccessFile
这个类在很多资料上翻译成中文都是:随机访问文件,在中文里,随机是具有不确定的含义,指一会访问这里,一会访问那里的意思。如果以这种语义来解释的话,就会感到很困惑。其实,Random在英文中不仅仅有随机,还有任意的意思。如果中文名为任意访问文件是不是就会更好的理解。任意表示我们可以指定文件中任何一个位置去操作一个文件。
RandomAccessFile适用于大小已知的文件,能够随机的读取或者写入文件。可以通过使用seek()将记录从一处转移到另外一处,然后读取或者修改记录。文件中记录的大小不一定相同,只要我们能确定记录的大小和它们在文件的位置即可。
2、RandowAccessFile存在的价值
1、是JAVA I/O流体系中功能最丰富的文件内容访问类,它提供了众多方法来访问文件内容。
2、由于可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,RandomAccessFile将是更好的选择。
3、可以用来访问保存数据记录的文件,文件的记录的大小不必相同,但是其大小和位置必须是可知的。
3、RandomAccessFile的使用
1 public class RandomFileDemo {
2
3 public static void main(String[] args) {
4
5 try {
6 RandomAccessFile raf = new RandomAccessFile(new File("E:\\a.txt"), "rw");
7 long offset = raf.getFilePointer();//文件指针
8 long len= raf.length();//当前文件的字节大小
9 System.out.println("offset:"+offset+" len:"+len);
10 //raf.seek(len);//移动到文件末尾,可进行追加文件内容
11 System.out.println("offset:"+raf.getFilePointer()+" len:"+raf.length());
12 raf.write(65);//1字节
13 raf.writeChar(97);//2字节
14 raf.writeChar(''\n'');//2字节
15 raf.writeBytes("test");//4字节
16 System.out.println("offset:"+raf.getFilePointer()+" len:"+raf.length());
17
18
19 raf.seek(0);//移动文件指针到开始位置
20 int c = raf.read();
21 System.out.println(c+" "+(byte)c+" "+(char)c);//从指定位置开始读取一个字节
22
23 System.out.println(raf.readChar());//从文件指针(类似一个游标)位置开始读取一个字符(2个字节)
24 //再次回到文件的开始位置,读取一行
25 raf.seek(0);
26 System.out.print(Arrays.toString(raf.readLine().getBytes())+" ");
27 System.out.println("offset:"+raf.getFilePointer()+" len:"+raf.length());
28 raf.close();
29
30
31
32
33 } catch (Exception e) {
34 e.printStackTrace();
35 }
36
37 }
38
39 }
结果输出(a.txt是空文件):
offset:0 len:0
offset:0 len:0
offset:9 len:9
65 65 A
a
[65, 0, 97, 0] offset:5 len:9
4、进程控制和流
在java程序中执行其他操作系统的程序,并且控制这些程序的输入和输出。主要要是借助流来读取程序的输出。如下:
1 public class ProcessDemo {
2
3 public static void main(String[] args) {
4
5 try {
6 Process process = Runtime.getRuntime().exec(new String[]{"cmd.exe","/C","dir"});
7
8 BufferedReader br =new BufferedReader(new InputStreamReader(process.getInputStream(),"GBK"));
9
10 BufferedReader br2 =new BufferedReader(new InputStreamReader(process.getErrorStream()));
11 String line=null;
12 String line2=null;
13 while((line=br.readLine())!=null){
14 System.out.println(line);
15 }
16 while((line2=br2.readLine())!=null){
17 System.out.println(line2);
18 }
19
20 br.close();
21 br2.close();
22 } catch (IOException e) {
23 e.printStackTrace();
24 }
25
26
27 }
28
29 }
输出结果:
驱动器 F 中的卷没有标签。
卷的序列号是 3A48-2555
F:\NewStudyWorkSpace\coder_java 的目录
2018/03/19 19:31 <DIR> .
2018/03/19 19:31 <DIR> ..
2018/03/19 19:31 1,433 .classpath
2018/03/19 19:31 562 .project
2018/03/19 19:31 <DIR> .settings
2018/04/05 18:05 702 pom.xml
2018/03/19 19:31 <DIR> src
2018/03/19 19:31 <DIR> target
3 个文件 2,697 字节
5 个目录 341,102,870,528 可用字节
FileChannel与RandomAccessFile io api

IO流之randomAccessFile
randomAccessFile raf =new randomAccessFile(file,"rw");
关于写入的操作:
raf.write();//这里只能写一个字节(后八位) 同时指针也会跟着后移
raf.writeInt()//能直接写入一个整形
String s="中";
byte[]gbk=s.getBytes("gbk");//括号里面写的是编码的方式
raf.write(gbk)//这里可以直接写入一串字符
关于读取的操作:
//首先进行的是把指针移到头部、
raf.seek(0);
//然后创建的是存储的数组
byte[]b=new byte[(int)(raf.length())];
//单独打read得到的是一个字节
raf.read();
//也可以同时读取一个数组
raf.read(b);
//要在控制台上打印出结果,可以把数组转化成字符串
System.out.println(Arrays.toString(b));
//或者
String s=new String(b);
System.out.println(s);
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和java random access的分享就到这里,谢谢您的阅读,如果想了解更多关于FileChannel与RandomAccessFile io api、IO流之randomAccessFile、Java I/O系统学习系列一:File和RandomAccessFile、JAVA IO - RandomAccessFile的相关信息,可以在本站进行搜索。
本文标签: