首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Node.js中,如何在不添加字节的情况下更改(覆盖)二进制文件中的字节

问在Node.js中,如何在不添加字节的情况下更改(覆盖)二进制文件中的字节
EN

Stack Overflow用户
提问于 2018-12-18 01:30:25
回答 2查看 546关注 0票数 2

在Node.js中,如何更改(覆盖)二进制文件中的一个字节(在某个偏移量上),而不增加其间的字节和更改其长度?

在C语言中,我只需使用"r+“对文件执行fopen(),将fseek()设置为我想要更改的偏移量,然后用fwrite()覆盖字节。Node.js中的等价物看起来会是什么样子?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-30 01:43:26

好的,我发现这其实很简单^^

代码语言:javascript
复制
fs.open(filename, "r+", (err, fd) => {
    if(!err) {
        fs.write(
            fd, new Uint8Array([byte]), 0, 1, offset,
            (err, bw, buf) => {
                if(!err) {
                    // succesfully wrote byte to offset
                }
            }
        );
    }
});
票数 2
EN

Stack Overflow用户

发布于 2018-12-18 03:21:15

我不得不像你最近描述的那样做一些事情。我不得不在不改变大小的情况下更新可执行文件中的URL。关键是在流上使用Transform。其思想是,转换将读入和写出您想要的确切数据,并且只修改您指定的字节。

这是一个在流中执行查找和替换的Transform类。构造函数接受应该被替换的块的起始和结束字节序列的参数。还有一个padValue参数用于保持相同的大小。

代码语言:javascript
复制
import { Transform } from 'stream'

export default class FindAndReplaceTransform extends Transform {
  constructor(startBuffer, endBuffer, replacementValueBuffer, padValue, options) {
    super(options);
    this.startBuffer = startBuffer;
    this.endBuffer = endBuffer;
    this.replacementValueBuffer = replacementValueBuffer;
    this.padValue = padValue;
  }

  _findInBuffer(sourceBuffer, searchBuffer) {
    let searchFound = -1;
    let lengthOfPartialMatch = 0;
    for (let i = 0; i < sourceBuffer.length; i++) {
      for (let j = 0; j < searchBuffer.length; j++) {
        if (i + j >= sourceBuffer.length) {
          if (j > 0) {
            lengthOfPartialMatch = j;
          }
          break;
        }
        if (sourceBuffer[i + j] !== searchBuffer[j]) {
          break;
        }
        if (j === searchBuffer.length - 1) {
          searchFound = i;
        }
      }
      if (searchFound >= 0 || lengthOfPartialMatch > 0) {
        break;
      }
    }
    return { searchFound, lengthOfPartialMatch };
  }

  _doReplacement(length) {
    let replacementValueBuffer = this.replacementValueBuffer;
    if (this.padValue !== undefined) {
      replacementValueBuffer = Buffer.concat([replacementValueBuffer, Buffer.alloc(length - replacementValueBuffer.length, this.padValue)], length);
    }
    this.push(replacementValueBuffer);
  }

  //override
  _transform(data, encoding, done) {
    if(this.lengthOfPartialStartMatch){
      data = Buffer.concat([this.startBuffer.slice(0, this.lengthOfPartialStartMatch), data], this.lengthOfPartialStartMatch + data.length);
      delete this.lengthOfPartialStartMatch;
    }
    if(this.lengthOfPartialEndMatch){
      data = Buffer.concat([this.endBuffer.slice(0, this.lengthOfPartialEndMatch), data], this.lengthOfPartialEndMatch + data.length);
      this.replacementBuffer = this.replacementBuffer.slice(0, this.replacementBuffer.length - this.lengthOfPartialEndMatch);
      delete this.lengthOfPartialEndMatch;
    }

    let startAlreadyFound = !!this.replacementBuffer
    let { searchFound: startIndex, lengthOfPartialMatch: lengthOfPartialStartMatch } = this._findInBuffer(data, this.startBuffer);
    let tail = data.slice(startIndex >= 0 && !startAlreadyFound ? startIndex : 0);
    let { searchFound: endIndex, lengthOfPartialMatch: lengthOfPartialEndMatch } = this._findInBuffer(tail, this.endBuffer);


    if (!startAlreadyFound && startIndex >= 0) {
      this.push(data.slice(0, startIndex))
      this.replacementBuffer = Buffer.alloc(0);
      startAlreadyFound = true;
    }
    if (startAlreadyFound) {
      if (endIndex >= 0) {
        let replacementLength = this.replacementBuffer.length + endIndex + this.endBuffer.length;
        this._doReplacement(replacementLength);
        delete this.replacementBuffer;
        if (endIndex + this.endBuffer.length < tail.length) {
          let remainder = tail.slice(endIndex + this.endBuffer.length)
          this._transform(remainder, encoding, done);
          return;
        }
      } else {
        this.lengthOfPartialEndMatch = lengthOfPartialEndMatch;
        this.replacementBuffer = Buffer.concat([this.replacementBuffer, tail], this.replacementBuffer.length + tail.length);
      }
    } else {
      this.lengthOfPartialStartMatch = lengthOfPartialStartMatch;
      this.push(data.slice(0, data.length - lengthOfPartialStartMatch))
    }
    done();
  }

  //override
  _flush(done) {
    if (this.replacementBuffer) {
      this.push(this.replacementBuffer)
    }
    if(this.lengthOfPartialStartMatch){
      this.push(this.startBuffer.slice(0, this.lengthOfPartialStartMatch));
    }
    delete this.replacementBuffer;
    delete this.lengthOfPartialStartMatch;
    delete this.lengthOfPartialEndMatch;
    done()
  }
}

要使用上面的转换,您可以执行如下操作:

代码语言:javascript
复制
let stream = fs.createReadStream(inputFile);
let padding = 0x00;
let startSequence = Buffer.from('${', 'utf16le');
let endSequence = Buffer.from('}', 'utf16le');
let transform = new FindAndReplaceTransform(startSequence, endSequence, Buffer.from(replacementValue, 'utf16le'), paddingValue);
stream = stream.pipe(transform);
stream.pipe(fs.createWriteStream(outputFile));

显然,如果您所要做的只是更改某个偏移量处的字节,那么Transform类将会简单得多。我提供了上面的代码,因为我有它,如果你想做一些更复杂的事情,你可以参考它。

您希望确保实现的主要方法是_transform方法。您可能还需要根据您的实现来实现_flush方法。上面代码中的其他类方法用于我的替换代码实现,不需要转换工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53820283

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档