javascript 實(shí)現(xiàn)分段讀取大文件

前些時(shí)候在用FileReader讀取文件的時(shí)候, 發(fā)現(xiàn)一個(gè)問題陨晶,如果文件過大不僅耗費(fèi)內(nèi)存猬仁,甚至?xí)x不出來帝璧,于是一時(shí)興起寫了一個(gè)可以同時(shí)讀取多個(gè)文件且在不考慮外部因素下不沒有文件大小上限的API

核心還是借助FileReader對象,具體實(shí)現(xiàn)細(xì)節(jié)如下

實(shí)現(xiàn)同時(shí)讀取多個(gè)文件

針對不同的文件建立獨(dú)立的FileReader對象并用一個(gè)數(shù)組臨時(shí)緩存湿刽,沒什么難度

實(shí)現(xiàn)分段讀取文件

要借助Blob對象的Slice方法的烁,將文件分成多個(gè)段進(jìn)行讀取,并且在FileReader讀取成功的 onload事件中處理開始讀取下一段文件诈闺。

slice 由于同瀏覽器的用法不一樣渴庆,寫了一個(gè)BlobSlice函數(shù)來統(tǒng)一處理

function blobSlice(blob, start, length) {
        if(blob.slice) {
            return blob.slice(start, length);
        } else if (blob.webkitSlice) {
            return blob.webkitSlice(start, length);
        } else if (blob.mozSlice) {
            return blob.mozSlice(start, length);
        } else {
            return null;
        }
    }

并且需要建立一個(gè)初始化FileReader的函數(shù),用來綁定onload事件雅镊,并記錄讀取的文件段的起始點(diǎn)襟雷,每讀取一段之后都進(jìn)行判斷確認(rèn)是否要讀下一段,或是已經(jīng)讀取完畢仁烹。同時(shí)耸弄,在這個(gè)事件中用傳入的回調(diào)函數(shù)處理都出來的數(shù)據(jù)

    initReader(type, index, step, file, callback) {
        var start = 0,
            Reader = this, 

            resolveProcess = function (event) {
                Reader.loadedMap[index] = step * start * 1024 + event.loaded;
                Reader.loaded = 0;
                Reader.loadedMap.forEach(function (loaded) {
                    Reader.loaded += loaded;
                }, this);
                Reader.allProgress[index] = (Reader.loadedMap[index] / Reader.sizeMap[index] * 100).toFixed(2);
                Reader.progress = Reader.progressBar.value = (Reader.loaded / Reader.total * 100).toFixed(2);
                console.log("total: "+Reader.total);
                console.log("loaded: "+Reader.loaded);
                console.log(index+": "+Reader.allProgress[index]+"%");
                console.log("\n");
            }, 

            readBlob = function (type, index, step, file) {
                var blob = Reader.blobSlice(file, start * step * 1024, (start + 1) * step * 1024);
                if (type === Reader.READ_AS_TEXT) {
                    Reader.reader[index].readAsText(blob);
                }
                else if (type === Reader.READ_AS_BINARY_STRING) {
                    Reader.reader[index].readAsBinaryString(blob);
                }
                else if (type === Reader.READ_AS_ARRAY_BUFFER) {
                    Reader.reader[index].readAsArrayBuffer(blob);
                }
            };

        Reader.reader[index].onload = function(event) {

            //process every line of the read content if it's text
            if (type === this.READ_AS_TEXT) {
                var view = event.target.result,
                    charCount = 0;
                for (var i = 0; i < view.length; ++i) {
                    if (view[i] === '\n' || view[i] === '\r' || i === view.length - 1) {
                        callback(view.slice(charCount, i));
                        charCount = i;
                    }
                }
            } else {
                callback(event.target.result);
            }

            resolveProcess(event);
            if (step === 0) {
                return;
            }

            if (Reader.loadedMap[index] < Reader.sizeMap[index]) {
                start++
            } else {
                delete Reader.reader[index];
                Reader.fileCount--;
                return;
            }

            readBlob(type, index, step, file);
        };

        Reader.reader[index].onprogress = function(event) {
            resolveProcess(event);
        };
    }

在init函數(shù)中保存了一個(gè)start變量,利用閉包封裝到onload中卓缰,每次讀取之后判斷已經(jīng)讀取的字節(jié)是否大于等于文件大小计呈,如果不是則加一,并在下次讀取的時(shí)候分割出新的段進(jìn)行讀取征唬。如果讀取完畢捌显,則將該FileReader從緩存中去掉。

至于怎么判斷已經(jīng)讀取的字節(jié)數(shù)鳍鸵,這部分代碼放在了處理文件讀取的進(jìn)度上苇瓣。

在讀取純文本的時(shí)候利用 \n 和 \r 判斷是否處在行尾,這樣來分割出一行進(jìn)行處理

實(shí)現(xiàn)進(jìn)度處理

在進(jìn)度處理上主要利用了onload 和 onprogress 兩個(gè)事件偿乖,用一個(gè)數(shù)組保存各個(gè)文件的大小,同時(shí)用另一個(gè)數(shù)組保存每個(gè)文件讀取出的字節(jié)數(shù)哲嘲。

resolveProcess = function (event) {
                Reader.loadedMap[index] = step * start * 1024 + event.loaded;
                Reader.loaded = 0;
                Reader.loadedMap.forEach(function (loaded) {
                    Reader.loaded += loaded;
                }, this);
                Reader.allProgress[index] = (Reader.loadedMap[index] / Reader.sizeMap[index] * 100).toFixed(2);
                Reader.progress = Reader.progressBar.value = (Reader.loaded / Reader.total * 100).toFixed(2);
                console.log("total: "+Reader.total);
                console.log("loaded: "+Reader.loaded);
                console.log(index+": "+Reader.allProgress[index]+"%");
                console.log("\n");
            }

event 就是傳入該函數(shù)的load 和 progress 事件贪薪,至于這段代碼中的progressBar,是封裝在這個(gè)API中的一個(gè)html5 的progress 元素眠副,用來動態(tài)顯示所有文件讀取的進(jìn)度画切。

github

https://github.com/sallerli1/fileReader-js

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市囱怕,隨后出現(xiàn)的幾起案子霍弹,更是在濱河造成了極大的恐慌,老刑警劉巖娃弓,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件典格,死亡現(xiàn)場離奇詭異,居然都是意外死亡台丛,警方通過查閱死者的電腦和手機(jī)耍缴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人防嗡,你說我怎么就攤上這事变汪。” “怎么了蚁趁?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵裙盾,是天一觀的道長。 經(jīng)常有香客問我他嫡,道長番官,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任涮瞻,我火速辦了婚禮鲤拿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘署咽。我一直安慰自己近顷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布宁否。 她就那樣靜靜地躺著窒升,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慕匠。 梳的紋絲不亂的頭發(fā)上饱须,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天,我揣著相機(jī)與錄音台谊,去河邊找鬼蓉媳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛锅铅,可吹牛的內(nèi)容都是我干的酪呻。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼盐须,長吁一口氣:“原來是場噩夢啊……” “哼玩荠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起贼邓,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤阶冈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后塑径,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體女坑,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年晓勇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了堂飞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灌旧。...
    茶點(diǎn)故事閱讀 38,625評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绰筛,靈堂內(nèi)的尸體忽然破棺而出枢泰,到底是詐尸還是另有隱情,我是刑警寧澤铝噩,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布衡蚂,位于F島的核電站,受9級特大地震影響骏庸,放射性物質(zhì)發(fā)生泄漏毛甲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一具被、第九天 我趴在偏房一處隱蔽的房頂上張望玻募。 院中可真熱鬧,春花似錦一姿、人聲如沸七咧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艾栋。三九已至,卻和暖如春蛉顽,著一層夾襖步出監(jiān)牢的瞬間蝗砾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工携冤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悼粮,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓曾棕,卻偏偏與公主長得像矮锈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子睁蕾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評論 2 348

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