前端js實(shí)現(xiàn)下載文件、讀取上傳文件的內(nèi)容

寫(xiě)在前面

在實(shí)際開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)碰到用戶(hù)要下載或者導(dǎo)出一個(gè)文件的需求絮蒿。傳統(tǒng)的做法是在后端存儲(chǔ)或者即時(shí)生成一個(gè)文件來(lái)提供下載功能,這樣的優(yōu)勢(shì)是可以做權(quán)限控制叁鉴、方便數(shù)據(jù)二次處理土涝,但缺點(diǎn)是需要額外發(fā)起請(qǐng)求、增大服務(wù)端壓力幌墓、下載速度慢但壮。但隨著HTML5的標(biāo)準(zhǔn)發(fā)布,我大前端已經(jīng)完全可以獨(dú)立實(shí)現(xiàn)文件下載與導(dǎo)出啦~

利用a標(biāo)簽的 download 屬性下載文件

download屬性指示瀏覽器下載 URL而不是導(dǎo)航到它常侣,因此將提示用戶(hù)將其保存為本地文件蜡饵。如果屬性有一個(gè)值,那么此值將在下載保存過(guò)程中作為預(yù)填充的文件名(如果用戶(hù)需要胳施,仍然可以更改文件名)溯祸。此屬性對(duì)允許的值沒(méi)有限制,但是 / 和 \ 會(huì)被轉(zhuǎn)換為下劃線(xiàn)舞肆。大多數(shù)文件系統(tǒng)限制了文件名中的標(biāo)點(diǎn)符號(hào)焦辅,故此,瀏覽器將相應(yīng)地調(diào)整建議的文件名胆绊。

<a download="文件名" href="文件地址">下載測(cè)試</a>

需要注意的是:

  1. download 僅適用于同源 URL氨鹏,但是可以使用 blob: URL 和 data: URL。
  2. 如果 HTTP 頭中的 Content-Disposition 屬性賦予了一個(gè)不同于此屬性的文件名压状,HTTP 頭屬性?xún)?yōu)先于此屬性。
  3. 如果 HTTP 頭屬性 Content-Disposition 被設(shè)置為inline 即Content-Disposition='inline'跟继,那么 Firefox 優(yōu)先考慮 HTTP 頭 Content-Disposition download 屬性种冬。

生成Data URLs 并下載文件

Data URL 即前綴為 data: 協(xié)議的URL,其允許內(nèi)容創(chuàng)建者向文檔中嵌入小文件舔糖。它 由四個(gè)部分組成:前綴(data:)娱两、指示數(shù)據(jù)類(lèi)型的MIME類(lèi)型、如果非文本則為可選的base64標(biāo)記金吗、數(shù)據(jù)本身十兢。

data:[<mediatype>][;base64],<data>

mediatype 是個(gè) MIME 類(lèi)型的字符串
例如 "image/jpeg" 表示 JPEG 圖像文件。
如果被省略摇庙,則默認(rèn)值為 text/plain;charset=US-ASCII
如果數(shù)據(jù)是文本類(lèi)型旱物,你可以直接將文本嵌入 
如果是二進(jìn)制數(shù)據(jù),你可以將數(shù)據(jù)進(jìn)行base64編碼之后再進(jìn)行嵌入卫袒。

導(dǎo)出文件代碼示例:

//導(dǎo)出Json文件
exportJson(){
    const downloadData = {
        name:"April",
        ager:"18",
        hobby:"學(xué)習(xí)"
    };
    let dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(downloadData));
    let downloadAnchorNode = document.createElement('a')
    downloadAnchorNode.setAttribute("href", dataStr);
    downloadAnchorNode.setAttribute("download", "文件名.json")
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
},

生成blob: URL 并下載文件

Blob()構(gòu)造函數(shù)返回一個(gè)新的 Blob 對(duì)象宵呛。 blob的內(nèi)容由參數(shù)數(shù)組中給出的值的串聯(lián)組成。

let aBlob = new Blob( array, options );

array 是一個(gè)由ArrayBuffer, ArrayBufferView, Blob, DOMString 等對(duì)象構(gòu)成的 Array 夕凝,或者其他類(lèi)似對(duì)象的混合體宝穗,它將會(huì)被放進(jìn) Blob户秤。DOMStrings會(huì)被編碼為UTF-8。

options 是一個(gè)可選的BlobPropertyBag字典逮矛,它可能會(huì)指定如下兩個(gè)屬性:

  1. type鸡号,默認(rèn)值為 "",它代表了將會(huì)被放入到blob中的數(shù)組內(nèi)容的MIME類(lèi)型须鼎。
  2. endings膜蠢,默認(rèn)值為"transparent",用于指定包含行結(jié)束符\n的字符串如何被寫(xiě)入莉兰。 它是以下兩個(gè)值中的一個(gè): "native"挑围,代表行結(jié)束符會(huì)被更改為適合宿主操作系統(tǒng)文件系統(tǒng)的換行符,或者 "transparent"糖荒,代表會(huì)保持blob中保存的結(jié)束符不變 杉辙。

URL.createObjectURL() 靜態(tài)方法會(huì)創(chuàng)建一個(gè) DOMString,其中包含一個(gè)表示參數(shù)中給出的對(duì)象的URL捶朵。這個(gè) URL 的生命周期和創(chuàng)建它的窗口中的 document 綁定蜘矢。這個(gè)新的URL 對(duì)象表示指定的 File 對(duì)象或 Blob 對(duì)象。

objectURL = URL.createObjectURL(object);

導(dǎo)出文件代碼示例:

exportJson() {
    const downloadData = {
        name: "April",
        ager: "18",
        hobby: "學(xué)習(xí)"
    };
                
    let blob = new Blob(
        [JSON.stringify(downloadData, null, 2)],
        {type: 'application/json'});
    let url = URL.createObjectURL(blob);
    let downloadAnchorNode = document.createElement('a')
    downloadAnchorNode.setAttribute("href", url);
    downloadAnchorNode.setAttribute("download", "文件名.json")
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
 }

讀取上傳文件的數(shù)據(jù)

想要讀取Blob數(shù)據(jù)的唯一方法是FileReader综看。
FileReader 對(duì)象允許Web應(yīng)用程序異步讀取存儲(chǔ)在用戶(hù)計(jì)算機(jī)上的文件(或原始數(shù)據(jù)緩沖區(qū))的內(nèi)容品腹,使用 FileBlob 對(duì)象指定要讀取的文件或數(shù)據(jù)。

其中File對(duì)象可以是來(lái)自用戶(hù)在一個(gè)<input>元素上選擇文件后返回的FileList對(duì)象,也可以來(lái)自拖放操作生成的 DataTransfer對(duì)象,還可以是來(lái)自在一個(gè)HTMLCanvasElement上執(zhí)行mozGetAsFile()方法后返回結(jié)果红碑。

包含5個(gè)方法:

  1. FileReader.abort()
    中止讀取操作舞吭。在返回時(shí)蛋辈,readyState屬性為DONE轻专。

  2. FileReader.readAsArrayBuffer()
    開(kāi)始讀取指定的 Blob中的內(nèi)容, 一旦完成, result 屬性中保存的將是被讀取文件的 ArrayBuffer 數(shù)據(jù)對(duì)象.

  3. FileReader.readAsBinaryString()
    開(kāi)始讀取指定的Blob中的內(nèi)容根暑。一旦完成串稀,result屬性中將包含所讀取文件的原始二進(jìn)制數(shù)據(jù)襟诸。

  4. FileReader.readAsDataURL()
    開(kāi)始讀取指定的Blob中的內(nèi)容煞躬。一旦完成瑟蜈,result屬性中將包含一個(gè)data: URL格式的字符串以表示所讀取文件的內(nèi)容爽哎。

  5. FileReader.readAsText()
    開(kāi)始讀取指定的Blob中的內(nèi)容奕剃。一旦完成衷旅,result屬性中將包含一個(gè)字符串以表示所讀取的文件內(nèi)容。

將上傳的文件讀取為字符串的代碼示例

handleUpload(blob) {
    // 新建一個(gè)FileReader
    const reader = new FileReader()
    // 讀取文件
    reader.readAsText(blob, "UTF-8")
    // 讀取完文件之后會(huì)回來(lái)這里
    reader.onload = function (e) {
        // 讀取文件內(nèi)容
        const fileString = e.target.result
        // 接下來(lái)可對(duì)文件內(nèi)容進(jìn)行處理
        const myData = JSON.parse(fileString);
        console.log(myData) // 打印讀取到的內(nèi)容
     }
},

將上傳的文件讀取為URL格式的字符串的代碼示例

handleUpload(file) {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function (e) {
        const urlStr = reader.result
        console.log(urlStr)
    }

點(diǎn)擊下載圖片

雖然目前瀏覽器都支持保存圖片到本地的功能(右鍵>圖片另存為)但是實(shí)際開(kāi)發(fā)中會(huì)涉及到批量下載圖片纵朋、Canvas繪圖的保存功能柿顶,應(yīng)運(yùn)上面的知識(shí),我大前端也可以輕松實(shí)現(xiàn)倡蝙。代碼如下:

 <button @click="downloadImg">下載圖片</button>
// 通過(guò)src獲取圖片的blob對(duì)象
getImageBlob(url, cb) {
    let xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.responseType = "blob";
    xhr.onload = function () {
        if (this.status == 200) {
            cb(this.response);
        }
    };
    xhr.send();
},
// 點(diǎn)擊下載圖片
downloadImg(){
    let reader = new FileReader();
    this.getImageBlob('https://b-gold-cdn.xitu.io/v3/static/img/simplify-logo.3e3c253.svg', function(blob){
        // 讀取來(lái)看下下載的內(nèi)容 最終生成的字符串
        reader.readAsDataURL(blob);
        // 生成下載用的URL對(duì)象
        let url = URL.createObjectURL(blob);
        // 生成一個(gè)a標(biāo)簽九串,并模擬點(diǎn)擊,即可下載,批量下載同理
        let downloadAnchorNode = document.createElement('a')
        downloadAnchorNode.setAttribute("href", url);
        downloadAnchorNode.setAttribute("download", "下載圖片")
        downloadAnchorNode.click();
        downloadAnchorNode.remove();
    })
},
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末猪钮,一起剝皮案震驚了整個(gè)濱河市品山,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烤低,老刑警劉巖肘交,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異扑馁,居然都是意外死亡涯呻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)腻要,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)复罐,“玉大人,你說(shuō)我怎么就攤上這事雄家⌒ё纾” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵趟济,是天一觀的道長(zhǎng)乱投。 經(jīng)常有香客問(wèn)我,道長(zhǎng)顷编,這世上最難降的妖魔是什么戚炫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮媳纬,結(jié)果婚禮上双肤,老公的妹妹穿的比我還像新娘。我一直安慰自己层宫,他們只是感情好杨伙,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著萌腿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抖苦。 梳的紋絲不亂的頭發(fā)上毁菱,一...
    開(kāi)封第一講書(shū)人閱讀 49,842評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音锌历,去河邊找鬼贮庞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛究西,可吹牛的內(nèi)容都是我干的窗慎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼遮斥!你這毒婦竟也來(lái)了峦失?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤术吗,失蹤者是張志新(化名)和其女友劉穎尉辑,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體较屿,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隧魄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了隘蝎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片购啄。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嘱么,靈堂內(nèi)的尸體忽然破棺而出狮含,到底是詐尸還是另有隱情,我是刑警寧澤拱撵,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布辉川,位于F島的核電站,受9級(jí)特大地震影響拴测,放射性物質(zhì)發(fā)生泄漏乓旗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一集索、第九天 我趴在偏房一處隱蔽的房頂上張望屿愚。 院中可真熱鬧,春花似錦务荆、人聲如沸妆距。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)娱据。三九已至,卻和暖如春盅惜,著一層夾襖步出監(jiān)牢的瞬間中剩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工抒寂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留结啼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓屈芜,卻偏偏與公主長(zhǎng)得像郊愧,于是被迫代替她去往敵國(guó)和親朴译。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容