在项目针对比较大的文件需要文件的分割功能,特意写了一个具有分割功能代码,以供大家拍砖之用,目的进行沟通交流,如有好的建议和联系本人沟通交流谢谢!
package easyway.tbs.file.transport.core.split;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 文件读写访问器
*
* @author longgangbai
*
*/
public class DataFileAccessor implements Serializable {
private final static Log logger = LogFactory.getLog(DataFileAccessor.class);
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 只读模式
*/
public static final String RANDOMACESSFILE_READ_MODE="r";
/**
* 只写模式
*/
public static final String RANDOMACESSFILE_WRITE_MODE="w";
/**
* 读写模式
*/
public static final String RANDOMACESSFILE_WRITE_READ_MODE="rw";
/**
* 随机读取的缓存文件的长度
*/
public static final int RANDOMACESSFILE_BUFFER_LENGTH=1024*1000;
/**
* 文件读取的对象操作对象
*/
private RandomAccessFile fileAcessor;
/**
* 在文件的路径
*/
private String filePath;
/**
*
* @throws IOException
*/
public DataFileAccessor() throws IOException {
this("", RANDOMACESSFILE_WRITE_READ_MODE);
}
/**
* 文件读取访问其
* @param sName
* @param nPos
* @param nPos
* @throws IOException
*/
public DataFileAccessor(String filePath, String mode) throws IOException {
this.filePath=filePath;
//支持读写操作
if(logger.isDebugEnabled()){
logger.info("filePath="+filePath+"======mode===="+mode);
}
fileAcessor = new RandomAccessFile(filePath, mode);
}
/**
* 写文件的片段
* @param buffer
* 临时存储的数据的数组
* @param nStart
* @param nLen
* @return
*/
public synchronized int write(byte[] buffer, int nStart, int nLen) {
if(logger.isDebugEnabled()){
logger.info("nStart="+nStart+" nLen="+nLen);
}
int n = -1;
try {
//移动文件指针
fileAcessor.seek(nStart);
fileAcessor.write(buffer, nStart, nLen);
n = nLen;
} catch (IOException e) {
logger.error("write file "+filePath +" nStart="+nStart+" nLen="+nLen,e);
}
return n;
}
/**
* 写文件的片段
* @param buffer
* 临时存储的数据的数组
* @param nStart
* @param nLen
* @return
*/
public synchronized int readFile(byte[] buffer, int offset, int nLen) {
try {
fileAcessor.seek(offset);
long length = nLen + 1;// 文件段的长度
byte[] b = new byte[RANDOMACESSFILE_BUFFER_LENGTH];
long m = length / b.length;// 读和写入2048个字节的次数
int leftsize = (int) (length - m * b.length);// 剩下的字节数
long timestart = System.currentTimeMillis();
for (long i = 1; i <= m; i++) {
fileAcessor.read(b);// 将数据从from文件读入
}
fileAcessor.read(b, 0, leftsize);// 读入最后剩下的字节
fileAcessor.close();// 关闭输入
long timeend = System.currentTimeMillis();
if(logger.isDebugEnabled()){
logger.info("线程" + Thread.currentThread().getName()
+ "读写完毕,共使用" + (timeend - timestart) + "毫秒");
}
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
/**
*
* @param file
* @param tempFile
* @param begin
* @param end
* @return
* @throws IOException
*/
public long writeTempFile(File file, File tempFile, long begin ,long end) throws IOException{
RandomAccessFile in=new RandomAccessFile(file,RANDOMACESSFILE_READ_MODE);
RandomAccessFile out=new RandomAccessFile(tempFile,RANDOMACESSFILE_WRITE_READ_MODE);
byte[] b=new byte[RANDOMACESSFILE_BUFFER_LENGTH];
int n=0;
in.seek(begin);
while(in.getFilePointer()<=end&&(n=in.read(b))!=-1){
out.write(b,0,n);
}
long endPointer=in.getFilePointer();
in.close();
out.close();
return endPointer;
}
public synchronized int read(byte[] buffer, int offset, int nLen) {
int n = -1;
FileInputStream is=null;
try {
is=new FileInputStream(filePath);
//忽略前面的读取信息
is.skip(offset);
fileAcessor.seek(offset);
//定义读取输入流内容的缓存数据
byte[] buff=new byte[RANDOMACESSFILE_BUFFER_LENGTH];
//定义最多需要读取几次就可以完成本次的读取
long times=(nLen%RANDOMACESSFILE_BUFFER_LENGTH==0)?nLen/RANDOMACESSFILE_BUFFER_LENGTH:((nLen/RANDOMACESSFILE_BUFFER_LENGTH)+1);
int hasRead=0;
for (int i = 0; i < times; i++) {
hasRead=is.read(buff);
if(hasRead<0){
break;
}
fileAcessor.read(buffer);
}
n = nLen;
} catch (IOException e) {
e.printStackTrace();
}finally{
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
is=null;
}
}
return n;
}
/**
* 关闭流对象
*
*/
public void close(){
if (fileAcessor != null) {
try {
fileAcessor.close();
} catch (Throwable ignore) {
}
fileAcessor = null;
}
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
}
package easyway.tbs.file.transport.core.split;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 文件分割线程
* @author longgangbai
*
*/
public class FileSplitterFetch implements Runnable {
private final static Log logger = LogFactory.getLog(DataFileAccessor.class);
/**
* 将读取到的字节输出到raf中
*/
private DataFileAccessor raf;
/**
* 文件整个完成标识
*/
private CountDownLatch masterLatch;
/**
* 当前文件读取执行完毕的标识
*/
private CountDownLatch childrenLatch;
/**
* 文件分割的文件片段
*/
private FileSplitterMessage message;
/**
* 构造器
* @param filepath 服务器文件的路径
* @param offset 输出流和读取起始点
* @param length 输出流和读取结束点
* @param buffer 数组的大小
* @throws IOException
*/
public FileSplitterFetch(FileSplitterMessage message,CountDownLatch masterLatch,CountDownLatch childrenLatch) throws IOException {
super();
this.message=message;
this.masterLatch=masterLatch;
this.childrenLatch=childrenLatch;
this.raf=new DataFileAccessor(message.getFilePath(),DataFileAccessor.RANDOMACESSFILE_READ_MODE);
System.out.println("raf=="+this.raf);
}
/**
* 执行读取的方法
*/
public void run() {
File tempFile = message.getTempFile();
try {
if(!tempFile.exists()){
tempFile.createNewFile();
}
//masterLatch.await();
this.raf.writeTempFile(new File(message.getFilePath()), tempFile, message.getStartPos(), message.getEndPos());
} catch (Exception ex) {
if(tempFile.exists()){
try {
FileUtils.forceDelete(tempFile);
} catch (IOException e) {
}
}
}finally {
//使用finally块来关闭当前线程的输入流、输出流
this.raf.close();
//childrenLatch.countDown();
}
}
}
package easyway.tbs.file.transport.core.split;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 文件分割管理器
* 当单个线程执行完毕之后,开始发送文件
* @author longgangbai
*
*/
public class FileSplitterManager {
private static String File_Split_Separator="_";
private static final transient Logger logger = LoggerFactory.getLogger(FileSplitterManager.class);
/**
* 文件的总长度
*/
private long fileLength;
/**
* 整个文件分割完成的标识
* 开始执行发送消息
*/
private CountDownLatch masterLatch = new CountDownLatch(1);
/**
*文件分割线程的数量
*/
private int splitThreadNum;
/**
*
* 当每一个线程执行完毕时候,则报告执行执行线程完成,当所有的执行线程
* 执行完毕,则开始发送文件
*/
private CountDownLatch childrenLatch = null;
/**
* 文件片段的集合
*/
private List<FileSplitterMessage> fileSplitterMessageList=null;
/**
* 创建文件锁
*/
private FileTransportLock fileLock=null;
//发送文件的路径
private String filepath;
//发送文件的限制大小
private int filepageSize;
private String fileChannel;
private File file;
/**
*
* @param filepath
* @param filepageSize
*/
public FileSplitterManager(String filepath,int filepageSize,String fileChannel){
this.filepath=filepath;
this.filepageSize=filepageSize;
this.fileChannel=fileChannel;
}
/**
* 文件分割管理器的方法
*
*/
public void splitFileMgr(){
file=new File(filepath);
//获取文件的大小
long fileTotalSize=file.length();
//如果文件的大小
if(filepageSize>0&&(filepageSize<fileTotalSize)){
initSplitFileMgr(file);
}else{
//直接发送文件
fileSplitterMessageList=new ArrayList<FileSplitterMessage>(1);
FileSplitterMessage fileSplitMessage=new FileSplitterMessage();
fileSplitMessage.setFilePath(file.getAbsolutePath());
fileSplitMessage.setFileLength(file.length());
fileSplitMessage.setFileName(file.getName());
fileSplitMessage.setSplitThreadNum(1);
fileSplitMessage.setCurrentThreadNum(1);
fileSplitMessage.setStartPos(0);
fileSplitMessage.setEndPos(filepageSize);
fileSplitMessage.setLen(fileTotalSize);
String threadNum="1";
String currentThread="1";
//临时文件的命名规则:源文件名称+“_”+"总线程数"+“_”+"当前线程编号"
String tempFileName=file.getName()+File_Split_Separator+threadNum+File_Split_Separator+currentThread+".tmp";
//文件相对比较小,文件的总线程数为1,当前线程也为1
File tempFile=getTempFileName(file.getParent(),tempFileName);
fileSplitMessage.setTempFile(tempFile);
fileSplitterMessageList.add(fileSplitMessage);
//重新命名原来的文件,标识文件已经开始发送
file.renameTo(new File(file.getAbsolutePath()+".bak"));
if(logger.isDebugEnabled()){
logger.debug("the direct send file "+file.getAbsolutePath());
}
}
System.out.println("fileSplitterMessageList ="+fileSplitterMessageList.size());
}
/**
* 创建临时文件
* @param parentPath
* @param tempFileName
* @return
*/
public File getTempFileName(String parentPath,String tempFileName){
System.out.println(parentPath+File.separator+tempFileName);
File tempFile=new File(parentPath+File.separator+tempFileName);
try {
if(tempFile.exists()){
FileUtils.forceDelete(tempFile);
if(logger.isDebugEnabled()){
logger.info("文件存在,已经删除!");
}
}
tempFile.createNewFile();
} catch (IOException e) {
if(logger.isDebugEnabled()){
logger.info("文件创建失败:"+e);
}
}
return tempFile;
}
/**
* 分割文件的方法
*
*/
public void initSplitFileMgr(File file) {
if(file.exists()){
//创建文件锁
//fileLock=new FileTransportLock(file,false);
try {
//设置文件锁
//fileLock.lock();
String fileName=file.getName();
//获取文件的长度
fileLength=file.length();
//获取文件对应的线程数
splitThreadNum=(int)getThreadNum(fileLength,filepageSize);
//线程同步线程
childrenLatch = new CountDownLatch(splitThreadNum);
//
fileSplitterMessageList=new ArrayList<FileSplitterMessage>(splitThreadNum);
//文件分割的过程
splitFile(filepath,filepageSize,fileName);
} catch (Exception e) {
e.printStackTrace();
}finally{
//释放文件锁
//fileLock.unlock();
}
}
}
/**
* 总的线程数
* @param fileSize
* @param filepageSize
* @return
*/
public long getThreadNum(long fileSize,long filepageSize){
long threadNum=(fileSize%filepageSize==0)?(fileSize%filepageSize):((fileSize/filepageSize)+1);
return threadNum;
}
/**
* 分解文件
* @param filepath 文件路径
* @param filepageSize 文件的大小
*/
public void splitFile(String filepath,int filepageSize,String fileName){
//当前线程真正读取的长度
int length=filepageSize;
//创建一个线程池
ExecutorService threadExePool = Executors.newFixedThreadPool(splitThreadNum);
//循环创建线程
for(int i=1;i<=splitThreadNum;i++){
//起始点
int startPos=(i-1)*filepageSize;
int endPos=i*filepageSize;
FileSplitterMessage fileSplitterMessage=new FileSplitterMessage();
String tempFileName=file.getName()+File_Split_Separator+splitThreadNum+File_Split_Separator+i+".tmp";
File tempFile=getTempFileName(file.getParent(), tempFileName);
//针对文件最后一个片度结束点和片段长度
if((splitThreadNum==i)&&(fileLength%filepageSize!=0)){
endPos=(int)fileLength;
length=(int)fileLength-startPos;
}
//设置文件片段内容
fileSplitterMessage.setTempFile(tempFile);
//文件读取起始点
fileSplitterMessage.setStartPos(startPos);
//文件读取起始点
fileSplitterMessage.setEndPos(endPos);
//文件总长度
fileSplitterMessage.setFileLength(fileLength);
//文件路径
fileSplitterMessage.setFilePath(filepath);
//文件分割线程数
fileSplitterMessage.setSplitThreadNum(splitThreadNum);
//当前线程编号数
fileSplitterMessage.setCurrentThreadNum(i);
//读取的长度
fileSplitterMessage.setLen(length);
System.out.println("fileSplitterMessage="+fileSplitterMessage);
//文件的名称
fileSplitterMessage.setFileName(file.getName());
fileSplitterMessageList.add(fileSplitterMessage);
}
try {
if(logger.isDebugEnabled()){
logger.debug("文件"+fileName+"开始分割....");
}
//线程池开始执行线程
for (FileSplitterMessage fileMessage : fileSplitterMessageList) {
threadExePool.execute(new FileSplitterFetch(fileMessage,masterLatch,childrenLatch));
}
masterLatch.countDown();//宣布开始
if(logger.isDebugEnabled()){
logger.debug("文件"+fileName+"分割完毕....");
}
//等待CountdownLatch信号为0,表示所有子线程都结束。
childrenLatch.await();//等待结束
System.out.println("size ================="+fileSplitterMessageList.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("整个文件"+fileName+"分割完毕");
//开始执行发送文件
}
//注意线程已经要结束了,但是threadExePool线程如果不关闭是不会结束的
threadExePool.shutdown();
}
public int getFilepageSize() {
return filepageSize;
}
public void setFilepageSize(int filepageSize) {
this.filepageSize = filepageSize;
}
public String getFilepath() {
return filepath;
}
public void setFilepath(String filepath) {
this.filepath = filepath;
}
public String getFileChannel() {
return fileChannel;
}
public void setFileChannel(String fileChannel) {
this.fileChannel = fileChannel;
}
}
package easyway.tbs.file.transport.core.split;
import java.io.File;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
/**
* 文件分割一段的信息
*
*
* @author longgangbai
*
*/
public class FileSplitterMessage {
/**
* 文件路径
*/
private String filePath;
/**
* 文件总长度
*/
private long fileLength;
/**
* 文件名称
*/
private String fileName;
/**
* 分割线程数量
*/
private int splitThreadNum;
/**
* 当前分割线程编号
*/
private int currentThreadNum;
/**
* 文件开始读取的起始点
*/
private int startPos;
/**
* 文件开始读取的结束点
*/
private int endPos;
/**
* 文件起止点之间的数据信息
*/
private byte[] data;
/**
* 临时文件
*/
private File tempFile;
/**
* 临时文件的长度
*/
private long len;
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public int getEndPos() {
return endPos;
}
public void setEndPos(int endPos) {
this.endPos = endPos;
}
public long getFileLength() {
return fileLength;
}
public void setFileLength(long fileLength) {
this.fileLength = fileLength;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public int getSplitThreadNum() {
return splitThreadNum;
}
public void setSplitThreadNum(int splitThreadNum) {
this.splitThreadNum = splitThreadNum;
}
public int getStartPos() {
return startPos;
}
public void setStartPos(int startPos) {
this.startPos = startPos;
}
public int getCurrentThreadNum() {
return currentThreadNum;
}
public void setCurrentThreadNum(int currentThreadNum) {
this.currentThreadNum = currentThreadNum;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public File getTempFile() {
return tempFile;
}
public void setTempFile(File tempFile) {
this.tempFile = tempFile;
}
@Override
public String toString(){
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
public long getLen() {
return len;
}
public void setLen(long len) {
this.len = len;
}
}
package easyway.tbs.file.transport.core.split;
import java.io.File;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
/**
* 文件分割一段的信息
*
*
* @author longgangbai
*
*/
public class FileSplitterMessage {
/**
* 文件路径
*/
private String filePath;
/**
* 文件总长度
*/
private long fileLength;
/**
* 文件名称
*/
private String fileName;
/**
* 分割线程数量
*/
private int splitThreadNum;
/**
* 当前分割线程编号
*/
private int currentThreadNum;
/**
* 文件开始读取的起始点
*/
private int startPos;
/**
* 文件开始读取的结束点
*/
private int endPos;
/**
* 文件起止点之间的数据信息
*/
private byte[] data;
/**
* 临时文件
*/
private File tempFile;
/**
* 临时文件的长度
*/
private long len;
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public int getEndPos() {
return endPos;
}
public void setEndPos(int endPos) {
this.endPos = endPos;
}
public long getFileLength() {
return fileLength;
}
public void setFileLength(long fileLength) {
this.fileLength = fileLength;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public int getSplitThreadNum() {
return splitThreadNum;
}
public void setSplitThreadNum(int splitThreadNum) {
this.splitThreadNum = splitThreadNum;
}
public int getStartPos() {
return startPos;
}
public void setStartPos(int startPos) {
this.startPos = startPos;
}
public int getCurrentThreadNum() {
return currentThreadNum;
}
public void setCurrentThreadNum(int currentThreadNum) {
this.currentThreadNum = currentThreadNum;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public File getTempFile() {
return tempFile;
}
public void setTempFile(File tempFile) {
this.tempFile = tempFile;
}
@Override
public String toString(){
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
public long getLen() {
return len;
}
public void setLen(long len) {
this.len = len;
}
}
package easyway.tbs.file.transport.core.split;
/**
* 分割文件测试类
* @author longgangbai
*
*/
public class FileSplitterManagerMain {
public static void main(String[] args) {
FileSplitterManager manager=new FileSplitterManager("E:/TestJoltProxy/RMAN.txt",10*1024*1024,"queue-svn");
manager.splitFileMgr();
}
}