Perl文本二进制互转脚本丢失10.0000数据问题求助
问题原因分析
你的问题核心出在txt2bin.pl的打包逻辑错误,导致10这个数值没有被正确处理,同时反向转换的bin2txt.pl也存在对应问题,具体拆解如下:
1. txt2bin.pl的核心错误
当你执行$line =~ s/\.0000//;后,得到的是类似"137 136 133 136 10 134 0 132 132"的字符串,但紧接着直接把这个字符串传给pack("C*", $line)——这里Perl会把字符串拆分成单个字符(包括空格、数字字符),然后将每个字符的ASCII码值打包成字节,而不是把每个数字串解析成数值后打包。
举个例子:原数据中的10.0000变成10,但在字符串里是两个字符'1'(ASCII 49)和'0'(ASCII 48),这会被打包成两个字节,而不是一个值为10的字节;后续即使反向转换,也根本还原不出原本的10.0000。
2. bin2txt.pl的对应问题
因为打包时错误地把字符ASCII存成了字节,反向转换时的$data =~ s/(.{1})/unpack("C*",$1).".0000 \n"/eg;逻辑也不对:它把每个字节解析成ASCII值,然后拼接成字符串,但这和你原本想要的“还原数值”完全不匹配,而且每个字节后都加换行,导致输出格式混乱。
修正后的脚本
修正版txt2bin.pl
my $file = $ARGV[0]; my $fileout = $file.".bin"; if($file eq "-h" or $file eq "-help" or $file eq "") { print "Usage : txt2bin.pl file_in\n"; print " file_out = file_in.bin\n"; print "This script converts a txt file to a binary file\n"; } else { print "File in = $file\n"; print "File out = $fileout\n"; open(FILE,"<$file") or die $!; open(FILEOUT,">$fileout") or die $!; binmode FILEOUT; while(defined(my $line=<FILE>)) { chomp($line); # 先分割成单个数据项,再去除每个项的.0000并转成整数 my @values = map { s/\.0000$//; int($_) } split /\s+/, $line; # 过滤掉超出无符号8位范围的数值(0-255),避免无效字节 @values = grep { $_ >=0 && $_ <=255 } @values; syswrite FILEOUT, pack("C*", @values); } close(FILE); close(FILEOUT); }
关键改动:
- 用
split /\s+/, $line将每行数据分割成独立的数字项 - 通过
map去除每个项的.0000并转换成整数 - 添加
grep过滤非法数值,保证打包的是有效的无符号8位字节 - 传递数值列表
@values给pack("C*"),而非原始字符串
修正版bin2txt.pl
my $file = $ARGV[0]; my $fileout = $file.".txt"; if($file eq "-h" or $file eq "-help" or $file eq "") { print "Usage : bin2txt.pl file_in\n"; print " file_out = file_in.txt\n"; print "This script converts a binary file to a txt file\n"; } else { print "File in = $file\n"; print "File out = $fileout\n"; undef $/; # 一次性读取整个二进制文件 open(FILE,"<$file") or die $!; open(FILEOUT,">$fileout") or die $!; binmode FILE; my $data = <FILE>; # 解析所有字节为数值,再拼接成指定格式的字符串 my @values = unpack("C*", $data); my $output = join(" ", map { sprintf("%.4f", $_) } @values); syswrite FILEOUT, $output . "\n"; close(FILE); close(FILEOUT); }
关键改动:
- 直接用
unpack("C*", $data)得到所有字节对应的数值列表 - 用
sprintf("%.4f", $_)还原成.0000结尾的格式 - 用
join将数值拼接成空格分隔的字符串,保持原数据的格式
验证效果
用你的测试数据:
137.0000 136.0000 133.0000 136.0000 10.0000 134.0000 0.0000 132.0000 132.0000
执行perl txt2bin.pl test.txt生成test.txt.bin,再执行perl bin2txt.pl test.txt.bin,得到的输出会和原数据完全一致,包括原本丢失的10.0000项。
内容的提问来源于stack exchange,提问作者dalex78
相关产品推荐
相关产品推荐

