在老的FAT32文件系統中,最大的單個文件大小必須保存在4G內,對於常常看電影的我這個是不能容許的。不過如今Windows有NTFS文件系統,Linux大部分發行版爲Ext4文件系統,最大單個文件大小能大於4G。不過這兩者並不能兼容。。格式化NTFS的U盤Linux不能識別,格式化Ext4的U盤Windows不能識別,只能用老的FAT32兼容兩者。因此將文件分割,再進行拼接就很重要,文件通過分割了在網絡上傳輸就十分方便,也能開多線程對每部分進行HASH提升處理效率。網絡
最近看的BradPitt的《狂怒》首先:對文件進行分割須要肯定每一部分的大小,假設上面的Fury.mkv文件大小爲280M,分割每一塊設置默認大小爲64M,因此: 多線程
對於最後一塊,通常小於等於設定好的每塊默認大小。 每塊大小設置好了,接下來,就須要將文件的路徑獲取,代碼中搭建輸入流,將文件讀入內存緩衝區中,再搭建輸出流,將緩衝區輸出到新的分割文件中。 再接下來實現就很簡單了。 新建一個 FileSlice類:有切割方法,拼接方法。public class FileSlice {
/**
* 分割文件
* @param filePath 文件路徑
* @param filePieceSize 文件每塊大小,單位爲字節,爲-1則默認爲每塊64M
* @return 成功返回True,出錯則返回False
*/
public static boolean slice(Path filePath, int filePieceSize){
return true;
}
/**
* 將分割好的文件從新連接
* @param filePath 被分割好的其中之一文件路徑,默認其餘塊與其在同一目錄下
* @param howManyParts 一共有多少塊
* @return 成功返回True,出錯則返回False
*/
public static boolean glue(Path filePath, int howManyParts){
return true;
}
}
複製代碼
接下來實現單線程的分割方法: 用圖解的話應該是這樣: ide
代碼實現: 進入函數首先判斷文件是否存在:if (!Files.exists(filePath)){
return false;
}
複製代碼
接下來判斷每塊大小是否使用默認值:函數
if(filePieceSize == -1){
filePieceSize = 1024*1024*64;
}
複製代碼
將路徑轉換爲文件對象,再計算將分割多少塊:測試
File file = filePath.toFile();
int howManyParts = (int) Math.ceil(file.length() / (double)filePieceSize);
複製代碼
初始化輸入輸出流,出錯輸出錯誤信息,返回false,得到當前目錄:spa
DataInputStream fileReader = null;
try {
fileReader = new DataInputStream(new FileInputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("文件找不到!");
return false;
}
DataOutputStream fileWriter;
Path dir = filePath.getParent();
複製代碼
接下來讀取文件,而且分別輸出到各個part文件中:線程
int readLength = -1;
long total = 0;
try {
for (int i = 1; i <= howManyParts ; i++){
//新建文件part i
Path temp = Files.createFile(dir.resolve(filePath.getFileName() + ".part" + i));
//搭建輸出流
fileWriter = new DataOutputStream(new FileOutputStream(temp.toFile()));
//讀取文件並輸出
while ( (readLength = fileReader.read(buffer)) != -1){
fileWriter.write(buffer,0,readLength);
fileWriter.flush();
total += readLength;
if (total == filePieceSize){
total = 0;
break;
}
}
//part i的文件已經輸出完畢,關閉流
fileWriter.close();
}
//讀取完畢,關閉輸入流
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO錯誤!");
return false;
}
複製代碼
該函數已經實現完畢,接下來測試(因爲電影Fury有14G。。太大了。。仍是換個吧): code
我是大哥大第5集,有729M,大概能分個12個part吧。public static void main(String[] args) throws IOException {
double before = System.currentTimeMillis();
Path bigboss = Paths.get("D:\\Video\\我是大哥大\\我是大哥大.Kyou.kara.Ore.wa.Ep05.Chi_Jap.HDTVrip.1280X720.mp4");
FileSlice.slice(bigboss,-1);
double after = System.currentTimeMillis();
System.out.println("分割文件我是大哥大.Kyou.kara.Ore.wa.Ep05.Chi_Jap.HDTVrip.1280X720.mp4," + Files.size(bigboss) + "字節,總用時" + (after - before) + "ms" );
}
複製代碼
運行結果:cdn
分割文件我是大哥大.Kyou.kara.Ore.wa.Ep05.Chi_Jap.HDTVrip.1280X720.mp4,765321889字節,總用時16335.0ms
複製代碼
速度仍是挺慢的。。 下次仍是換成多線程來實現,再來測試下速度。在單線程狀況下一個普通的40分鐘日劇都要15-30s左右,要是mkv格式的電影都要很久了。。不過其實極限應該不在CPU中執行的速度,而是在硬盤IO中,若是是普通硬盤那麼就算是多線程也應該提速不了多少。。
這個就很簡單了,和分割相反就OK。 直接上完整代碼:對象
public static boolean glue(Path filePath, int howManyParts){
if (!Files.exists(filePath)){
return false;
}
//獲取原始文件名
String filename = getOriginalFileName(filePath.getFileName().toString());
if (filename == null){
System.out.println("傳入part文件名解析出錯!");
return false;
}
//初始化緩衝區
byte [] buffer = new byte[1024 * 8];
//獲取文件存儲的路徑
Path dir = filePath.getParent();
try {
DataInputStream fileReader = null;
//建立原始文件
Files.createFile(dir.resolve(filename));
//搭建原始文件輸出流
DataOutputStream fileWriter = new DataOutputStream(new FileOutputStream(dir.resolve(filename).toFile()));
int readLength = -1;
for (int i = 1; i <= howManyParts ; i++){
//獲得part i文件路徑
Path temp = dir.resolve(filename + ".part" + i);
//搭建輸入流
fileReader = new DataInputStream(new FileInputStream(temp.toFile()));
//讀取文件並輸出
while ( (readLength = fileReader.read(buffer)) != -1){
fileWriter.write(buffer,0,readLength);
fileWriter.flush();
}
//part i的文件已經讀入完畢,關閉流
fileReader.close();
}
//寫入完畢,關閉輸出流
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO錯誤!");
return false;
}
return true;
}
複製代碼
再測試剛剛分割好的我是大哥大第5集
public static void main(String[] args) throws IOException {
double before = System.currentTimeMillis();
Path bigboss = Paths.get("D:\\Video\\我是大哥大\\我是大哥大.Kyou.kara.Ore.wa.Ep05.Chi_Jap.HDTVrip.1280X720.mp4.part1");
FileSlice.glue(bigboss,12);
double after = System.currentTimeMillis();
System.out.println("拼接12個part,用時" + (after - before) + "ms");
}
複製代碼
結果輸出,用12s左右,還行。
拼接12個part,用時12147.0ms
複製代碼
打開播放毫無問題,最後截張圖。
未完待續。。下次來使用多線程進行實現。