You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl实现文件二进制转十六进制时输出文件仅显示"82"的问题排查

问题分析:Perl二进制转十六进制脚本输出文件仅显示最后一个字节

嘿,我来帮你拆解一下为什么原脚本的输出文件只显示"82",以及修正后的脚本是怎么解决问题的——你踩的坑其实是个很常见的文件操作误区!

原脚本的核心问题

  • 重复以覆盖模式打开输出文件:你在foreach(split(//, $buf))循环内部每次都执行open(H,">$hexName"),>这个模式的作用是清空目标文件并从头写入。所以每处理一个字节,文件就被清空一次,最后只剩下最后一个字节转换后的十六进制值(也就是你看到的"82")。
  • 变量名拼写错误:die语句里的$fname应该是$hexName,虽然这个错误没触发(因为你终端能输出,说明文件打开成功了),但这是个潜在的bug。
  • 不必要的read偏移量设置:read(F,$buf,$blockSize,$ct*$blockSize)里的第四个参数是强制设置读取的偏移量,但read默认会从文件当前位置继续读取,加上这个参数反而可能导致读取逻辑混乱,比如重复读取或者漏读内容。

修正后的脚本为什么能正常工作

修正后的脚本做了几个关键优化,直接解决了这些问题:

  • 一次性打开/关闭输出文件:在读取源文件前就打开输出文件,直到所有内容处理完成才关闭,彻底避免了重复打开覆盖文件的问题。
  • 一次性读取整个文件:用$blockSize = -s $fileName获取源文件的总大小,然后一次性把整个文件内容读入缓冲区,再通过unpack("H*", $buf)直接把所有二进制内容转换成连续的十六进制字符串写入文件,逻辑清晰还更高效。
  • 去掉冗余的循环和变量:unpack("H*")可以直接处理整个缓冲区,不需要逐字节拆分处理,减少了不必要的循环嵌套。

另一种渐进式修复方案(适合大文件)

如果你的源文件很大,一次性读取整个文件会有内存压力,可以修改原脚本,把输出文件的打开/关闭移到循环外面,保持分块读取的逻辑:

#!/usr/bin/perl -w
use strict;
my $blockSize = 1024;
my $fileName = $ARGV[0];
my $hexName = $ARGV[1];

open(F,"<$fileName") or die("Unable to open file $fileName, $!");
binmode(F);
# 提前打开输出文件,只打开一次
open(H,">$hexName") or die("Unable to open file $hexName, $!");
binmode (H);

my $buf;
# 去掉不必要的偏移量参数,让read从当前位置自动读取
while(read(F,$buf,$blockSize)){
    foreach(split(//, $buf)){
        my $hex_str = unpack ("H*", $_);
        print $hex_str; # 终端输出
        print H $hex_str; # 文件输出
    }
    print "\n";
}

close(H);
close(F);

这个版本既保留了分块读取的优势,又解决了文件覆盖的问题,适合处理大体积的二进制文件。

内容的提问来源于stack exchange,提问作者Mookie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:15:06