package cn.com; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.RandomAccessFile; //文件的拆分和组合 //步骤: //1 依据源文件大小和每块的大小计算出块数 //2 将每一块写到一个对应的文件 public class FileSeparatorAndUnite { long rawFileSize; long blocksNumber; String rawFileName=null; String [] allPaths=null; public static void main(String[] args) { FileSeparatorAndUnite test=new FileSeparatorAndUnite(); //拆分文件 String [] allPaths=test.separatorFile("F:\\2.jpg", 1024*10); //组合文件 test.uniteFile(allPaths, "F:\\33.jpg"); } /** * @param rawFilePath 待拆分文件的路径 * @param perBlockSize 拆分后每份的大小 * @return 各部分路径的数组集合 */ private String[] separatorFile(String rawFilePath,long perBlockSize){ File rawFile=new File(rawFilePath); rawFileName=rawFile.getName(); rawFileSize=rawFile.length(); blocksNumber=getBlocksNumber(rawFileSize,perBlockSize); allPaths=new String[(int)blocksNumber]; if (blocksNumber==1) { perBlockSize=rawFileSize; } long perPartSize=0; long perPartBeginPosition=0; String perPartPath=null; for (int i = 1; i <=blocksNumber; i++) { if (i<blocksNumber) { //每一块的大小就为perBlockSize perPartSize=perBlockSize; } else { //最后一块的大小为总大小-该块的起始位置 perPartSize=rawFileSize-perPartBeginPosition; } //得到每一块的path if (blocksNumber==1) { perPartPath=rawFilePath+".bat"; } else { perPartPath=getPerPartFilePath(rawFilePath, i); } //操作每一块 //第一次调用时perPartBeginPosition当然为0 writePerPartToFile(rawFilePath, perPartPath, perBlockSize, perPartBeginPosition); //计算每一块的在原文件中的起始位置. perPartBeginPosition=perPartBeginPosition+perPartSize; //保存每一块的路径 allPaths[i-1]=perPartPath; } return allPaths; } /** * @param rawFilePath 原文件路径 * @param perPartFilePath 每部分对应的路径 * @param blockSize 每部分的块大小 * @param beginPosition 每部分在原文件中的开始位置 * @return * 在这里 len=len-(int)(writedBytes-blockSize)有些不好理解 * 假设blockSize=2100,每次写入1024,那么两次后还剩余 * 2100-1024*2=52 * 如果再写入1024,那么就会报错,超出了最大范围. * 所以还能写入的=blockSize-已经写入的大小(writedBytes) * 因为在if语句前面已经有了赋值语句writedBytes=writedBytes+len; * 所以需要:len=len-(int)(writedBytes-blockSize) * 其实代入:len=len-(int)(writedBytes+len-blockSize) * 可以得知:len=blockSize-writedBytes */ public boolean writePerPartToFile(String rawFilePath,String perPartFilePath,long blockSize,long beginPosition){ RandomAccessFile raf=null; FileOutputStream fos=null; byte [] buffer=new byte[8*1024]; int len=0; long writedBytes=0; try { raf=new RandomAccessFile(rawFilePath, "r"); raf.seek(beginPosition); fos=new FileOutputStream(perPartFilePath); while ((len=raf.read(buffer))!=-1) { if (writedBytes<blockSize) { writedBytes=writedBytes+len; if (writedBytes<=blockSize) { fos.write(buffer, 0, len); } else { len=len-(int)(writedBytes-blockSize); fos.write(buffer, 0, len); } } } } catch (Exception e) { try { if (fos!=null) { fos.close(); } if (raf!=null) { raf.close(); } } catch (Exception ex) { } return false; } return true; } /** * @param rawFileSize 原文件大小 * @param perBlockSize 每块的大小 * @return 拆分后块数 */ public long getBlocksNumber(long rawFileSize,long perBlockSize){ if (rawFileSize<=perBlockSize) { return 1; } else { if (rawFileSize%perBlockSize==0) { return ((rawFileSize/perBlockSize)+1); } else { return rawFileSize/perBlockSize; } } } /** * @param rawFilePath 原文件路径 * @param blockNumer 当前块号码 * @return 当前块对应的路径 */ public String getPerPartFilePath(String rawFilePath,int blockNumer){ String perPartFilePath=rawFilePath+".part"+blockNumer; return perPartFilePath; } /** * @param partsPaths 各部分路径 * @param unitedFilePath 合并后文件路径 */ public void uniteFile(String [] partsPaths,String unitedFilePath){ try { File perPartFile=null; File unitedFile=new File(unitedFilePath); FileOutputStream fos=new FileOutputStream(unitedFile); FileInputStream fis=null; for (int i = 0; i < partsPaths.length; i++) { perPartFile=new File(partsPaths[i]); fis=new FileInputStream(perPartFile); byte [] buffer=new byte[1024*8]; int len=0; while ((len=fis.read(buffer))!=-1) { fos.write(buffer, 0, len); } } fis.close(); fos.close(); } catch (Exception e) { } } }
时间: 2024-10-08 10:53:08