文件
读文件
如果你需要在不同端之间读取文件,你可以根据该文件是二进制文件还是文本文件来选择使用 FileInputStream
或者 FileReader
。
这两个类允许你从文件开始到文件末尾一次读取一个字节或者字符,或者将读取到的字节写入到字节数组或者字符数组。
你不必一次性读取整个文件,相反你可以按顺序地读取文件中的字节和字符。
写文件
如果你需要在不同端之间进行文件的写入,你可以根据你要写入的数据是二进制型数据还是字符型数据选用 FileOutputStream
或者 FileWriter
。
你可以一次写入一个字节或者字符到文件中,也可以直接写入一个字节数组或者字符数据。数据按照写入的顺序存储在文件当中。
随机存取文件
你可以通过 RandomAccessFile
对文件进行随机存取。
随机存取并不意味着你可以在真正随机的位置进行读写操作,它只是意味着你可以跳过文件中某些部分进行操作,并且支持同时读写,不要求特定的存取顺序。
这使得 RandomAccessFile
可以覆盖一个文件的某些部分、或者追加内容到它的末尾、或者删除它的某些内容,当然它也可以从文件的任何位置开始读取文件。
文件信息
通过 File 类可以获取文件和目录的信息。
File
功能
Java IO API中的FIle类可以让你访问底层文件系统,通过File类,你可以做到以下几点:
-
检测文件是否存在
-
读取文件长度
-
重命名或移动文件
-
删除文件
-
检测某个路径是文件还是目录
-
读取目录中的文件列表
RandomAccessFile
由于RandomAccessFile 可以自由访问文件的任意位置,所以如果需要访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将是更好的选择。
- 局限
RandomAccessFile 的方法虽然多,但它有一个最大的局限,就是只能读写文件,不能读写其他IO节点。
RandomAccessFile 的构造函数
RandomAccessFile 类有两个构造函数,其实这两个构造函数基本相同,只不过是指定文件的形式不同——一个需要使用String参数来指定文件名,一个使用File参数来指定文件本身。
除此之外,创建RandomAccessFile对象时还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,一共有4种模式。
"r" : 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
"rw": 打开以便读取和写入。
"rws": 打开以便读取和写入。相对于 "rw","rws" 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。
"rwd" : 打开以便读取和写入,相对于 "rw","rwd" 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。
核心方法
RandomAccessFile既可以读文件,也可以写文件,所以类似于InputStream的read()方法,以及类似于OutputStream的write()方法,RandomAccessFile都具备。
除此之外,RandomAccessFile具备两个特有的方法,来支持其随机访问的特性。
RandomAccessFile对象包含了一个记录指针,用以标识当前读写处的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件指针记录位于文件头(也就是0处),当读/写了n个字节后,文件记录指针将会后移n个字节。
除此之外,RandomAccessFile还可以自由移动该记录指针。
下面就是RandomAccessFile具有的两个特殊方法,来操作记录指针,实现随机访问:
long getFilePointer():返回文件记录指针的当前位置
void seek(long pos):将文件指针定位到pos位置
实例
利用RandomAccessFile实现文件的多线程下载,即多线程下载一个文件时,将文件分成几块,每块用不同的线程进行下载。
下面是一个利用多线程在写文件时的例子,其中预先分配文件所需要的空间,然后在所分配的空间中进行分块,然后写入:
- RandomAccessFileTest.java
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileTest {
public static void main(String[] args) throws Exception {
// 预分配文件所占的磁盘空间,磁盘中会创建一个指定大小的文件
RandomAccessFile raf = new RandomAccessFile("abc.txt", "rw");
// 预分配 8K 的文件空间
raf.setLength(1024*8);
raf.close();
// 所要写入的文件内容
String s1 = "第一个字符串";
String s2 = "第二个字符串";
String s3 = "第三个字符串";
String s4 = "第四个字符串";
String s5 = "第五个字符串";
// 利用多线程同时写入一个文件
// 从文件的1024字节之后开始写入数据
new FileWriteThread(1024*1,s1.getBytes()).start();
// 从文件的2048字节之后开始写入数据
new FileWriteThread(1024*2,s2.getBytes()).start();
// 从文件的3072字节之后开始写入数据
new FileWriteThread(1024*3,s3.getBytes()).start();
// 从文件的4096字节之后开始写入数据
new FileWriteThread(1024*4,s4.getBytes()).start();
// 从文件的5120字节之后开始写入数据
new FileWriteThread(1024*5,s5.getBytes()).start();
}
/**
* 利用线程在文件的指定位置写入指定数据
*/
private static class FileWriteThread extends Thread{
private int skip;
private byte[] content;
FileWriteThread(int skip, byte[] content){
this.skip = skip;
this.content = content;
}
@Override
public void run(){
try (RandomAccessFile raf = new RandomAccessFile("abc.txt", "rw")) {
raf.seek(skip);
raf.write(content);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
参考资料
File
https://docs.oracle.com/javase/7/docs/api/java/io/File.html
https://blog.csdn.net/u013309870/article/details/52098414
http://ifeve.com/java-io-%E6%96%87%E4%BB%B6/
http://ifeve.com/java-io-file/
RandomAccessFile
https://docs.oracle.com/javase/7/docs/api/java/io/RandomAccessFile.html
https://www.jianshu.com/p/c8aa567f2101
https://blog.csdn.net/akon_vm/article/details/7429245