亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文探索Java文件讀寫更高效方式

 更新時間:2022年07月07日 14:24:08   作者:??你呀不牛??  
這篇文章主要介紹了一文探索Java文件讀寫更高效方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值需要的小伙伴可以參考一下

背景

最近在探秘kafka為什么如此快?其背后的秘訣又是什么?

懷著好奇之心,開始像剝洋蔥 一樣逐層內(nèi)嵌。一步步揭曉kafka能夠吊打mq的真因。了解之后不得不說kafka:yyds。

了解到順序存盤的運用

探測到稀疏索引的引進

知曉其零拷貝技術(shù)的威力

嗅覺到mmp(內(nèi)存映射文件)的神來之筆

......

mmp如此神奇,那么運用于文件壓縮,是否同樣可以實現(xiàn)飛速壓縮呢?

又懷著好奇之心,決定用實際行動證明這個結(jié)論(否則我們的知識只能紙上談兵)

編碼是我們的本能功能,好奇之心是我們永遠(yuǎn)的利器。不能丟

曾幾何時,有位BA告訴我他的經(jīng)歷:DEV轉(zhuǎn)為BA后,代碼就生疏了,后來他強迫自己每個迭代都領(lǐng)一個小需求鞭策自己。

曾幾何時,有位前輩告訴我:即使你以后成長為架構(gòu)師甚至更高職位,也不能丟失編碼這件神器。否則你會發(fā)現(xiàn)會很尷尬——會被人稱為“需求翻譯機”

......

這不是心靈雞湯,這是來自靈魂的諫言,我深刻了解到:編碼真的是學(xué)到老活到老的工作。

看到很多優(yōu)秀的同事離職遠(yuǎn)去,通過交流感觸更加深厚

所以,大家一定記得:學(xué)會一個知識要努力應(yīng)用一遍。這樣才能記得牢固;在學(xué)習(xí)中要不求甚解,完全知道這個知識也要知道為什么這么做

......

場景分析

場景1:小文件單文件壓縮

  • 1、原始文件介紹:63.7M、 csv文件 、單個文件
  • 2、對比技術(shù)介紹:網(wǎng)上流傳、使用緩沖區(qū)、使用管道、使用mmp
  • 3、對比結(jié)果展示:

方式1:網(wǎng)上流傳(流傳在坊間的神話,其實是帶刺的玫瑰)

小王剛?cè)肼毑痪?,有一天突然接到需求,要壓縮文件,之前沒寫過,怎么辦?這個時候會在網(wǎng)上搜到這個方法

執(zhí)行結(jié)果(效率很嚇人)

zipMethod=withoutBuffer

costTime=327000ms

代碼如下:

public void zipFileWithoutBuffer(String outFile){
    long beginTime = System.currentTimeMillis();
    File zipFile = new File(outFile);
    File inputFile = new File(INPUT_FILE);
    try(ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile))) {
        try (InputStream inputStream = new FileInputStream(inputFile)){
            zipOutputStream.putNextEntry(new ZipEntry(inputFile.getName()));
            int temp;
            while ((temp = inputStream.read()) != -1){
                zipOutputStream.write(temp);
            }
        }
        printResult(beginTime,"withoutBuffer");
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("error" + e.getMessage());
    } 
}

方式2:使用緩沖區(qū)

小王很開心,提交代碼,翻轉(zhuǎn)了需求狀態(tài),可驗收。

小花是團隊資深技術(shù)達人,走查代碼發(fā)現(xiàn)一臉懵逼:網(wǎng)上搜的?這個會很慢,你再研究研究

小王又換了一種思路,借助緩沖區(qū)BufferedOutputStream

執(zhí)行結(jié)果(快了很多)

zipMethod=withBuffer

costTime=5170ms

代碼如下:

public void zipFileWithBuffer(String outFile){
    long beginTime = System.currentTimeMillis();
    File zipFile = new File(outFile);
    File inputFile = new File(INPUT_FILE);
    try(ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(zipOutputStream)) {
        try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(inputFile))){
            zipOutputStream.putNextEntry(new ZipEntry(inputFile.getName()));
            int temp;
            while ((temp = bufferedInputStream.read()) != -1){
                bufferedOutputStream.write(temp);
            }
        }
        printResult(beginTime,"withBuffer");
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("error" + e.getMessage());
    } 
}

方式3:使用通道

小王懷著忐忑的心情,又一次召集大家走查代碼。

小花:速度要求沒那么高,這樣做已經(jīng)差不多了,代碼可以提交了

其實最近研究kafka,接觸過nio,知曉:nio有種技術(shù)叫通道:Channel

執(zhí)行結(jié)果(好快)

zipMethod=withChannel

costTime=1642ms

代碼如下:

public void zipFileWithChannel(String outFile){
    long beginTime = System.currentTimeMillis();
    File zipFile = new File(outFile);
    File inputFile = new File(INPUT_FILE);
    try(ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));
        WritableByteChannel writableByteChannel = Channels.newChannel(zipOutputStream)) {
        try (FileChannel fileChannel = new FileInputStream(inputFile).getChannel()){
            zipOutputStream.putNextEntry(new ZipEntry(inputFile.getName()));
            fileChannel.transferTo(0,inputFile.length(),writableByteChannel);
        }
        printResult(beginTime,"withChannel");
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("error" + e.getMessage());
    } 
}

方式4:使用mmp

研究kafka過程中,不止知曉nio有種技術(shù)叫通道:Channel,還有種技術(shù)叫mmp

執(zhí)行結(jié)果(好快)

zipMethod=withMmp

costTime=1554ms

代碼如下:

public void zipFileWithMmp(String outFile){
    long beginTime = System.currentTimeMillis();
    File zipFile = new File(outFile);
    File inputFile = new File(INPUT_FILE);
    try(ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile));
        WritableByteChannel writableByteChannel = Channels.newChannel(zipOutputStream)) {
        zipOutputStream.putNextEntry(new ZipEntry(inputFile.getName()));
        MappedByteBuffer mappedByteBuffer = new RandomAccessFile(INPUT_FILE,"r").getChannel()
                .map(FileChannel.MapMode.READ_ONLY,0,inputFile.length());
        writableByteChannel.write(mappedByteBuffer);
        printResult(beginTime,"withMmp");
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("error" + e.getMessage());
    } 
}

場景2:大文件單文件壓縮

  • 1、原始文件介紹:585M、 csv文件 、單個文件
  • 2、對比技術(shù)介紹:使用緩沖區(qū)、使用管道、使用mmp
  • 3、對比結(jié)果展示:
使用緩沖區(qū)使用通道使用mmp
costTime=46034mscostTime=11885mscostTime=10810ms

場景3:大文件多文件壓縮

  • 1、原始文件介紹:585M、 csv文件 、5個文件
  • 2、對比技術(shù)介紹:使用緩沖區(qū)、使用管道、使用mmp
  • 3、對比結(jié)果展示:
使用緩沖區(qū)使用通道使用mmp
costTime=173122mscostTime=53982mscostTime=50543ms

分析結(jié)論

1、對比見下表

壓縮場景網(wǎng)上流傳使用緩沖區(qū)使用通道使用mmp
場景1:小文件單文件壓縮(60M)327000ms5170ms1642ms1554ms
場景2:大文件單文件壓縮(585M)--46034ms11885ms10810ms
場景3:大文件多文件壓縮(5個585M)--173122ms53982ms50543ms
場景4:100K文件單文件壓縮--28ms26ms24ms
場景5:5K文件單文件壓縮 18ms20ms23ms
場景5:1K文件單文件壓縮 15ms21ms24ms

結(jié)論:

  • 1)網(wǎng)上流傳的方法不可取,效率最差
  • 2)使用緩沖區(qū)雖然性能還湊合,但和兩種nio技術(shù)(通道和mmp)相比,還是差了很多,尤其是在中型文件(500M左右)的單文件壓縮和多文件壓縮
  • 中,對比更加明顯
  • 3)通道技術(shù)和mmp技術(shù)對比相差不大,小型文件基本沒影響,大型文件差距也在幾秒之間
  • 4)文件大于10K時,推薦使用通道技術(shù)或者mmp技術(shù)進行文件壓縮
  • 5)文件小于10K時,推薦使用緩沖區(qū)技術(shù)(比兩種nio技術(shù)表現(xiàn)了更好的性能)
  • 6)如果有些團隊在使用api,可以看看其源碼是否使用了nio技術(shù)。如果不是,建議修改為文中方式

另外,操作文件操作時,都可以嘗試使用nio技術(shù),測試下其效率,理論上應(yīng)該都是很可觀的

背后機密

1、網(wǎng)上流傳方法

FileInputStream的read方法如下:

/**
 * Reads a byte of data from this input stream. This method blocks
 * if no input is yet available.
 *
 * @return     the next byte of data, or <code>-1</code> if the end of the
 *             file is reached.
 * @exception  IOException  if an I/O error occurs.
 */public int read() throws IOException {
    return read0();}private native int read0() throws IOException;

這是調(diào)用本地方法與原生操作系統(tǒng)進行交互,從磁盤中讀取數(shù)據(jù)。每讀取一個字節(jié)數(shù)據(jù)就調(diào)用一次這個方法(一次交互很耗時)。

這個方法還是每次讀取一個字節(jié),假如文件很大,這個開銷是巨大的

2、使用緩沖區(qū)

BufferedInputSream read方法如下:

/**
 * See
 * the general contract of the <code>read</code>
 * method of <code>InputStream</code>.
 *
 * @return     the next byte of data, or <code>-1</code> if the end of the
 *             stream is reached.
 * @exception  IOException  if this input stream has been closed by
 *                          invoking its {@link #close()} method,
 *                          or an I/O error occurs.
 * @see        java.io.FilterInputStream#in
 */public synchronized int read() throws IOException {
    if (pos >= count) {
        fill();
        if (pos >= count)
            return -1;
    }
    return getBufIfOpen()[pos++] & 0xff;}

這樣雖然也是一次讀一個字節(jié),但不是每次都從底層讀取數(shù)據(jù),而是一次調(diào)用底層系統(tǒng)讀取了最多buf.length個字節(jié)到buf數(shù)組中,然后從 buf中一次讀一個字節(jié),減少了頻繁調(diào)用底層接口的開銷。

3、使用通道

在復(fù)制大文件時,F(xiàn)ileChannel復(fù)制文件的速度比BufferedInputStream/BufferedOutputStream復(fù)制文件的速度快了近三分之一,體現(xiàn)出FileChannel的速度優(yōu)勢。NIO的Channel的結(jié)構(gòu)更加符合操作系統(tǒng)執(zhí)行I/O的方式,所以其速度相比較于傳統(tǒng)的IO而言速度有了顯著的提高。

操作系統(tǒng)能夠直接傳輸字節(jié)從文件系統(tǒng)緩存到目標(biāo)的Channel中,而不需要實際的copy階段(copy: 從內(nèi)核空間轉(zhuǎn)到用戶空間的一個過程)

4、使用mmp

內(nèi)存映射文件,是把位于硬盤中的文件看做是程序地址空間中一塊區(qū)域?qū)?yīng)的物理存儲器,文件的數(shù)據(jù)就是這塊區(qū)域內(nèi)存中對應(yīng)的數(shù)據(jù),讀寫文件中的數(shù)據(jù),直接對這塊區(qū)域的地址操作,就可以,減少了內(nèi)存復(fù)制的環(huán)節(jié)。所以說,內(nèi)存映射文件比起文件I/O操作,效率要高,而且文件越大,體現(xiàn)出來的差距越大。

到此這篇關(guān)于一文探索Java文件讀寫更高效方式的文章就介紹到這了,更多相關(guān) Java文件讀寫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • web 容器的設(shè)計如何實現(xiàn)

    web 容器的設(shè)計如何實現(xiàn)

    這篇文章主要介紹了web 容器的設(shè)計如何實現(xiàn)的相關(guān)資料,本文旨在介紹如何設(shè)計一個web容器,只探討實現(xiàn)的思路,并不涉及過多的具體實現(xiàn)。把它分解劃分成若干模塊和組件,每個組件模塊負(fù)責(zé)不同的功能,需要的朋友可以參考下
    2016-12-12
  • 深入淺出了解happens-before原則

    深入淺出了解happens-before原則

    一提到happens-before原則,就讓人有點“丈二和尚摸不著頭腦”。這個涵蓋了整個JMM中可見性原則的規(guī)則,究竟如何理解,把我個人一些理解記錄下來。下面可以和小編一起學(xué)習(xí)
    2019-05-05
  • jpa使用manyToOne(opntional=true)踩過的坑及解決

    jpa使用manyToOne(opntional=true)踩過的坑及解決

    這篇文章主要介紹了jpa使用manyToOne(opntional=true)踩過的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • SpringBoot+Redisson自定義注解一次解決重復(fù)提交問題

    SpringBoot+Redisson自定義注解一次解決重復(fù)提交問題

    項目中經(jīng)常會出現(xiàn)重復(fù)提交的問題,本文主要介紹了SpringBoot+Redisson自定義注解一次解決重復(fù)提交問題,具有一定的參考價值,感興趣的可以了解一下
    2024-03-03
  • 最新評論