欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java使用NIO優(yōu)化IO實(shí)現(xiàn)文件上傳下載功能

 更新時(shí)間:2022年07月28日 09:51:54   作者:趙廣陸  
IO 是基于流來讀取的,而NIO則是基于塊讀取,面向流 的 I/O 系統(tǒng)一次一個(gè)字節(jié)地處理數(shù)據(jù),這篇文章主要介紹了Java使用NIO優(yōu)化IO實(shí)現(xiàn)文件上傳下載功能,需要的朋友可以參考下

1 NIO的一些基礎(chǔ)預(yù)備知識(shí)

Java中IO流類的體系中BIO與NIO:https://blog.csdn.net/ZGL_cyy/article/details/104326458
Java IO體系與NIO和BIO體系面試題 :https://blog.csdn.net/ZGL_cyy/article/details/122836368
為什么使用NIO:因?yàn)閭鹘y(tǒng)IO文件傳輸速率低,所以選擇了NIO進(jìn)行文件的下載操作。NIO還有一個(gè)好處就是其中零拷貝可以實(shí)現(xiàn)減少內(nèi)存中數(shù)據(jù)的重復(fù),減少CPU操作的效果。所以相對(duì)于傳統(tǒng)IO,NIO有著效率高點(diǎn)的優(yōu)勢(shì)。

2 NIO為何較傳統(tǒng)的io速度較快

就拿單個(gè)io過程來看,首先時(shí)間主要花在了用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換上,其次,考慮將多個(gè)io的“合并”為一個(gè)io,這不就節(jié)省時(shí)間了嗎

相應(yīng)的NIO主要做了兩方面的提升

1.避免了用戶態(tài)和內(nèi)核態(tài)的交換,直接操作內(nèi)存,用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換是很費(fèi)時(shí)的,傳統(tǒng)的io寫入磁盤時(shí),用戶態(tài)的接口不能直接操作內(nèi)存,而是通過操作系統(tǒng)調(diào)用內(nèi)核態(tài)接口來進(jìn)行io。

2.利用buffer減少io的次數(shù),buffer化零為整”的寫入方式因?yàn)榇蟠鬁p小了尋址/寫入次數(shù),所以就降低了硬盤的負(fù)荷。

3.IO 是基于流來讀取的,而NIO則是基于塊讀取,面向流 的 I/O 系統(tǒng)一次一個(gè)字節(jié)地處理數(shù)據(jù)。一個(gè)輸入流產(chǎn)生一個(gè)字節(jié)的數(shù)據(jù),一個(gè)輸出流消費(fèi)一個(gè)字節(jié)的數(shù)據(jù)。為流式數(shù)據(jù)創(chuàng)建過濾器非常容易。鏈接幾個(gè)過濾器,以便每個(gè)過濾器只負(fù)責(zé)單個(gè)復(fù)雜處理機(jī)制的一部分,這樣也是相對(duì)簡(jiǎn)單的。不利的一面是,面向流的 I/O 通常相當(dāng)慢。
一個(gè) 面向塊 的 I/O 系統(tǒng)以塊的形式處理數(shù)據(jù)。每一個(gè)操作都在一步中產(chǎn)生或者消費(fèi)一個(gè)數(shù)據(jù)塊。按塊處理數(shù)據(jù)比按(流式的)字節(jié)處理數(shù)據(jù)要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優(yōu)雅性和簡(jiǎn)單性。

4.非阻塞IO 和 異步IO的支持, 減少線程占有的??臻g,以及上下文切換

5.IO 多路復(fù)用的支持

6.Buffer 支持,所有讀寫操作都是基于 緩沖 來實(shí)現(xiàn)

7.NIO 支持 Direct Memory, 可以減少一次數(shù)據(jù)拷貝

8.Netty 零拷貝的支持

3 NIO實(shí)戰(zhàn)上傳下載

3.1 url下載文件

java NIO包提供了無緩沖情況下在兩個(gè)通道之間直接傳輸字節(jié)的可能。

為了讀來自URL的文件,需從URL流創(chuàng)建ReadableByteChannel :

ReadableByteChannel readableByteChannel = Channels.newChannel(url.openStream());

從ReadableByteChannel 讀取字節(jié)將被傳輸至FileChannel:

FileOutputStream fileOutputStream = new FileOutputStream(FILE_NAME);
FileChannel fileChannel = fileOutputStream.getChannel();

然后使用transferFrom方法,從ReadableByteChannel 類下載來自URL的字節(jié)傳輸?shù)紽ileChannel:

fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);

transferTo() 和 transferFrom() 方法比簡(jiǎn)單使用緩存從流中讀更有效。依據(jù)不同的底層操作系統(tǒng),數(shù)據(jù)可以直接從文件系統(tǒng)緩存?zhèn)鬏數(shù)轿覀兊奈募?,而不必將任何字?jié)復(fù)制到應(yīng)用程序內(nèi)存中。

在Linux和UNIX系統(tǒng)上,這些方法使用零拷貝技術(shù),減少了內(nèi)核模式和用戶模式之間的上下文切換次數(shù)。

工具類:

/**NIO文件下載工具類
 * @author olalu
 */
public class NioDownloadUtils {

    /**
     * @description:
     * @param file: 要下在文件
     * @return: void
     */
    public static void downloadDoc(File file,HttpServletResponse response) throws IOException {
        OutputStream outputStream = response.getOutputStream();
        String contentType = Files.probeContentType(Paths.get(file.getAbsolutePath()));
        //設(shè)置響應(yīng)頭
        response.setHeader("Content-Type", contentType);
        response.setHeader("Content-Disposition", "attachment;filename="+ new String(file.getName().getBytes("utf-8"),"ISO8859-1"));
        response.setContentLength((int) file.length());
        //獲取文件輸入流
        FileInputStream fileInputStream = new FileInputStream(file);
        //獲取輸出流通道
        WritableByteChannel writableByteChannel = Channels.newChannel(outputStream);
        FileChannel fileChannel = fileInputStream.getChannel();
        //采用零拷貝的方式實(shí)現(xiàn)文件的下載
        fileChannel.transferTo(0,fileChannel.size(),writableByteChannel);
        //關(guān)閉對(duì)應(yīng)的資源
        fileChannel.close();
        outputStream.flush();
        writableByteChannel.close();
    }

    public static void downloadDoc(String path,HttpServletResponse response) throws IOException {
        File file = new File(path);
        if (!file.exists()){
            throw new RuntimeException("文件不存在");
        }
        downloadDoc(file,response);
    }

}


3.2 通過NIO上傳文件

/**
     * 文件上傳方法
     */
    public static Result uploading(MultipartFile file) {
        //獲取文件名
        String realName = file.getOriginalFilename();
        String newName = null;
        if(realName != null && realName != ""){
            //獲取文件后綴
            String suffixName = realName.substring(realName.lastIndexOf("."));
            //生成新名字
            newName = UUID.randomUUID().toString().replaceAll("-", "")+suffixName;
        }else {
            return Result.fail("文件名不可為空");
        }
        //創(chuàng)建流
        FileInputStream fis = null;
        FileOutputStream fos = null;
        //創(chuàng)建通道
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            fis = (FileInputStream)file.getInputStream();
            //開始上傳
            fos = new FileOutputStream(UPLOAD_URL+"\\"+newName);
            //通道間傳輸
            inChannel = fis.getChannel();
            outChannel = fos.getChannel();
            //上傳
            inChannel.transferTo(0,inChannel.size(),outChannel);

        }catch (IOException e){
            return Result.fail("文件上傳路徑錯(cuò)誤");
        }finally {
            //關(guān)閉資源
            try {
                if (fis != null) {
                    fis.close();
                }
                if (fos != null) {
                    fos.close();
                }
                if (inChannel != null) {
                    inChannel.close();
                }
                if (outChannel != null) {
                    outChannel.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return Result.ok(newName);

    }

到此這篇關(guān)于Java使用NIO優(yōu)化IO實(shí)現(xiàn)文件上傳下載的文章就介紹到這了,更多相關(guān)Java NIO文件上傳下載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論