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();
}
}
}
}