java有幾種文件拷貝方式侥衬?哪一種最高效诗祸?
java有多重比較典型的文件拷貝實(shí)現(xiàn)方式:
1、利用java.io.類庫(kù)轴总,直接為源文件構(gòu)建一個(gè)FileInputStream讀取直颅,然后再為目標(biāo)文件構(gòu)建一個(gè)FileOutputStream,完成寫入工作
public static void copyFileByStream(File source, File dest) throws
IOException {
try (InputStream is = new FileInputStream(source);
OutputStream os = new FileOutputStream(dest);){
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
}
}
2怀樟、利用java.nio類庫(kù)提供的transferTo或transferFrom方式實(shí)現(xiàn)
public static void copyFileByChannel(File source, File dest) throws
IOException {
try (FileChannel sourceChannel = new FileInputStream(source)
.getChannel();
FileChannel targetChannel = new FileOutputStream(dest).getChannel
();){
for (long count = sourceChannel.size() ;count>0 ;) {
long transferred = sourceChannel.transferTo(
sourceChannel.position(), count, targetChannel); sourceChannel.position(sourceChannel.position() + transferred);
count -= transferred;
}
}
}
java標(biāo)準(zhǔn)類庫(kù)本身提供了幾種Files.copy的實(shí)現(xiàn)
對(duì)于copy的效率功偿,這個(gè)其實(shí)與操作系統(tǒng)和配置等情況相關(guān),總體來(lái)說(shuō)往堡,NIO transferTo/From的方式可能更快脖含,因?yàn)樗芾矛F(xiàn)代操作系統(tǒng)底層機(jī)制,避免不要拷貝和上下文切換投蝉。
拷貝實(shí)現(xiàn)機(jī)制分析
操作系統(tǒng)包含用戶態(tài)空間和內(nèi)核態(tài)空間,操作系統(tǒng)內(nèi)核征堪、硬件驅(qū)動(dòng)運(yùn)行在內(nèi)核態(tài)空間瘩缆,具有較高的特權(quán);而用戶空間佃蚜,則是給普通應(yīng)用和服務(wù)使用庸娱。
當(dāng)使用輸入輸出流進(jìn)行讀寫時(shí),實(shí)際上進(jìn)行了多次上下文切換谐算,比如應(yīng)用讀取數(shù)據(jù)時(shí)熟尉,先在內(nèi)核態(tài)將數(shù)據(jù)從磁盤讀取到內(nèi)核緩存,在切換到用戶態(tài)將數(shù)據(jù)從內(nèi)核緩存讀取到用戶緩存洲脂。
所以斤儿,這種方式會(huì)帶來(lái)一定的額外開銷,可能會(huì)降低 IO 效率恐锦。
而基于NIO transferTo的實(shí)現(xiàn)方式往果,在Linux和Unix上,則會(huì)使用零拷貝技術(shù)一铅,數(shù)據(jù)傳輸并不需要用戶態(tài)參與陕贮,省去上下文切換的開銷和不必要的內(nèi)存拷貝,進(jìn)而可能提高應(yīng)用拷貝性能潘飘。注意肮之,transferTo 不僅僅是可以用在文件拷貝中掉缺,與其類似的,例如讀取磁盤文件戈擒,然后進(jìn)行 Socket 發(fā)送眶明,同樣可以享受這種機(jī)制帶來(lái)的性能和擴(kuò)展性提高。
NIO Buffer
buffer是NIO操作數(shù)據(jù)的基本工具峦甩,java為每種數(shù)據(jù)類型都提供了相應(yīng)的buffer實(shí)現(xiàn)(布爾除外)
Buffer 有幾個(gè)基本屬性:
- capcity:它反映這個(gè)buffer到底多大赘来,也就是數(shù)據(jù)長(zhǎng)度
- postion:要操作的數(shù)據(jù)起始位置
- limit:相當(dāng)于操作的限額,在讀取或者寫入時(shí)凯傲,limit 的意義很明顯是不一樣的犬辰。比如,讀取操作時(shí)冰单,很可能將 limit 設(shè)置到所容納數(shù)據(jù)的上限幌缝;而在寫入時(shí),則會(huì)設(shè)置容量或容量以下的可寫限度诫欠。
- mark涵卵,記錄上一次postion的位置,默認(rèn)是0