dongshenyu4638
2016-08-09 20:13
浏览 89
已采纳

用PHP读取二进制文件

Is there any comprehensive information on how binary files can be read? I found information on the PHP website (http://www.php.net/manual/en/function.pack.php) but I am struggling to understand on how to handle "typedef struct" and struct uses.

I have a long binary file with many blocks, each block can be represented us C struct. This C struct has various "typedef struct" similar to what i have come up with below:

typedef struct
{ 
 unsigned char Day;
 unsigned char Month;
 unsigned char Year;
} DATE_OF_BIRTH;
#define USER_TYPE 5
DATE_OF_BIRTH Birth[2];\

EDIT:

I have a structure below, this is a part of a bigger structure

typedef struct FILE_HEADER_tag
{
    int Type;
    int Version;
    unsigned long Model;
    unsigned long Number;
    int Class;

    int TemplateLoaded;
    char TemplateName[32];
    RTC_TIME_DATE StartTime;
    RTC_TIME_DATE CurrentCal;
    RTC_TIME_DATE OriginalCal;
    TEMPLATE_SETTINGS;
    int EndType;
} FILE_HEADER;

typedef struct
{
 unsigned char Second;
 unsigned char Minute;
 unsigned char Hour;
 unsigned char Day;
 unsigned char Month;
 unsigned char Year;
} RTC_TIME_DATE;

The binary file is full of line breaks and I was able to decode the first line of it, which returned correct: type, version, model, number and a class. I think I have also decoded two next variable, but i am not sure of it because StartTime returns some gibberish.

At the moment I am looping through the lines from the binary file and trying to unpack each one:

$i = 1;
while (($line = fgets($handle)) !== false) {
    // process the line read.
    var_dump($line);
    if($i == 1) {
        $unpacked = unpack('iType/iVersion/LModel/LNumber/iClass/iTemplateLoaded', $line );
    }if($i == 2) {
        $i++;
        continue;
    }if($i == 3) { 
        $unpacked = unpack('C32TemplateName/CStartTime[Second]/CStartTime[Minute]/CStartTime[Hour]/CStartTime[Day]/CStartTime[Month]/CStartTime[Year]', $line);
    }

    print "<pre>";
    var_dump($unpacked);
    print "</pre>";

    $i++;

    if($i == 4) { exit; }
}

图片转代码服务由CSDN问答提供 功能建议

是否有关于如何读取二进制文件的全面信息? 我在PHP网站上找到了相关信息( http://www.php.net/ manual / en / function.pack.php )但我很难理解如何处理“typedef struct”和struct use。

我有一个很长的二进制文件 很多块,每个块都可以用C struct表示。 这个C结构有各种“typedef结构”,类似于我在下面提出的结构:

  typedef struct 
 {
 unsigned char Day; 
 unsigned char Month;  
 unsigned char Year; 
} DATE_OF_BIRTH; 
 #define USER_TYPE 5 
DATE_OF_BIRTH Birth [2]; \
   
 
 

编辑 :

我有一个结构,这是更大结构的一部分

  typedef struct FILE_HEADER_tag 
 {
 int Type  ; 
 int Version; 
 unsigned long Model; 
 unsigned long Number; 
 int Class; 
 
 int TemplateLoaded; 
 char TemplateName [32]; 
 RTC_TIME_DATE StartTime; 
 RTC_TIME_DATE CurrentCal; 
  RTC_TIME_DATE OriginalCal; 
 TEMPLATE_SETTINGS; 
 int EndType; 
} FILE_HEADER; 
 
typedef struct 
 {
 unsigned char Second; 
 unsigned char Minute; 
 unsigned char Hour; 
 unsigned char Day; \  n unsigned char Month; 
 unsigned char Year; 
} RTC_TIME_DATE; 
   
 
 

二进制文件中包含换行符,我能够解码第一行 的 它返回正确:类型,版本,型号,数量和类。 我想我也解码了两个下一个变量,但我不确定它,因为StartTime返回了一些乱码。

目前我正在循环二进制文件中的行并尝试 解压每一个:

  $ i = 1; 
while(($ line = fgets($ handle))!== false){
 //处理行读取 。
 var_dump($ line); 
 if($ i == 1){
 $ unpacked = unpack('iType / iVersion / LModel / LNumber / iClass / iTemplateLoaded',$ line); 
} if(  $ i == 2){
 $ i ++; 
 continue; 
} if($ i == 3){
 $ unpacked = unpack('C32TemplateName / CStartTime [Second] / CStartTime [Minute] / CStartTime [ 小时] / CStartTime [日] / CStartTime [月] / CStartTime [年]',$行); 
} 
 
打印“&lt; pre&gt;”; 
 var_dump($ unpacked); 
 print“  &lt; / pre&gt;“; 
 
 $ i ++; 
 
 if if($ i == 4){exit;  } 
} 
   
 
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • donglu1913 2016-08-09 20:38
    已采纳

    I'm not really sure what you are trying to achieve here. If you have a binary file generated from the above c code then you could read and upack its content like this:

    // get size of the binary file
    $filesize = filesize('filename.bin');
    // open file for reading in binary mode
    $fp = fopen('filename.bin', 'rb');
    // read the entire file into a binary string
    $binary = fread($fp, $filesize);
    // finally close the file
    fclose($fp);
    
    // unpack the data - notice that we create a format code using 'C%d'
    // that will unpack the size of the file in unsigned chars
    $unpacked = unpack(sprintf('C%d', $filesize), $binary);
    
    // reset array keys
    $unpacked = array_values($unpacked);
    
    // this variable holds the size of *one* structure in the file
    $block_size = 3;
    // figure out the number of blocks in the file
    $block_count = $file_size/$block_size;
    
    // you now should have an array where each element represents a
    // unsigned char from the binary file, so to display Day, Month and Year
    for ($i = 0, $j = 0; $i < $block_count; $i++, $j+=$block_size) {
       print 'Day: ' . $unpacked[$j] . '<br />';
       print 'Month: ' . $unpacked[$j+1] . '<br />';
       print 'Year: ' . $unpacked[$j+2] . '<br /><br />';
    }
    

    Of course you could also create an object to hold the data:

    class DATE_OF_BIRTH {
      public $Day;
      public $Month;
      public $Year;
    
      public function __construct($Day, $Month, $Year) {
          $this->Day = $Day;
          $this->Month = $Month;
          $this->Year = $Year;
      }
    }
    
    $Birth = [];
    
    for ($i = 0, $j = 0; $i < $block_count; $i++, $j+=$block_size) {
       $Birth[] = new DATE_OF_BIRTH(
           $unpacked[$j], 
           $unpacked[$j+1], 
           $unpacked[$j+2]
       );
    }
    

    Another approach would be to slice it at each third element:

    $Birth = [];    
    
    for ($i = 0; $i < $block_count; $i++) {
      // slice one read structure from the array
      $slice = array_slice($unpacked, $i * $block_size, $block_size);
    
      // combine the extracted array containing Day, Month and Year
      // with the appropriate keys
      $slice = array_combine(array('Day', 'Month', 'Year'), $slice);
    
      $Birth[] = $slice;
    }
    

    You should also be aware that this could become much more complicated depending on what data your structure contains, consider this small c program:

    #include <stdio.h>
    #include <stdlib.h>
    
    // pack structure members with a 1 byte aligment
    struct __attribute__((__packed__)) person_t {
      char name[5];
      unsigned int age;
    };
    
    struct person_t persons[2] = {
      {
        { 
          'l', 'i', 's', 'a', 0 
        },
        16
      },
      {
        { 
           'c', 'o', 'r', 'n', 0 
        },
        52
      }
    };
    
    int main(int argc, char** argv) {
      FILE* fp = fopen("binary.bin", "wb");
      fwrite(persons, sizeof(persons), 1, fp);
      fclose(fp);
      return 0;
    }
    

    The above will write each packed structure into the file binary.bin, the size will be exactly 18 bytes. To get a better grasp on alignment/packing you can check out this so post: Structure padding and packing

    Then in you php code you could read each block in a loop like so:

    $filesize = filesize("binary.bin");
    $fp = fopen("binary.bin", "rb");
    $binary = fread($fp, $filesize);
    fclose($fp);
    
    // this variable holds the size of *one* structure
    $block_size = 9;
    $num_blocks = $filesize/$block_size;
    
    // extract each block in a loop from the binary string
    for ($i = 0, $offset = 0; $i < $num_blocks; $i++, $offset += $block_size) {
       $unpacked_block = unpack("C5char/Iint", substr($binary, $offset));
       $unpacked_block = array_values($unpacked_block);
    
       // walk over the 'name' part and get the ascii value
       array_walk($unpacked_block, function(&$item, $key) {
          if($key < 5) {
            $item = chr($item);
          }
       });
       $name = implode('', array_slice($unpacked_block, 0, 5));
       $age = implode('', array_slice($unpacked_block, 5, 1));
       print 'name: ' . $name . '<br />';
       print 'age: ' . $age . '<br />';
    }
    
    点赞 评论

相关推荐 更多相似问题