【问题标题】:Node.js delete first N bytes from a fileNode.js 从文件中删除前 N 个字节
【发布时间】:2020-12-25 20:00:30
【问题描述】:

如何在不加载到内存的情况下从二进制文件的开头删除(删除|修剪)N个字节?

我们有fs.ftruncate(fd, len, callback),它会从文件末尾删除字节(如果文件更大)。

如何在Node.js中从头开始剪切字节,或者从头开始修剪而不读取内存中的文件?

我需要truncateFromBeggining(fd, len, callback)removeBytes(fd, 0, N, callback) 之类的东西。

如果不可能,用文件流最快的方法是什么?

在大多数文件系统上,您不能从文件的开头或中间“剪切”一部分,您只能在末尾截断它。

考虑到上述情况,我想,我们可能必须打开输入文件流,在第 N 个字节之后寻找,并将其余字节寻找到 pipe 到输出文件流。

【问题讨论】:

    标签: node.js file filestream truncate


    【解决方案1】:

    您要求的是操作系统文件系统操作:能够从文件开头删除一些字节,而无需重写文件。

    您要求的文件系统操作不存在,至少在 Linux / FreeBSD / MacOS / Windows 中是这样。

    如果您的程序是文件的唯一用户并且它适合 RAM,那么最好的办法是将整个内容读入 RAM,然后重新打开文件进行写入,然后写出您要保留的部分。

    或者您可以创建一个新文件。假设您的输入文件名为q。然后,您将创建一个名为 new_q 的文件,并附加一个流。您可以将所需的内容通过管道传输到新文件。然后你将unlink (delete) 输入文件qrename 输出文件new_qq

    小心:当没有名为q 的文件可用时,此取消链接/重命名操作将创建一小段时间。因此,如果其他程序试图打开它并没有找到它,它应该再试几次。

    如果您正在创建队列方案,您可能会考虑使用其他方案来保存队列数据。这个文件读取/重写/取消链接/重命名序列有很多方法可能会在重负载下给你出错。 (问我,当您有几个小时的空闲时间时,我怎么知道 ;-) redis 值得一看。

    【讨论】:

      【解决方案2】:

      我决定在bash解决问题。

      脚本首先截断temp 文件夹中的文件,然后将它们移回原始文件夹。

      使用tail完成截断:

      tail --bytes="$max_size" "$from_file" > "$to_file"
      

      完整的脚本:

      #!/bin/bash
      
      declare -r store="/my/data/store"
      declare -r temp="/my/data/temp"
      declare -r max_size=$(( 200000 * 24 ))
      
      or_exit() {
          local exit_status=$?
          local message=$*
      
          if [ $exit_status -gt 0 ]
          then
              echo "$(date '+%F %T') [$(basename "$0" .sh)] [ERROR] $message" >&2
              exit $exit_status
          fi
      }
      
      # Checks if there are any files in 'temp'. It should be empty.
      ! ls "$temp/"* &> '/dev/null'
          or_exit 'Temp folder is not empty'
      
      # Loops over all the files in 'store'
      for file_path in "$store/"*
      do
          # Trim bigger then 'max_size' files from 'store' to 'temp'
          if [ "$( stat --format=%s "$file_path" )" -gt "$max_size" ]
          then
              # Truncates the file to the temp folder
              tail --bytes="$max_size" "$file_path" > "$temp/$(basename "$file_path")"
                  or_exit "Cannot tail: $file_path"
          fi
      done
      unset -v file_path
      
      # If there are files in 'temp', move all of them back to 'store'
      if ls "$temp/"* &> '/dev/null'
      then
          # Moves all the truncated files back to the store
          mv "$temp/"* "$store/"
              or_exit 'Cannot move files from temp to store'
      fi
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-06-26
        • 2022-09-27
        • 1970-01-01
        • 1970-01-01
        • 2015-04-18
        • 2017-06-25
        • 2011-04-27
        相关资源
        最近更新 更多