记得读高中的时候特别喜欢看电子书,但是那时候还是2010年的时候,经济条件不好,买不起智能手机,只能使用1些山寨机,硬件设施较差,里面的txt文本浏览器只能读取大小不超过5M的电子书,但是网上的电子书基本上都超过了5M,为了能看这些书,只能在网上下载1个txt文件分割器,分割成小文件后,再下载得手机上,那时候还不懂编程,就觉得这个分割器是1个很奇异的东西。但是如今自己学了编程后发现1个文件分割器是10分容易实现的。
现在笔者就以Java中的IO流知识,实现1个文件分割器,固然知识实现了核心的代码,没有实现界面,毕竟Java中的Swing包做出来的界面不是那末好看,笔者对这1块知识也没有深入学习。
要想将1个文件分割,首先要知道将文件分成大小为多少的块(或分成几块,笔者在这里只以每块的大小举例),例如我们要将1个大小为324个字节大小的文件分割成每块大小为100个字节的小文件,那末就需要将文件分成4块,且最后1块的实际大小为24。固然也会遇到这类情况,文件为324个字节,而要将文件分割成大小为400个字节的块,那末这个块的实际大小为324。

将文件分割好块后,接下来我们就需要将每个小块写出到磁盘中。首先我们得用RandomAccessFile来读取文件到内存当中,利用seek方法设置从哪儿开始读取,然后用FileOutputStream来将读取到的内容写出到磁盘中。但是在写出的时候,会遇到这样1个问题:每次读取的长度len可能大于每块的实际大小(例如该块的实际大小为100,而len却为120,这时候候就不能将读取到的内容全部写出),因此需要判断,具体可以看下面的代码中的注释。

具体的代码以下:
package com.tiantang.split;
import java.io.BufferedOutputStream;
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;
public class SplitFile {
//被分割文件的路径
private String srcPath;
//被分割的文件对象
private File src;
//分割的块数
private int size;
//每块的大小
private long blockSize;
//每块的实际大小
private long actualBlockSize;
//原文件的长度
private long length;
//分割得到的文件名的集合
private List<String> splitFileNames=new ArrayList<String>();
public SplitFile(String srcPath,long blockSize){
this.srcPath=srcPath;
this.blockSize=blockSize;
init();
}
/**
* 初始化文件分隔需要用到的参数
*/
private void init(){
//路径为空,则抛出异常
if(srcPath==null){
throw new RuntimeException("文件路径不合法");
}
src=new File(srcPath);
//文件是不是存在
if(!src.exists()){
throw new RuntimeException("文件不存在");
}
//是不是是文件夹
if(src.isDirectory()){
throw new RuntimeException("不能分割文件夹");
}
//如果文件存在
length=src.length();
if(length<this.blockSize){
this.blockSize=length;
}
//计算分割的块数
size=(int) ((length⑴)/this.blockSize+1);
//初始化分割后的文件名集合
initSplitFileNames();
}
/**
* 初始化文件被分割后新生成文件的名字
* 格式为:原文件名+第几块+扩大名
*/
private void initSplitFileNames() {
//文件的全名(包括后缀)
String fileName=src.getName();
//取得文件的扩大名前的分隔符‘.’
int index=fileName.indexOf('.');
//文件名的前缀
String prefixName=fileName.substring(0,index );
//文件名的后缀
String extName=fileName.substring(index);
for(int i=0;i<size;i++){
splitFileNames.add(prefixName+(i+1)+extName);
}
}
/**
* 文件分割的详细细节
*/
public void split(){
RandomAccessFile raf=null;
OutputStream os=null;
try {
raf=new RandomAccessFile(src,"r");
byte[] b=new byte[1024];
int len=0;
for(int i=0;i<size;i++){
raf.seek(blockSize*i);
//计算最后1块的实际大小
if(i==(size⑴)){
actualBlockSize=length-blockSize*(size⑴);
}else{
actualBlockSize=blockSize;
}
os=new BufferedOutputStream(new FileOutputStream(new File(src.getParent(),splitFileNames.get(i))));
while(⑴!=(len=raf.read(b))){
//如果读取的长度已超过了实际的长度,则只需要写实际长度的数据
if(len>=actualBlockSize){
os.write(b, 0, (int) actualBlockSize);
os.flush();
break;
}else{
os.write(b, 0, len);
os.flush();
actualBlockSize-=len;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(raf!=null){
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//测试
public static void main(String[] args) {
SplitFile sf=new SplitFile("F:\\test\\tiantang\\java1\\TestException.java",200);
sf.split();
}
}
这样我们就实现了文件的分割,至于文件的合并的思路则是顺次将文件读到内存中,然后将文件利用 new FileOutputStream(destPath,true)将文件写出,注意该对象的第2个参数需要指定为true,只要这样才能是将文件追加写入,否则将是覆盖上一篇 shc加密shell原理