这是一道面试题,题意如图所示:
参考文献地址是http://www.cnblogs.com/yjmyzz/p/how-to-split-a-large-file-into-small-files-fastly.html
以上这篇参考文献对我帮助很大。文件分割部分基本是按照他的方法来改的,不过它是采用的多线程,我没有采用多线程。
既然不能利用文件名,那么就需要把顺序信息存到文件中去,分割后每个文件前五个字节表示顺序,其中第一个文件后面还有五个字节表示总共有多少个文件,再后面还有50个字节表示原文件名。我后来想如果在每个文件里都加上总共有多少个文件也许更好,处理起来会更简单,因为我这里还要单独处理万一少了第一个文件的情况。
分割就是将文件按照前五个字节排序之后,去除后加入的信息,再写入就可以了。我之前有个错误就是将第一个文件的读到的byte[]转换为String处理后加入的信息,再转回回byte[]进行写入,会产生错误,直接用读到的byte[]写就解决了~that's all ~不是很难,就是比较麻烦,而且不熟练。
package lzz;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Map;
import java.util.TreeMap;
public class FileUtilNew {
/**
* 当前目录路径
*/
public static String currentWorkDir = System.getProperty("user.dir") + "\\";
/**
* 存放分割后文件目录
*/
public static String splitDir = "F:\\files\\";
/**
* 拆分文件
*
* @param fileName
* 待拆分的完整文件名
* @param partNumber
* 拆分成多少部分
* @throws IOException
*/
public void splitByNum(String fileName, int partNumber)throws IOException {
File file = new File(fileName);
long totalLen = file.length();
int averLen = (int)(totalLen / partNumber);
int lastLen = (int)(totalLen - averLen * (partNumber - 1));
System.out.println(averLen + " " + lastLen);
String filePre = "00001" + leftFill(String.valueOf(partNumber)) + leftFillFileName(file.getName());
executeSplit(averLen, 0, filePre, file);
for (int i = 2; i < partNumber; i++) {
filePre = leftFill(String.valueOf(i));
executeSplit(averLen, (i - 1) * averLen, filePre, file);
}
filePre = leftFill(String.valueOf(partNumber));
executeSplit(lastLen, (partNumber - 1) * averLen, filePre, file);
}
/**
* 合并文件
*
* @param dirPath
* 拆分文件所在目录名
* @throws FileNotFoundException
* @throws IOException
*/
public void mergePartFiles(String dirPath) throws IOException{
File path = new File(dirPath);
File[] files = path.listFiles();
int fileNumber = files.length;
Map<Integer,File> map = new TreeMap<Integer,File>();
for(int i = 0; i < fileNumber; i++){
FileInputStream fs = new FileInputStream(files[i]);
byte[] b = new byte[5];
fs.read(b);
fs.close();
int index = Integer.parseInt(new String(b));
map.put(index, files[i]);
}
File fileFir = map.get(1);
FileInputStream fis = new FileInputStream(fileFir);
byte[] b = new byte[(int)fileFir.length()];
fis.read(b);
fis.close();
int splitNum = Integer.parseInt(new String(b,5, 5));
if(splitNum != fileNumber){
System.out.println("File Lose!");
return;
}
String fileName = "";
for(int i = 10; i < 60; i++){
if(b[i] != '.'){
fileName = new String(b,i,60-i);
break;
}
}
FileOutputStream fos = new FileOutputStream(dirPath + fileName);
fos.write(b, 60, b.length-60);
map.remove(1);
int len = 0;
byte[] con = null;
for(Map.Entry<Integer, File> entry : map.entrySet()){
FileInputStream fs = new FileInputStream(entry.getValue());
len = (int)entry.getValue().length();
con = new byte[len];
fs.read(con);
fs.close();
fos.write(con, 5, len-5);
}
fos.close();
}
private void executeSplit(int byteSize, int startPos, String partFileIndex,File originFile){
RandomAccessFile rFile;
OutputStream os;
try {
rFile = new RandomAccessFile(originFile, "r");
byte[] b = new byte[byteSize];
rFile.seek(startPos);// 移动指针到每“段”开头
int s = rFile.read(b);
os = new FileOutputStream(splitDir + partFileIndex.substring(0,5));
os.write(partFileIndex.getBytes());
os.write(b, 0, s);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private String leftFill(String index){
int zeroNum = 5 - index.length();
StringBuilder sb = new StringBuilder("");
for(int i = 0; i < zeroNum; i++){
sb.append("0");
}
sb.append(index);
return sb.toString();
}
private String leftFillFileName(String name) {
// TODO Auto-generated method stub
int dotNum = 50 - name.length();
StringBuilder sb = new StringBuilder("");
for(int i = 0; i < dotNum; i++){
sb.append(".");
}
sb.append(name);
return sb.toString();
}
}