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

时间: 2024-09-30 19:38:57

Java IO的RandomAccessFile的使用(转)的相关文章

java io学习(二十五) RandomAccessFile

RandomAccessFile RandomAccessFile 是随机访问文件(包括读/写)的类.它支持对文件随机访问的读取和写入,即我们可以从指定的位置读取/写入文件数据. 需要注意的是,RandomAccessFile 虽然属于java.io包,但它不是InputStream或者OutputStream的子类:它也不同于FileInputStream和FileOutputStream. FileInputStream 只能对文件进行读操作,而FileOutputStream 只能对文件进

Java IO: RandomAccessFile

RandomAccessFile允许你来回读写文件,也可以替换文件中的某些部分.FileInputStream和FileOutputStream没有这样的功能. 创建一个RandomAccessFile 在使用RandomAccessFile之前,必须初始化它.这是例子: 1 RandomAccessFile file = new RandomAccessFile("c:\\data\\file.txt", "rw"); 请注意构造函数的第二个参数:"rw

java io系列26之 RandomAccessFile

本文主要介绍 RandomAccessFile. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_26.html 更多内容请参考:java io系列01之 "目录"   RandomAccessFile RandomAccessFile 是随机访问文件(包括读/写)的类.它支持对文件随机访问的读取和写入,即我们可以从指定的位置读取/写入文件数据.需 要注意的是,RandomAccessFile 虽然属于java.io包,但它不是Inpu

使用HttpURLConnection下载文件时出现 java.io.FileNotFoundException彻底解决办法

使用HttpURLConnection下载文件时经常会出现 java.io.FileNotFoundException文件找不到异常,下面介绍下解决办法 首先设置tomcat对get数据的编码:conf/server.xml <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncodin

Java IO: 流

原文链接 作者: Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) Java IO流是既可以从中读取,也可以写入到其中的数据流.正如这个系列教程之前提到过的,流通常会与数据源.数据流向目的地相关联,比如文件.网络等等. 流和数组不一样,不能通过索引读写数据.在流中,你也不能像数组那样前后移动读取数据,除非使用RandomAccessFile 处理文件.流仅仅只是一个连续的数据流. 某些类似PushbackInputStream 流的实现允许你将数据重新推回

Java IO教程

Java IO 是一套Java用来读写数据(输入和输出)的API.大部分程序都要处理一些输入,并由输入产生一些输出.Java为此提供了java.io包. 如果你浏览下java.io包,会对其中各样的类选择感到迷惑.这些类的作用都是什么?对于某个任务该选择哪个类?怎样创建你自己的类做插件?这个手册的目的就是给你介绍这些类是如何组织的,以及怎样使用他们,因此你就不会疑惑需要时怎样选取合适的类,或者是否有一个满足你需求的类已经存在了. Java.io 包的范围 java.io 包并没有涵盖所有输入输出

Java IO流学习总结

 Io流的内容比较多 ,大致可以分为字节流和字符流,其中为了提高效率又用到了缓冲区. Java流操作有关的类或接口: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作.  IO流的分类 根据处理数据类型的不同分为:字符流和字节流 根据数据流向不同分为:输入流和输出流 字符流和字节流 字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象.本

Java IO

一.java io 概述 1.1 相关概念 Java IO Java IO即Java 输入输出系统.不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这要考虑的因素特别多,比如我们要考虑和哪种媒介进行IO(文件.控制台.网络),我们还要考虑具体和它们的通信方式(顺序.随机.二进制.按字符.按字.按行等等).Java类库的设计者通过设计大量的类来攻克这些难题,这些类就位于java.io包中. 在JDK1.4之后,为了提高Java IO的效率,Java

Java.nio vs Java.io

Java.nio vs Java.io By Nino Guarnacci on Jun 18, 2009 --- posted by Davide Pisano This document is not a Java.io or a Java.nio manual, or a technical document about Java.io and Java.nio use. It only attempts to compare these two packages, highlightin