现有如下的一个需求,向已存在1G数据的txt文本里末尾追加一行文字,内容如下“Lucene是一款非常优秀的全文检索库”。可能大多数朋友会觉得这个需求很easy,说实话,确实easy,然后XXX君开始实现了,直接使用Java中的流读取了txt文本里原来所有的数据转成字符串后,然后拼接了“Lucene是一款非常优秀的全文检索库”,又写回文本里了,至此,大功告成。后来需求改了,向5G数据的txt文本里追加了,结果XXX君傻了,他内存只有4G,如果强制读取所有的数据并追加,会报内存溢出的异常。

其实上面的需求很简单,如果我们使用JAVA IO体系中的RandomAccessFile类来完成的话,可以实现零内存追加。其实这就是支持任意位置读写类的强大之处。

在这之前,还是先啰嗦的介绍下RandomAccessFile这个类,RandomAccessFile是Java中输入,输出流体系中功能最丰富的文件内容访问类,它提供很多方法来操作文件,包括读写支持,与普通的IO流相比,它最大的特别之处就是支持任意访问的方式,程序可以直接跳到任意地方来读写数据。

如果我们只希望访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将会带来更简洁的代码以及更好的性能。

下面来看下RandomAccessFile类中比较重要的2个方法,其他的和普通IO类似,在这里,就不详细说明了。

方法名 作用
getFilePointer() 返回文件记录指针的当前位置
seek(long pos) 将文件记录指针定位到pos的位置

下面散仙给出示例,分析下怎么使用RandomAccessFile
首先,我们先看下要操作的文本文件的内容截图。


功能one,读取任意位置的数据,代码如下

  1. /**
  2. * 读的方法
  3. * @param path 文件路径
  4. * @param pointe 指针位置
  5. * **/
  6. public static void randomRed(String path,int pointe){
  7. try{
  8. //RandomAccessFile raf=new RandomAccessFile(new File("D:\\3\\test.txt"), "r");
  9. /**
  10. * model各个参数详解
  11. * r 代表以只读方式打开指定文件
  12. * rw 以读写方式打开指定文件
  13. * rws 读写方式打开,并对内容或元数据都同步写入底层存储设备
  14. * rwd 读写方式打开,对文件内容的更新同步更新至底层存储设备
  15. *
  16. * **/
  17. RandomAccessFile raf=new RandomAccessFile(path, "r");
  18. //获取RandomAccessFile对象文件指针的位置,初始位置是0
  19. System.out.println("RandomAccessFile文件指针的初始位置:"+raf.getFilePointer());
  20. raf.seek(pointe);//移动文件指针位置
  21. byte[]  buff=new byte[1024];
  22. //用于保存实际读取的字节数
  23. int hasRead=0;
  24. //循环读取
  25. while((hasRead=raf.read(buff))>0){
  26. //打印读取的内容,并将字节转为字符串输入
  27. System.out.println(new String(buff,0,hasRead));
  28. }
  29. }catch(Exception e){
  30. e.printStackTrace();
  31. }
  32. }

测试代码

  1. public static void main(String[] args) {
  2. String path="D:\\3\\test.txt";
  3. int seekPointer=20;
  4. randomRed(path,seekPointer);//读取的方法
  5. //randomWrite(path);//追加写的方法
  6. //insert(path, 33, "\nlucene是一个优秀的全文检索库");
  7. }

运行效果:

  1. RandomAccessFile文件指针的初始位置:0
  2. is a teacher
  3. hadoop is perfect

功能two,追加数据,代码如下

  1. /**
  2. * 追加方式
  3. * 写的方法
  4. * @param path 文件路径
  5. * ***/
  6. public static void randomWrite(String path){
  7. try{
  8. /**以读写的方式建立一个RandomAccessFile对象**/
  9. RandomAccessFile raf=new RandomAccessFile(path, "rw");
  10. //将记录指针移动到文件最后
  11. raf.seek(raf.length());
  12. raf.write("我是追加的 \r\n".getBytes());
  13. }catch(Exception e){
  14. e.printStackTrace();
  15. }
  16. }

测试代码

  1. public static void main(String[] args) {
  2. String path="D:\\3\\test.txt";
  3. //int seekPointer=20;
  4. // randomRed(path,seekPointer);//读取的方法
  5. randomWrite(path);//追加写的方法
  6. //insert(path, 33, "\nlucene是一个优秀的全文检索库");
  7. }

运行效果:


功能three,任意位置插入数据,代码如下

  1. /**
  2. * 实现向指定位置
  3. * 插入数据
  4. * @param fileName 文件名
  5. * @param points 指针位置
  6. * @param insertContent 插入内容
  7. * **/
  8. public static void insert(String fileName,long points,String insertContent){
  9. try{
  10. File tmp=File.createTempFile("tmp", null);
  11. tmp.deleteOnExit();//在JVM退出时删除
  12. RandomAccessFile raf=new RandomAccessFile(fileName, "rw");
  13. //创建一个临时文件夹来保存插入点后的数据
  14. FileOutputStream tmpOut=new FileOutputStream(tmp);
  15. FileInputStream tmpIn=new FileInputStream(tmp);
  16. raf.seek(points);
  17. /**将插入点后的内容读入临时文件夹**/
  18. byte [] buff=new byte[1024];
  19. //用于保存临时读取的字节数
  20. int hasRead=0;
  21. //循环读取插入点后的内容
  22. while((hasRead=raf.read(buff))>0){
  23. // 将读取的数据写入临时文件中
  24. tmpOut.write(buff, 0, hasRead);
  25. }
  26. //插入需要指定添加的数据
  27. raf.seek(points);//返回原来的插入处
  28. //追加需要追加的内容
  29. raf.write(insertContent.getBytes());
  30. //最后追加临时文件中的内容
  31. while((hasRead=tmpIn.read(buff))>0){
  32. raf.write(buff,0,hasRead);
  33. }
  34. }catch(Exception e){
  35. e.printStackTrace();
  36. }
  37. }

测试代码

  1. public static void main(String[] args) {
  2. String path="D:\\3\\test.txt";
  3. //int seekPointer=20;
  4. // randomRed(path,seekPointer);//读取的方法
  5. // randomWrite(path);//追加写的方法
  6. insert(path, 33, "\nlucene是一个优秀的全文检索库");
  7. }

运行效果:

至此,RandomAccessFile类的几个功能,散仙在代码中已给出实现了,现在回到本文开始前的提的那个需求,用RandomAccessFile类就可以轻而易举的完成了,另外需要注意的是,向指定位置插入数据,是散仙自己改造的功能,RandomAccessFile并不直接支持,需要新建一个缓冲区临时空间,存数据,然后在写,因为一旦数据量上了级别,在任意位置插入数据,是很耗内存的,这个也就是为什么hadoop的HDFS文件系统,只支持append的方式,而没有提供修改的操作。

另外我们可以用RandomAccessFile这个类,来实现一个多线程断点下载的功能,用过下载工具的朋友们都知道,下载前都会建立两个临时文件,一个是与被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,每次暂停的时候,都会保存上一次的指针,然后断点下载的时候,会继续从上一次的地方下载,从而实现断点下载或上传的功能,有兴趣的朋友们可以自己实现下。

Java 实现文件随机读写-RandomAccessFile的更多相关文章

  1. 从零开始学C++之IO流类库(三):文件的读写、二进制文件的读写、文件随机读写

    一.文件的读写 如前面所提,流的读写主要有<<, >>, get, put, read, write 等操作,ofstream 继承自ostream, ifstream 继承自 ...

  2. 营销MM让我讲MySQL日志顺序读写及数据文件随机读写原理

    摘要:你知道吗,MySQL在实际工作时候的两种数据读写机制? 本文分享自华为云社区<MySQL日志顺序读写及数据文件随机读写原理>,作者:JavaEdge . MySQL在实际工作时候的两 ...

  3. 文件随机读写专用类——RandomAccessFile

     RandomAccessFile类可以随机读取文件,但是在测试中并不好用;File类可以测试文件存不存在,不存在可以创建文件;FileWriter类可以对文件进行重写或者追加内容;FileReade ...

  4. Java实现文件的读写,复制

    import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStr ...

  5. java字符文件的读写

    1.java文件读写,首先我们需要导入相应的包:java.io.*; 2.代码如下: package Demo1; import java.io.*; public class FileWirteTe ...

  6. Java实现文件的读写

    需求:实现基本的读写 package com.sbx.io; import java.io.File; import java.io.FileReader; import java.io.FileWr ...

  7. 第9.9节 Python文件随机读写定位操作方法seek

    类似于C语言,Python也提供了文件位置定位的操作方法seek. 一. 语法 seek(offset, whence=SEEK_SET) 语法释义: 1)offset :将文件当前操作位置移动偏移量 ...

  8. java 实现文件读写操作

    import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; /* JAVA IO 读写操作 20 ...

  9. java中文件的I/O操作

    java中文件的读写操作 (一) (1)java中文件的字节转成字符读操作 FileInputStream fStream = new FileInputStream("test.txt&q ...

随机推荐

  1. 结构体sockadrr、sockaddr_in、in_addr的定义

    /* Internet address.  */typedef uint32_t in_addr_t;struct in_addr  {    in_addr_t s_addr;  };  typed ...

  2. 飞思卡尔烧写工具mfgtools的使用

    MFGTool是飞思卡尔提供的烧写工具,使用起来非常方便.但是,在使用MFGTool有几点是需要注意的,否则就会在烧写过程中遇到一些问题: 1.在使用MFGTool前,文件cfg.ini 和 UICf ...

  3. windows下GVIM的配置(vimrc)

    学习python时想要在gvim中配置python的编译环境,网上找到一个比较好用的vimrc配置,保存下来以备下次有需要. set encoding=utf-8 set termencoding=u ...

  4. SVN版本库的备份、还原、移植(初级篇、中级篇和高级篇)

    版本库数据的移植:svnadmin dump.svnadmin load 导出: $svnlook youngest myrepos //查看到目前为止最新的版本号 $svnadmin dump my ...

  5. Java异常处理中,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

    Java异常处理中,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 解答:会执行,在return前 ...

  6. Cross compile perl

    Alex Suykov had do some work for this purpose, and my compile script is based on her patch. Steps St ...

  7. android Dialog 底部弹出

    . if (dialShareDialog == null) { dialShareDialog = new Dialog(context, R.style.dialog); dialShareDia ...

  8. cocos2dx lua 3.10 使用cjson

    本篇介绍如何在lua中使用cjson对数据进行json的encode与decode,首先简单介绍下cjson: Lua CJSON 是 Lua 语言提供高性能的 JSON 解析器和编码器,其性能比纯 ...

  9. 鱼眼镜头的distortion校正【matlab】

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 作者:WWC %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% ...

  10. [Algorithms] Counting Sort

    Counting sort is a linear time sorting algorithm. It is used when all the numbers fall in a fixed ra ...