RandomAccessFile类的使用
该类默认的写操作是覆盖操作。例如原来的文件内容是“abcde”,我们将文件指针移向2位置(seek(2)
,即覆盖的位置在b字符之后),我们写入3个字符:raf.write("xxx".getBytes());
文件就变成了"abxxe"。如果我们要将xxx插入到b和c字符之间,默认的RandomAccessFile是无法实现的。
/**
* 向文本文件的特定位置插入字符串
*/
public static void insertStringToTxtFile(File f,String content,int pos) throws IOException{
RandomAccessFile raf = new RandomAccessFile(f, "rw");
raf.seek(pos);
// 暂存插入点后的字符串
byte[] buf = new byte[1024];
int len = 0;
StringBuilder sb = new StringBuilder();
while ((len = raf.read(buf)) != -1) {
sb.append(new String(buf, 0, len));
}
// 此时FP已经移动到了EOF,需要重新回到插入点写入字符串
raf.seek(pos);
raf.write(content.getBytes());
raf.write(sb.toString().getBytes());
raf.close();
}
以上的代码中最关键的代码是将文件指针之后的内容暂存起来,使用到了StringBuilder容器,读取的时候采用的是读取到字节数组(因为一次读取一行可能会产生换行的问题)。
该类用于随机读取文件,利用该类我们可以实现多线程写文件的操作。具体思路是将目标文件分块,每个线程负责写入一个数据块。例如:
public class WriteFile implements Runnable{
private int block; // 数据块标号
private File descFile; // 目标文件
private static final int SIZE_PER_BLOCK = 20; // 每个数据块大小
public WriteFile(int block, File descFile) {
super();
this.block = block;
this.descFile = descFile;
}
@Override
public void run() {
try {
RandomAccessFile raf = new RandomAccessFile(descFile, "rw");
raf.seek((block - 1) * SIZE_PER_BLOCK);
raf.writeBytes("This is block " + block + "\n");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class MultipleThreadWrite {
static File file = new File("data.txt");
public static void main(String[] args) {
for (int i = 1; i < 6; i++) {
new Thread(new WriteFile(i, file)).start();
}
}
}
以上开启了5个线程向data.txt文件中写入数据,每个线程负责写入一个数据块的数据,我们要写入的字符串的长度是16个字节,没有完全占用1个数据块,但是第二个线程写入数据的时候将文件指针移动到了20,从20开始写入,前面的4个字节是没有数据的。因此,全部线程执行完毕之后,文件的大小是 4 * 20 + 16 = 96bytes。
apache commons IO库
maven依赖如下:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
常用方法如下:
@Test
public void testFileUtils() throws Exception{
File file = new File("test.txt");
// 将文本文件读取为字符串
String str = FileUtils.readFileToString(file, "utf-8");
System.out.println("文本文件内容:" + str);
// 文件大小
System.out.println(FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(new File("F:/BaiduYunDownload/OS X Mavericks 10.9 (GM).iso"))));
// 向文件中写入字符串
FileUtils.writeStringToFile(new File("data.txt"), "你好hellodfd#$", "utf-8");
// 遍历目录及其子目录下的所有文件
Iterator<File> iterator = FileUtils.iterateFilesAndDirs(new File("E:/tmp"), FileFileFilter.FILE, DirectoryFileFilter.DIRECTORY);
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 文件拷贝
File destFile = new File("test_copy.txt");
FileUtils.copyFile(file, destFile);
// 从URL(必须是file协议,即本地计算机)中得到文件资源
file = FileUtils.toFile(new URL("file:///E:/tmp/%E7%84%A6%E7%82%B9%E5%9B%BE.html"));
System.out.println("本地文件:" + file);
// 将文件拷贝到指定目录(目录不存在,创建之)
FileUtils.copyFileToDirectory(file, new File("E:/tmp/demo"));
// 拷贝一个目录(及其文件和子目录)到另一个目录
FileUtils.copyDirectoryToDirectory(new File("E:/tmp"), new File("E:/demo"));
// 下载远程资源到本地
FileUtils.copyURLToFile(new URL("http://www.knowsky.com/384261.html"), new File("tmp.html"), 3000, 3000);
// 删除目录中的内容
FileUtils.deleteDirectory(new File("E:/demo"));
// 移动文件(rename)
FileUtils.moveFile(new File("test.txt"), new File("ok.txt"));
}