Perl: seek to and read bits, not bytes

青春壹個敷衍的年華 提交于 2019-12-23 06:10:18

问题


In Perl, I want to seek to the nth bit (not byte) of a file and then read the next m bits, returned as a list of 0s and 1s.

Is there any easy way to do this?

I realize I can write a subroutine wrapping regular seek and read, but was wondering if there's a easier solution.


回答1:


If n is a multiple of m, and m is one of 1, 2, 4, 8, 16, 32, and on some platforms, 64, you can read the whole file into a string and use vec for this.

(Admittedly a fairly constraining case, but a common one.)

Barring that, you'll just have to do the math; in pseudo-code:

discard = n % 8;
startbyte = (n - discard) / 8
bits = m + discard
bytes = int( (bits + 7) / 8 )
seek to startbyte
read bytes into string
@list = split //, unpack "${bits}b", string
splice( @list, 0, $discard ) 
splice( @list, $m, @list )



回答2:


bitseek would grab a group of bits at one time.

seek($fh, int($bit_num/8), SEEK_SET);
my $offset = $bit_num % 8;
read($fh, my $buf, ceil(($offset+$num_bits)/8));

I'm looking for bit addressing, not bit-by-bit reading.

vec($bits, $offset+$bit_num, 1);



回答3:


I ended up writing something like what @ikegami and @ysth suggested. For reference:

=item seek_bits($fh, $start, $num) 

Seek to bit (not byte) $start in filehandle $fh, and return the next 
$num bits (as a list). 

=cut 

sub seek_bits { 
  my($fh, $start, $num) = @_; 
  # the byte where this bit starts and the offset 
  my($fbyte, $offset) = (floor($start/8), $start%8); 
  # the number of bytes to read ($offset does affect this) 
  my($nbytes) = ceil($num+$offset)/8; 

  seek($fh, $fbyte, SEEK_SET);  
  read($fh, my($data), $nbytes); 
  my(@ret) = split(//, unpack("B*", $data)); 
  # return requested bits 
  return @ret[$offset-1..$offset+$num]; 
} 


来源:https://stackoverflow.com/questions/25510199/perl-seek-to-and-read-bits-not-bytes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!