node.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import * as fs from 'fs';
  2. const node = {};
  3. node.FileStream = class {
  4. constructor(file, start, length, mtime) {
  5. this._file = file;
  6. this._start = start;
  7. this._length = length;
  8. this._position = 0;
  9. this._mtime = mtime;
  10. }
  11. get position() {
  12. return this._position;
  13. }
  14. get length() {
  15. return this._length;
  16. }
  17. stream(length) {
  18. const stream = new node.FileStream(this._file, this._start + this._position, length, this._mtime);
  19. this.skip(length);
  20. return stream;
  21. }
  22. seek(position) {
  23. this._position = position >= 0 ? position : this._length + position;
  24. if (this._position > this._length || this._position < 0) {
  25. throw new Error(`Expected ${this._position - this._length} more bytes. The file might be corrupted. Unexpected end of file.`);
  26. }
  27. }
  28. skip(offset) {
  29. this._position += offset;
  30. if (this._position > this._length || this._position < 0) {
  31. throw new Error(`Expected ${this._position - this._length} more bytes. The file might be corrupted. Unexpected end of file.`);
  32. }
  33. }
  34. peek(length) {
  35. length = length === undefined ? this._length - this._position : length;
  36. if (length < 0x1000000) {
  37. const position = this._fill(length);
  38. this._position -= length;
  39. return this._buffer.subarray(position, position + length);
  40. }
  41. const position = this._position;
  42. this.skip(length);
  43. this.seek(position);
  44. const buffer = new Uint8Array(length);
  45. this._read(buffer, position);
  46. return buffer;
  47. }
  48. read(length) {
  49. length = length === undefined ? this._length - this._position : length;
  50. if (length < 0x10000000) {
  51. const position = this._fill(length);
  52. return this._buffer.slice(position, position + length);
  53. }
  54. const position = this._position;
  55. this.skip(length);
  56. const buffer = new Uint8Array(length);
  57. this._read(buffer, position);
  58. return buffer;
  59. }
  60. _fill(length) {
  61. if (this._position + length > this._length) {
  62. const offset = this._position + length - this._length;
  63. throw new Error(`Expected ${offset} more bytes. The file might be corrupted. Unexpected end of file.`);
  64. }
  65. if (!this._buffer || this._position < this._offset || this._position + length > this._offset + this._buffer.length) {
  66. this._offset = this._position;
  67. const length = Math.min(0x10000000, this._length - this._offset);
  68. if (!this._buffer || length !== this._buffer.length) {
  69. this._buffer = new Uint8Array(length);
  70. }
  71. this._read(this._buffer, this._offset);
  72. }
  73. const position = this._position;
  74. this._position += length;
  75. return position - this._offset;
  76. }
  77. _read(buffer, offset) {
  78. const descriptor = fs.openSync(this._file, 'r');
  79. const stat = fs.statSync(this._file);
  80. if (stat.mtimeMs !== this._mtime) {
  81. throw new Error(`File '${this._file}' last modified time changed.`);
  82. }
  83. try {
  84. fs.readSync(descriptor, buffer, 0, buffer.length, offset + this._start);
  85. } finally {
  86. fs.closeSync(descriptor);
  87. }
  88. }
  89. };
  90. export const FileStream = node.FileStream;