package test; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class FileUtil { private final static short MAGIC = (short) 0xacef; private final static String SUFFIX = ".part"; public static void main(String[] args) throws IOException { FileUtil util = new FileUtil(); // util.splitBySize("E:\\test\\Spring源码深度解析.pdf", 50 * 1024 * 1024); util.mergePartFiles("E:\\test", "E:\\test\\Spring.pdf"); } /** * 左填充 */ public static String leftPad(String str, int length, char ch) { if (str.length() >= length) { return str; } char[] chs = new char[length]; Arrays.fill(chs, ch); char[] src = str.toCharArray(); System.arraycopy(src, 0, chs, length - src.length, src.length); return new String(chs); } /** * 删除文件 */ public static boolean delete(String fileName) { boolean result = false; File f = new File(fileName); if (f.exists()) { result = f.delete(); } else { result = true; } return result; } /*** * 递归获取指定目录下的所有的文件(不包括文件夹) */ public static List<File> getAllFiles(String dirPath) { File dir = new File(dirPath); List<File> files = new ArrayList<File>(); if (dir.isDirectory()) { File[] fileArr = dir.listFiles(); for (int i = 0; i < fileArr.length; i++) { File f = fileArr[i]; if (f.isFile()) { files.add(f); } else { files.addAll(getAllFiles(f.getPath())); } } } return files; } /** * 获取指定目录下的所有文件(不包括子文件夹) */ public static List<File> getDirFiles(String dirPath) { File path = new File(dirPath); File[] fileArr = path.listFiles(); List<File> files = new ArrayList<File>(); for (File f : fileArr) { if (f.isFile()) { files.add(f); } } return files; } /** * 获取指定目录下特定文件后缀名的文件列表(不包括子文件夹) */ public static List<File> getDirFiles(String dirPath, final String suffix) { File path = new File(dirPath); File[] fileArr = path.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { String lowerName = name.toLowerCase(); String lowerSuffix = suffix.toLowerCase(); if (lowerName.endsWith(lowerSuffix)) { return true; } return false; } }); List<File> files = new ArrayList<File>(); for (File f : fileArr) { if (f.isFile()) { files.add(f); } } return files; } /** * 追加内容到指定文件 */ public static void append(String fileName, String fileContent) throws IOException { File f = new File(fileName); if (f.exists()) { RandomAccessFile rFile = new RandomAccessFile(f, "rw"); byte[] b = fileContent.getBytes(); long originLen = f.length(); rFile.setLength(originLen + b.length); rFile.seek(originLen); rFile.write(b); rFile.close(); } } /** * 拆分文件 */ public List<String> splitBySize(String fileName, int byteSize) throws IOException { List<String> parts = new ArrayList<String>(); File file = new File(fileName); int count = (int) Math.ceil(file.length() / (double) byteSize); ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 0, count, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(count)); String destDir = file.getParent(); for (int i = 0; i < count; i++) { String partFileName = destDir + File.separator + file.getName() + leftPad(String.valueOf(i + 1), String.valueOf(count).length(), '0') + SUFFIX; Fragment f = new Fragment(); f.count = count; f.order = i + 1; f.byteSize = byteSize; f.startPos = i * byteSize; f.partFile = new File(partFileName); threadPool.execute(new SplitRunnable(file, f)); parts.add(partFileName); } return parts; } /** * 合并文件 */ public void mergePartFiles(String dirPath, String mergeFileName) throws IOException { List<Fragment> fragments = collectPartFiles(dirPath); if(fragments.size() < 1){ return; } RandomAccessFile randomAccessFile = new RandomAccessFile(mergeFileName, "rw"); Fragment f = fragments.get(fragments.size() -1); randomAccessFile.setLength(f.startPos + f.byteSize); randomAccessFile.close(); ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 0, fragments.size(), 1, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(fragments.size())); for (int i = 0; i < fragments.size(); i++) { threadPool.execute(new MergeRunnable(mergeFileName, fragments.get(i))); } } public List<Fragment> collectPartFiles(String dirPath) throws IOException{ List<File> partFiles = getDirFiles(dirPath); Set<Fragment> fragments = new HashSet<Fragment>(); for(File file : partFiles){ DataInputStream in = new DataInputStream(new FileInputStream(file)); if(in.available() < 14) continue; short magic = in.readShort(); if(magic != MAGIC) continue; int count = in.readInt(); int order = in.readInt(); int size = in.readInt(); if(size + 14 != file.length()) continue; Fragment fragment = new Fragment(); fragment.byteSize = size; fragment.count = count; fragment.order = order; fragment.partFile = file; fragments.add(fragment); in.close(); } List<Fragment> list = new ArrayList<Fragment>(); list.addAll(fragments); Collections.sort(list, new Comparator<Fragment>(){ @Override public int compare(Fragment o1, Fragment o2) { return o1.order - o2.order; } }); long startPos = 0; for(int i = 0; i < list.size(); i++){ Fragment f = list.get(i); if(f.order != i + 1){ return Collections.emptyList(); } if(f.count != list.size()){ return Collections.emptyList(); } f.startPos = startPos; startPos = startPos + f.byteSize; } return list; } public static class Fragment { private int count; private int order; private long startPos; private int byteSize; private File partFile; public int getCount() { return count; } public void setCount(int count) { this.count = count; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public long getStartPos() { return startPos; } public void setStartPos(long startPos) { this.startPos = startPos; } public int getByteSize() { return byteSize; } public void setByteSize(int byteSize) { this.byteSize = byteSize; } public File getPartFile() { return partFile; } public void setPartFile(File partFile) { this.partFile = partFile; } @Override public int hashCode() { final int prime = 31; long result = 1; result = prime * result + byteSize; result = prime * result + count; result = prime * result + order; result = prime * result + startPos; return (int)result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Fragment other = (Fragment) obj; if (byteSize != other.byteSize) return false; if (count != other.count) return false; if (order != other.order) return false; if (startPos != other.startPos) return false; return true; } } /** * 分割处理Runnable */ private class SplitRunnable implements Runnable { File originFile; Fragment fragment; public SplitRunnable(File originFile, Fragment fragment) { this.fragment = fragment; this.originFile = originFile; } public void run() { RandomAccessFile rFile; DataOutputStream os; try { rFile = new RandomAccessFile(originFile, "r"); byte[] b = new byte[fragment.byteSize]; os = new DataOutputStream(new FileOutputStream(fragment.partFile)); os.writeShort(MAGIC); os.writeInt(fragment.count); os.writeInt(fragment.order); rFile.seek(fragment.startPos); int s = rFile.read(b); os.writeInt(s); os.write(b, 0, s); os.flush(); os.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 合并处理Runnable */ private class MergeRunnable implements Runnable { String mergeFileName; Fragment fragment; public MergeRunnable(String mergeFileName, Fragment fragment) { this.mergeFileName = mergeFileName; this.fragment = fragment; } public void run() { RandomAccessFile rFile; try { rFile = new RandomAccessFile(mergeFileName, "rw"); rFile.seek(fragment.startPos); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fragment.partFile)); byte[] buf = new byte[2048]; bis.read(buf, 0, 14); int len = 0; while((len = bis.read(buf)) > 0){ rFile.write(buf, 0, len); } bis.close(); rFile.close(); } catch (IOException e) { e.printStackTrace(); } } } }