まず、先週jParserのドキュメントを翻訳した後(jParserを使用して

したがって、例は二重になります。 JAM形式で保存されたFidonet電子メールメッセージのヘッダーの分析に注目します。 この形式は、遠い昔からフィドネットで人気がありました
JAMのドキュメントはさまざまなBBSファイドで簡単に見つけることができますが、BBSは時間の経過とともに住所を閉鎖または変更する傾向があるため、信頼性のために、5年前に自分の手紙を参照します。 (チェコのBBSは、その後私のソースとして使用されていましたが、すでに閉鎖されています。この世界のすべてが荒れ狂っています。)
ご覧のとおり、Fidonetの
もう1つの重要な状況はあまり目立ちません。JHR
したがって
var fs = require('fs'); var jParser = require('jParser'); var ulong = 'uint32'; var ushort = 'uint16'; var JAM = function(echotag){ if (!(this instanceof JAM)) return new JAM(echotag); this.echotag = echotag; // Buffers: this.JHR = null; /* this.JDT = null; this.JDX = null; this.JLR = null; */ } JAM.prototype.readJHR = function(callback){ // (err) if (this.JHR !== null) callback(null); fs.readFile(this.echotag+'.JHR', function (err, data) { if (err) callback(err); this.JHR = data; callback(null); }); } JAM.prototype.ReadHeaders = function(callback){ // err, struct this.readJHR(function(err){ if (err) callback(err); var thisJAM = this; var parser = new jParser(this.JHR, { 'reserved1000uchar': function(){ this.skip(1000); return true; }, 'JAM0' : ['string', 4], 'FixedHeaderInfoStruct': { 'Signature': 'JAM0', 'datecreated': ulong, 'modcounter': ulong, 'activemsgs': ulong, 'passwordcrc': ulong, 'basemsgnum': ulong, 'RESERVED': 'reserved1000uchar', }, 'SubField': { 'LoID': ushort, 'HiID': ushort, 'datlen': ulong, 'Buffer': ['string', function(){ return this.current.datlen }] /* 'type': function(){ switch( this.current.LoID ){ case 0: return 'OADDRESS'; break; case 1: return 'DADDRESS'; break; case 2: return 'SENDERNAME'; break; case 3: return 'RECEIVERNAME'; break; case 4: return 'MSGID'; break; case 5: return 'REPLYID'; break; case 6: return 'SUBJECT'; break; case 7: return 'PID'; break; case 8: return 'TRACE'; break; case 9: return 'ENCLOSEDFILE'; break; case 10: return 'ENCLOSEDFILEWALIAS'; break; case 11: return 'ENCLOSEDFREQ'; break; case 12: return 'ENCLOSEDFILEWCARD'; break; case 13: return 'ENCLOSEDINDIRECTFILE'; break; case 1000: return 'EMBINDAT'; break; case 2000: return 'FTSKLUDGE'; break; case 2001: return 'SEENBY2D'; break; case 2002: return 'PATH2D'; break; case 2003: return 'FLAGS'; break; case 2004: return 'TZUTCINFO'; break; default: return 'UNKNOWN'; break; } } */ }, 'MessageHeader': { 'Signature': 'JAM0', 'Revision': ushort, 'ReservedWord': ushort, 'SubfieldLen': ulong, 'TimesRead': ulong, 'MSGIDcrc': ulong, 'REPLYcrc': ulong, 'ReplyTo': ulong, 'Reply1st': ulong, 'Replynext': ulong, 'DateWritten': ulong, 'DateReceived': ulong, 'DateProcessed': ulong, 'MessageNumber': ulong, 'Attribute': ulong, 'Attribute2': ulong, 'Offset': ulong, 'TxtLen': ulong, 'PasswordCRC': ulong, 'Cost': ulong, 'Subfields': ['string', function(){ return this.current.SubfieldLen; } ], /* 'Subfields': function(){ var final = this.tell() + this.current.SubfieldLen; var sfArray = []; while (this.tell() < final) { sfArray.push( this.parse('SubField') ); } return sfArray; }, */ 'AfterSubfields': function(){ var initial = this.tell(); var bytesLeft = thisJAM.JHR.length - initial - 4; var seekJump = 0; var sigFound = false; var raw = this; if (bytesLeft <= 0) return 0; do { this.seek(initial + seekJump, function(){ var moveSIG = raw.parse('JAM0'); if (moveSIG === 'JAM\0') { sigFound = true; /* if (seekJump > 0){ console.log( 'initial = ' + initial + ', seekJump = ' + seekJump + ', moveSIG = ' + moveSIG ); } */ } }); seekJump++; } while (!sigFound && (seekJump < bytesLeft) ); this.skip(seekJump-1); return seekJump-1; } }, 'JHR': { 'FixedHeader': 'FixedHeaderInfoStruct', 'MessageHeaders': function(){ var mhArray = []; while (this.tell() < thisJAM.JHR.length - 69) { mhArray.push( this.parse('MessageHeader') ); } return mhArray; } } }); callback(null, parser.parse('JHR')); }); } module.exports = JAM;
このスケッチは、エクスポートされたJAMオブジェクト(
JAMドキュメントのデータ型(たとえば
SubField構造体の説明には、コメント化された
MessageHeader構造内のSubfieldsフィールドは、2つの方法で定義されます。 最初の(高速)は、このフィールドをサイズSubfieldLenのバイト文字列として読み取ります。 2番目の(コメントアウト)は、このフィールドを完全に処理し、jParserを使用してサブフィールドを分離します。モジュールを使用するアプリケーションがフィードのヘッダーの可変部分のメタデータを必要とする場合、長いボックスで分析を延期します。
AfterSubfieldsフィールドには、3バイトの
JHR構造体のMessageHeadersフィールドの説明の数字69は「魔法」です。 その目標は、分析がファイルの終わりに近づきすぎないようにすることです。ファイルの終わりでは、ガベージデータも予想されます。
このテストスクリプトを使用して分析の速度を確認しました。
var JAM = require('../'); var util = require('util'); console.log( new Date().toLocaleString() ); var blog = JAM('blog-MtW'); blog.ReadHeaders(function(err,data){ if (err) throw err; //console.log( util.inspect(data, false, Infinity, false) ); console.log( new Date().toLocaleString() ); });
スクリプトはテストサブディレクトリにあるため、最初の行では親ディレクトリを使用します
シングルコアPentium IV(2.2 GHz)でテストを実行すると、ヘッダーが
Fidonetサイトでは、このようなエコー会議が100を超えることがあり、電子メールヘッダーの合計分析時間は数分になるため、これは1つのエコー会議にとっては多くのことです。

作業の開始時のGoldEDがファイル全体を高速化するのではなく、1つのヘッダー構造FixedHeaderInfoStructのみを疑うのは皮肉なままです(エコー会議のメッセージ数を表示するにはデータが十分であり、作業の開始時にはGoldED
私のモジュール(JAMヘッダーのリーダー )のコードを無料のMITライセンスの下でGithubに投稿しました。