nodejsはexcelをエクスポートして実戦になります.


私達はすべてnodejsのメモリがv 8メモリの分配の構造の原因のためとても有限なことを知っています.
64ビットのシステムも1.4 Gぐらいしか占められませんので、大きなファイルを生成したり読み取ったりするとメモリの締め付けが私たちに大きな悩みをもたらします.このような状況に遭遇したNodeは私たちに良い解決方法をくれました.
簡単な理解は下品です.
ストリームはデータのセットです.配列や文字列のようです.違いは、ストリーム中のデータはすぐにすべて利用できないかもしれません.そして、これらのデータを一括してメモリに入れる必要はありません.これは、大量のデータを操作したり、外部ソースからセグメント毎にデータを送ったりする時に流れが非常に有用になる.
パイプラインとストリームの結合はlinuxに多く使われており、streamの複数の命令によって複雑な機能を実現することができます.実は簡単に言えば、pipeは私達が一気に食べたいものを何回かの量に分けて食べていきます.食べ合わせを避けるために、食べながら食べてもいいです.私達の体に低負荷の状態を保つことができます.同時に、nodeプロセスのメモリがあまりきつくないことを保証します.
nodejs中の流れ
先天的な原因のため、流れはnodeの中で通常私達に用いられて大きいファイルを処理して、甚だしきに至ってはnodejsの各種のモジュールの中ですべてstreamを採用しました.
  • は、serverにおけるstreamが読み取り可能なストリームであり(http request)、Readable Streamは書き込み可能なストリームであり(http response)、つまり、なぜ私たちは常にrequestでclientの戻り値を読み取り、reponseを介してデータに書き込まれた
  • に戻るのか?
  • fsは、読み書き可能なストリームであり(Writable Stream)、1つのファイルを書き込みおよび読み出しする動作
  • である.
    これらのモジュールはnodejsにおけるストリームアプリケーションの一部のシーンにすぎず、その公式APIにおけるストリームのタイプと解釈は、
  • Duplex Stream-strems from which data can be read(for example fs.create ReadStream).
  • Readable-strems to which data can be written(for example fs.create WriteStream).
  • Writable-strems that are both Readable and Writable(for example net.Socket)
  • Duplex-Duplex steams that can modify or transform the data as it is written and read(for example zlib.create Deflate).
  • そうです.つまり、4つのタイプです.中にはtranformはduplexから継承されています.
    流れの典型例
    nodejsで大ファイルを読み込み、書き込みするのは、一般的に流れが最も広く、最も重要なシーンの一つです.これもこのブログを書く原因の一つです.ですから、簡単なファイル読み取りの例として、流れを知る小さなDemoさんを紹介します.
    サイズ160 Mのファイルを読み込み、fs.readFile()を使用します.
    const fs = require('fs')
    const server = require('http').createServer()
    
    server.on('request', (req, res) => {
      fs.readFile('./Demo.txt', (err, result)=>{
        if(err){
          throw err
        }
        res.end(result)
      })
    })
    
    server.listen(3000)
    このようなnodeプロセスを起動して、メモリの占有率は約8 mです.実行要求Transformを実行すると、メモリが160 mに急増しています.ほとんどは私たちが読み込んだファイルのサイズです.
    ストリーム読み出し方式を採用する
    const fs = require('fs')
    const server = require('http').createServer()
    
    server.on('request', (req, res) => {
      let data = fs.createReadStream('./Demo.txt')
      data.pipe(res)
    })
    
    server.listen(3000)
    
    メモリは基本的に11 mで安定していることが見られます.これは読み取りフローを使ってメモリに大きな最適化をもたらしていることを証明しています.もちろん、これは小さなDemoにすぎません.1 Gでも2 G以上のファイルを読み込むことができます.fs.readFile()の方式はメモリの制限を突破することができて、過程のcrashを招いて落ちるかもしれなくて、もし生産環境の中で、多く同時に比較的に高い環境を求めるならば、このような方式は通用しません.
    流れでExcelファイルをエクスポートします.
    背景
    必要なのは、プロジェクト下のすべてのグループを一つのプロジェクトエクセルファイルに複数のグループsheetを含めてエクスポートすることができることです.
    csvファイルをエクスポートするなら、完全に流れでエクスポートできますが、excelでは、ファイルタイプの制限のため、excelを流れによって直接エクスポートするのは難しいです.最終的にexcel jsを選択しました.
    コーディングフォーマット
  • node.jsはcurl localhost:3000asciiutf8base64符号化方式をサポートしています.binaryフォーマットはサポートされていません.マイクロソフトはutf 8にBOMヘッドを追加しました.このため、excelは中国語で文字化けが発生しますので、ファイルの先頭に3つの識別バイトを追加する必要があります.utf 8対応のBOMはutf-8 + BOM( )転送ゲートですので、このように実現します.
  • がexcelファイルをエクスポートする以上、ファイルの内容(Content-Type)は何ですか?最終的にStock Overflowで答えを見つけました.転送ゲートStock Overflow、ファイルのタイプは専用のOfficeセットがあります.EF BB BF
  • 実現する
    excerjsを使う一番重要な原因は偽流を支持することです.
    The interface to the streaming workbook and worksheet is almost the same as the document versions with a few minor practical differences:
  • Once a worksheet is added to a workbook,it cannot be removed.
  • Once a row is comitted,it isのlonger accessible since it will have been dropped from the worksheet.
  • unMerge Cels()is not supported.
  • 文書の説明から、excel jsは各sheetをexcel documentに書き込むことをサポートしています.そして、直ちにpipeを出します.これは比較的実行可能な方案です.しかし、sheetごとのデータ量が大きすぎたらどうすればいいですか?同様に私達のメモリの増加を招きます.ソースも確かにexcerjs Streamを実現しました.だから、これは疑似ストリームです.解決していません.根本的な問題ですが、問題の根本的な原因はやはりexcelの中で区別しなければなりません.sheetを続けて読むことができなくなりました.やはりこの部分のデータを先にメモリに読み取って書き込む必要があります.これは業務コードにデータ量の制限を加える必要があります.個sheet
    一部コード、Demo.co.ffee
    res.set('Content-Type','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
    
    res.setHeader('Content-Disposition', filename)
    res.set('Set-Cookie', 'fileDownload=true; path=/')
    
    excel = require('exceljs')
    
    options = {
        stream: res,
        useStyles: true,
        useSharedStrings: true
    }
    
    workbook = new excel.stream.xlsx.WorkbookWriter(options)
    
    worksheet = workbook.addWorksheet(tasklist.title)
    headers = [
      { header: 'csv.content', width: 15 }
      { header: 'csv.ancestor', width: 10 }
      { header: 'csv.note',  width: 20 }
      { header: 'csv.priority', width: 10 }
      { header: 'csv.executor', width: 10 }
      { header: 'csv.startDate', width: 20 }
      { header: 'csv.dueDate', width: 20 }
      { header: 'csv.creator', width: 20 }
      { header: 'csv.created', width: 20 }
      { header: 'csv.isDone', width: 10 }
      { header: 'csv.accomplished', width: 20 }
      { header: 'csv.tasklist', width: 10 }
      { header: 'csv.stage', width: 10 }
      { header: 'csv.delayDays', width: 10 }
      { header: 'csv.delayed', width: 10 }
      { header: 'csv.totaltime', width: 10 }
      { header: 'csv.usedtime', width: 10 }
      { header: 'csv.tag', width: 10 }
    ]
    
    //      
    worksheet.columns = headers
    
    rows = [
        [5,'Bob',new Date()], // row by array
        {id:6, name: 'Barbara', dob: new Date()}
    ]
    worksheet.addRows rows
    
    worksheet.commit()
    workbook.commit()
    
    締め括りをつける
    excelをエクスポートするには、res.write(Buffer.from('\xEF\xBB\xBF', 'binary'))の小さなパフォーマンスとアプリケーションだけで、実際には、背景とシーンのアプリケーション全体を把握するためには、まだ私たちの実践とソースの実装を確認する必要があります.私たちが持ってきた性能の最適化と簡便さは、以上の通りです.