当前位置: 首页 > news >正文

Java IO的RandomAccessFile的使用(转)

 


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

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

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

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

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

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

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

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

 

public static void main(String[] args) {  
    String path="D:\\3\\test.txt";         
     int seekPointer=20;  
     randomRed(path,seekPointer);//读取的方法   
    //randomWrite(path);//追加写的方法  
    //insert(path, 33, "\nlucene是一个优秀的全文检索库");  
}  
RandomAccessFile文件指针的初始位置:0  
is a teacher  
hadoop is perfect 

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

/** 
 * 追加方式 
 * 写的方法 
 * @param path 文件路径 
 * ***/  
public static void randomWrite(String path){  
    try{  
        /**以读写的方式建立一个RandomAccessFile对象**/  
        RandomAccessFile raf=new RandomAccessFile(path, "rw");  
          
        //将记录指针移动到文件最后  
        raf.seek(raf.length());  
        raf.write("我是追加的 \r\n".getBytes());  
          
    }catch(Exception e){  
        e.printStackTrace();  
    }  
      
}  
public static void main(String[] args) {  
    String path="D:\\3\\test.txt";         
     //int seekPointer=20;  
    // randomRed(path,seekPointer);//读取的方法   
     randomWrite(path);//追加写的方法  
    //insert(path, 33, "\nlucene是一个优秀的全文检索库");  
}  

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

/** 
     * 实现向指定位置 
     * 插入数据 
     * @param fileName 文件名 
     * @param points 指针位置 
     * @param insertContent 插入内容 
     * **/  
    public static void insert(String fileName,long points,String insertContent){  
        try{  
        File tmp=File.createTempFile("tmp", null);  
        tmp.deleteOnExit();//在JVM退出时删除  
          
        RandomAccessFile raf=new RandomAccessFile(fileName, "rw");  
        //创建一个临时文件夹来保存插入点后的数据  
        FileOutputStream tmpOut=new FileOutputStream(tmp);  
        FileInputStream tmpIn=new FileInputStream(tmp);  
        raf.seek(points);  
        /**将插入点后的内容读入临时文件夹**/  
          
        byte [] buff=new byte[1024];  
        //用于保存临时读取的字节数  
        int hasRead=0;  
        //循环读取插入点后的内容  
        while((hasRead=raf.read(buff))>0){  
            // 将读取的数据写入临时文件中  
            tmpOut.write(buff, 0, hasRead);  
        }  
          
        //插入需要指定添加的数据  
        raf.seek(points);//返回原来的插入处  
        //追加需要追加的内容  
        raf.write(insertContent.getBytes());  
        //最后追加临时文件中的内容  
        while((hasRead=tmpIn.read(buff))>0){  
            raf.write(buff,0,hasRead);  
        }  
        }catch(Exception e){  
            e.printStackTrace();  
        }  
    }  
public static void main(String[] args) {  
        String path="D:\\3\\test.txt";         
         //int seekPointer=20;  
        // randomRed(path,seekPointer);//读取的方法   
        // randomWrite(path);//追加写的方法  
         insert(path, 33, "\nlucene是一个优秀的全文检索库");  
    }  

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


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

 

http://blog.csdn.net/czplplp_900725/article/details/37809579

相关文章:

  • 执行Asp.net应用程序在Linux上的3种托管方式
  • CSS学习笔记——定位position属性的学习
  • 【转】搭建高可用mongodb集群(一)——配置mongodb
  • 从实体和关系角度看 PowerDesigner 设计数据库模型
  • 基础知识__WebService
  • Lepus经历收获杂谈(二)——QT
  • Python Function Note
  • 腾讯下一个重点:硬件;硬件自身的未来也正进入多元化发展
  • REST架构的思考
  • python的统一编码规范
  • c# 反射
  • 使用AutoCompleteTextView和AsyncTask 检索城市
  • python之路(二)函数
  • Linux下设置定期执行脚本
  • Linux下安装配置MongoDB数据库
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • Angular数据绑定机制
  • css选择器
  •  D - 粉碎叛乱F - 其他起义
  • HTTP中的ETag在移动客户端的应用
  • Java精华积累:初学者都应该搞懂的问题
  • Java小白进阶笔记(3)-初级面向对象
  • java中的hashCode
  • MQ框架的比较
  • 翻译--Thinking in React
  • 前端设计模式
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 学习笔记TF060:图像语音结合,看图说话
  • 延迟脚本的方式
  • 再次简单明了总结flex布局,一看就懂...
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • (11)MATLAB PCA+SVM 人脸识别
  • (26)4.7 字符函数和字符串函数
  • (4)事件处理——(7)简单事件(Simple events)
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (Matlab)使用竞争神经网络实现数据聚类
  • (八十八)VFL语言初步 - 实现布局
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (十二)python网络爬虫(理论+实战)——实战:使用BeautfulSoup解析baidu热搜新闻数据
  • (十一)图像的罗伯特梯度锐化
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • ./configure、make、make install 命令
  • .NET 4.0中的泛型协变和反变
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .NET 使用 XPath 来读写 XML 文件
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .NET性能优化(文摘)
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!