java IO流:RandomAccessFile

一、提出问题

现在有一个这样的需求:向已存在1G数据的txt文本里末尾追加一行文字,内容如:“luncene是一款非常优秀的全文检索库”。可能大多数人都会感觉很简单,说实话,确实很简单
只需要将txt文本里原有的数据读取到字符串中,然后拼接刚才那句话,再写回到txt文件中就行了,
但是需求改了,向5G数据的txt文本里追加那,是不是傻眼了?内存只有4G,如果强制读取所有的数据并追加,就会报内存溢出的异常。

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

二、RandomAccessFile介绍

RandomAccessFile:是java中输入,输出流体系中功能最丰富的文件内容访问类,他提供很多方法来操作文件,包括读写支持,与普通的io流相比,他最强大的特别之处就是支持任意访问的方式,程序可以直接跳到任意地方来读写数据。
如果我们只希望访问文件的部分内容,而不是把文件从头读到尾,使用RandomAccessFile将会带来更简洁的代码以及更好的性能。

三、RandomAccessFile几个重要方法

1、getFilePointer():返回文件记录指针的当前位置
2、seek(long pos):将文件记录指针定位到pos的位置
3、writeUTF(String str):使用modified UTF-8编码以与机器无关的方式将一个字符串写入该文件
	public static void main(String[] args) throws IOException{
		RandomAccessFile raf = new RandomAccessFile("rwrite.dat", "rw");
		//设定临时文件的大小
		raf.setLength(258);
		//将文件指针定位到100
		raf.seek(100);
		//在偏移量100的地方写入追加内容
		raf.writeUTF("luncene是一款非常优秀的全文检索库");
		//指针自动的移动
		System.out.println("文件指针移动前的位置:"+raf.getFilePointer());
		//重新将文件指针定位到100的位置
		raf.seek(100);
		//获取刚才写入的字符串
		System.out.println(raf.readUTF());
    }  
4、打印结果
读取任意位置的数据,代码如下:
    public static void main(String[] args) throws IOException{
		randomRed("rwrite.dat",100);
    }  
    public static void randomRed(String path,int pointe){  
        try{  
            /** 
             * model各个参数详解 
             * r 代表以只读方式打开指定文件 
             * rw 以读写方式打开指定文件 
             * rws 读写方式打开,并对内容或元数据都同步写入底层存储设备 
             * rwd 读写方式打开,对文件内容的更新同步更新至底层存储设备 
             * **/  
            RandomAccessFile raf=new RandomAccessFile(path, "rw"); 
            //获取RandomAccessFile对象文件指针的位置,初始位置是0  
            System.out.println("RandomAccessFile文件指针的初始位置:"+raf.getFilePointer());  
            raf.seek(pointe);//移动文件指针位置  
            System.out.println(raf.readUTF());
        }catch(Exception e){  
            e.printStackTrace();  
        }  
    } 
运行效果:

追加数据,代码如下
	public static void main(String[] args) throws IOException{
		randomWrite("C:\\Users\\Administrator\\Desktop\\ttt\\abc.txt");
       }  
	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) throws IOException{
		String str="what are you doing now";
		insert("C:\\Users\\Administrator\\Desktop\\ttt\\abc.txt",10,str);
    }  
	/** 
     * 实现向指定位置 
     * 插入数据 
     * @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();  
        }  
    }

执行结果如下:

致此,RandomAccessFile类的几个功能,在代码中已经实现了,现在回到本文开始前的提的那个需求,用RandomAccessFile类就可以轻而易举的完成了,另外需要注意的是。向指定位置插入数据,使我们自己改造的功能,RandomAccessFile并不直接支持,需要新建一个缓冲区临时空间,存数据,然后在写,因为一旦数据上了级别,在任意位置插入数据,是很耗内存的,这个也就是为什么hadoop的HDFS文件系统,只支持append的方式,而没有提供修改的操作。
另外我们可以用RandomAccessFile这个类,来实现一个多线程断点下载的功能,一个是与被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,每次暂停的时候,都会保存上一次的指针,然后断点下载的时候,会继续从上一次的地方下载,从而实现的断点下载活着上传的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值