RandomAcessFile随机访问文件
String mode解析:
除了指定文件以外,还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,该参数有如下四个值:
1、 r: 以只读方式打开指定文件。如果试图对该RandomAccessFile指定的文件执行写入方法则会抛出IOException
2 、rw: 以读取、写入方式打开指定文件。如果该文件不存在,则尝试创建文件
3 、rws: 以读取、写入方式打开指定文件。相对于rw模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备,默认情形下(rw模式下),是使用buffer的,只有cache满的或者使用RandomAccessFile.close()关闭流的时候儿才真正的写到文件
4 、rwd: 与rws类似,只是仅对文件的内容同步更新到磁盘,而不修改文件的元数据
常用方法:
其它方法参考API文档
实现文件分割,将分割后的文件存储到新的文件夹中
package com.sxt.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
/**
* 随机读取和写入流 RandomAccessFiles
* @懒惰的小黑
*
*/
public class RandTest06 {
public static void main(String[] args) throws IOException {
test04();
}
//先创建文件夹dest,把分割后的每一块用文件夹存储起来
public static void split(File src,int i,int beginPos,int actualSize) throws IOException{
RandomAccessFile raf = new RandomAccessFile(src,"r");
OutputStream raf2 = new FileOutputStream("dest/");
//随机读取
raf.seek(beginPos);
//读取
byte[] flush = new byte[1024];
int len = -1;
while((len = raf.read(flush)) != -1) {
if(actualSize > len) { //获取本次读取的所有内容
raf2.write(flush,0,len);
actualSize -= len; //剩余还需要读取的长度
}else {
raf2.write(flush,0,actualSize);
break;
}
}
raf2.close();
raf.close();
}
/**
* 指定第i块的起始位置 和 实际程度
* @throws IOException
*/
public static void test04() throws IOException {
//源头
File src = new File("src/com/sxt/io/RandTest04.java");
//总长度
long len = src.length();
//每块大小
int blockSize = 1024;
//块数:多少块
int size = (int)Math.ceil(len*1.0/blockSize); //向上取整(四舍五入)
//起始位置和实际大小
int beginPos = 0;
int actualSize = (int)(blockSize > len?len:blockSize); //考虑开始时不够一块(1024),取len长度
for(int i=0; i<size;i++) {
beginPos = i*blockSize;
if(i == size -1) { //最后一块
actualSize = (int)len;
}else {
actualSize = blockSize; //足够一块(1024)的情况
len -= actualSize; //剩余量
}
System.out.println(i + "---->" + beginPos + "--->" + actualSize);
split(src,i,beginPos,actualSize);
}
}
}
注意:
使用FileOutputStream把分割后的文件写入文件夹中,如果按上述写法,则会出现以下问题:
定位到63行,在API文档中查看FileOutputStream发现:
分析发现:
如果按上述代码这样写(直接在dest的子文件下写入文件,但是没有指定文件的名称),那 test04() 中的for循环每一次调用该 split()写入的都是无名称的文件,我们知道同一个文件夹是不能出现同名的文件的,也不能写入空的文件中,显然会发生上述该错误。
所以我们要把每一个分割的文件放在同一个文件夹下应该这样纠正:
注意:dest后必须加“/”,因为dest为文件夹,在文件夹下存储分割的文件,所以要实现文件路径分隔符
文件分隔符有:“/” 、 “//”。具体使用哪种方式看需要。
代码实现结果:
实现文件分割,使用面向对象思想优化
package com.sxt.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
/**
* 使用面向对象思想封装--文件分割
* 注:批量修改变量名:alt + shift + r
* @懒惰的小黑
*
*/
public class SplitFile {
//源头
private File src;
//目的地(文件夹)
private String destDir;
//所有分割后的文件存储路径
private List<String> destPaths;
//每块大小
private int blockSize;
//块数
private int size;
public SplitFile(String srcPath,String destDir,int blockSize) {
this.src = new File(srcPath);
this.destDir = destDir;
this.blockSize = blockSize;
this.destPaths = new ArrayList<String>();
//初始化
init();
}
private void init() {
//总长度
long len = this.src.length();
//块数:多少块
this.size = (int)Math.ceil(len*1.0/blockSize); //向上取整(四舍五入)
//路径
for(int i=0;i<size;i++) {
this.destPaths.add(this.destDir + "/" + i + "-" + this.src.getName());
}
}
//分割:计算每一块的起始位置的大小
public void split() throws IOException {
//总长度
long len = this.src.length();
//块数:多少块
int size = (int)Math.ceil(len*1.0/blockSize); //向上取整(四舍五入)
//起始位置和实际大小
int beginPos = 0;
int actualSize = (int)(blockSize > len?len:blockSize); //考虑开始时不够一块(1024),取len长度
for(int i=0; i<size;i++) {
beginPos = i*blockSize;
if(i == size -1) { //最后一块
actualSize = (int)len;
}else {
actualSize = blockSize; //足够一块(1024)的情况
len -= actualSize; //剩余量
}
splitDetail(i,beginPos,actualSize);
}
}
public void splitDetail(int i,int beginPos,int actualSize) throws IOException{
RandomAccessFile raf = new RandomAccessFile(this.src,"r");
OutputStream raf2 = new FileOutputStream(this.destPaths.get(i)); //创建文件输出流以指定的名称写入文件。
System.out.println(this.destPaths.get(i));
//随机读取
raf.seek(beginPos);
//读取
byte[] flush = new byte[1024];
int len = -1;
while((len = raf.read(flush)) != -1) {
if(actualSize > len) { //获取本次读取的所有内容
raf2.write(flush,0,len);
actualSize -= len; //剩余还需要读取的长度
}else {
raf2.write(flush,0,actualSize);
break;
}
}
raf2.close();
raf.close();
}
public static void main(String[] args) throws IOException {
SplitFile sf = new SplitFile("copy.png","dest",1024*10);
sf.split();
}
}
代码实现结果:
上述为部分结果,其实把图片分隔成了35份。
参考学习【尚学堂java教程】