【问题标题】:binary safe write on file with php to create a DBF file使用 php 对文件进行二进制安全写入以创建 DBF 文件
【发布时间】:2023-03-20 23:27:02
【问题描述】:

我需要使用 php 函数拆分一个大的 DBF 文件,这意味着我有例如 1000 条记录,我必须创建 2 个文件,每个文件有 500 条记录。

我没有任何可用的 dbase 扩展,也无法安装它,所以我必须使用基本的 php 函数。使用基本的fread 函数,我能够正确读取和解析文件,但是当我尝试编写新的 dbf 时,我遇到了一些问题。

据我了解,DBF 文件结构为 2 行文件:第一行包含文件信息、标题信息,并且是二进制文件。第二行包含数据,它是纯文本。所以我想简单地写一个新的二进制文件复制第一行并手动添加第一个文件中的第一条记录,另一个文件中的其他记录。

这是我用来解析文件的代码,效果很好

    $fdbf = fopen($_FILES['userfile']['tmp_name'],'r');
    $fields = array();
    $buf = fread($fdbf,32);
    $header=unpack( "VRecordCount/vFirstRecord/vRecordLength", substr($buf,4,8));
    $goon = true;
    $unpackString='';
    while ($goon && !feof($fdbf)) { // read fields:
        $buf = fread($fdbf,32);
        if (substr($buf,0,1)==chr(13)) {$goon=false;} // end of field list
        else {
            $field=unpack( "a11fieldname/A1fieldtype/Voffset/Cfieldlen/Cfielddec", substr($buf,0,18));
            
            $unpackString.="A$field[fieldlen]$field[fieldname]/";
            array_push($fields, $field);
        }
    }
    fseek($fdbf, 0);
    $first_line = fread($fdbf, $header['FirstRecord']+1);
    
    fseek($fdbf, $header['FirstRecord']+1); // move back to the start of the first record (after the field definitions)

first_line 是包含标头数据的变量,但是当我尝试将其写入新文件时,会发生错误,并且该行并未完全按照读取的方式写入。这是我用来编写的代码:

$handle_log = fopen($new_filename, "wb");
fwrite($handle_log, $first_line, strlen($first_line) );
fwrite($handle_log, $string );
fclose($handle_log);

我已尝试将 b 值添加到 fopen mode 参数中,建议以二进制方式打开它,我还建议准确添加字符串的长度以避免一些字符的条纹但不成功,因为写入的所有文件都不是正确的 DBF 格式。我可以做些什么来实现我的目标?

【问题讨论】:

  • 你可以不使用 DBF 库,因为没有,还是有一些随意的理由让你不得不重新发明轮子?
  • 我无法控制网络服务器,我无法安装新的扩展,并且提供商不允许我这样做
  • 如果您编写自己的 php,为什么不在您的代码中包含一个 DBF 库?

标签: php dbf


【解决方案1】:

据我了解,DBF 文件结构为 2 行文件: 第一行包含文件信息,标题信息,它是二进制的。这 第二行包含数据,它是纯文本。

嗯,比这要复杂一些。

有关 dbf 文件格式的完整说明,请参阅 here

所以最好使用库来读写 dbf 文件。

如果你真的需要自己做,这里是最重要的部分:

  • Dbf 是一种二进制文件格式,因此您必须将其作为二进制文件进行读写。例如,记录数存储在一个 32 位整数中,可以包含零字节。
  • 不能对该二进制数据使用字符串函数。例如strlen() 将扫描数据直到第一个空字节,该字节存在于该 32 位整数中,并将返回错误的值。
  • 如果您拆分文件(记录),则必须调整标题中的记录数。
  • 在拆分记录时请记住,每条记录前面都有一个额外的字节,如果记录没有被删除,则为空格0x20,如果记录被删除,则为星号0x2A。 (例如,如果您有 4 个 10 字节的字段,则每条记录的长度将为 41) - 该值也可在标头中找到:bytes 10-11 - 16-bit number - Number of bytes in the record. (Least significant byte first)
  • 文件可能以文件结束标记 0x1A 结尾,因此您也必须检查这一点。

【讨论】:

  • 是的,你是对的。所以我真的需要一个 DBF 库,问题不在于 php fwrite 函数。谢谢
  • @TizianoMischi 我认为您的主要(第一个)问题在strlen($first_line) 中,它将返回错误的值。如果您解决该问题并更改标题中的记录计数值,您可能应该没问题。您也不必阅读每个字段定义,只需复制整个标题并更改记录数。标头的长度为 8-9 字节。
猜你喜欢
  • 2017-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-21
  • 2013-05-09
  • 2015-02-22
相关资源
最近更新 更多