使用 php 二进制安全写入文件以创建 DBF 文件
binary safe write on file with php to create a DBF file
我需要使用 php 函数拆分一个大的 DBF 文件,这意味着我有例如 1000 条记录,我必须创建 2 个文件,每个文件有 500 条记录。
我没有可用的数据库扩展,也无法安装它,所以我必须使用基本的 php 功能。使用基本的 fread
函数我能够正确读取和解析文件,但是当我尝试编写一个新的 dbf 时我遇到了一些问题。
据我所知,DBF 文件由两行文件组成:第一行包含文件信息,header 信息,并且是二进制文件。第二行包含数据并且是纯文本。所以我想简单地写一个新的二进制文件复制第一行并在第一个文件中手动添加第一条记录,在另一个文件中添加其他记录。
这是我用来解析文件的代码,效果很好
$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
是包含 header 数据的变量,但是当我尝试将其写入新文件时,出现了错误,并且该行的写入与读取时不完全相同。那是我用来编写的代码:
$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 格式。我可以做些什么来实现我的目标?
As i have understood, the DBF file is structured in a 2 line file: the
first line contains file info, header info and it's in binary. The
second line contains the data and it's plain text.
嗯,比这要复杂一点。
有关 dbf 文件格式的完整说明,请参阅 here。
所以如果能用一个库来读写dbf文件就更好了
如果您真的需要自己做,这里是最重要的部分:
- Dbf 是一种二进制文件格式,因此您必须以二进制形式读写它。例如,记录数存储在一个 32 位整数中,它可以包含零字节。
- 您不能对该二进制数据使用字符串函数。例如
strlen()
将扫描数据直到第一个空字节,该字节存在于该 32 位整数中,并且 return 会得到错误的值。
- 如果拆分文件(记录),则必须调整 header 中的记录数。
- 拆分记录时请记住,每条记录前面都有一个额外的字节,如果记录未删除则为 space
0x20
,如果记录为星号 0x2A
被删除。 (例如,如果您有 4 个 10 字节的字段,则每条记录的长度将为 41)- 该值也可用于 header:bytes 10-11 - 16-bit number - Number of bytes in the record. (Least significant byte first)
- 文件可能以 end-of-file 标记
0x1A
结尾,因此您也必须检查一下。
我需要使用 php 函数拆分一个大的 DBF 文件,这意味着我有例如 1000 条记录,我必须创建 2 个文件,每个文件有 500 条记录。
我没有可用的数据库扩展,也无法安装它,所以我必须使用基本的 php 功能。使用基本的 fread
函数我能够正确读取和解析文件,但是当我尝试编写一个新的 dbf 时我遇到了一些问题。
据我所知,DBF 文件由两行文件组成:第一行包含文件信息,header 信息,并且是二进制文件。第二行包含数据并且是纯文本。所以我想简单地写一个新的二进制文件复制第一行并在第一个文件中手动添加第一条记录,在另一个文件中添加其他记录。
这是我用来解析文件的代码,效果很好
$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
是包含 header 数据的变量,但是当我尝试将其写入新文件时,出现了错误,并且该行的写入与读取时不完全相同。那是我用来编写的代码:
$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 格式。我可以做些什么来实现我的目标?
As i have understood, the DBF file is structured in a 2 line file: the first line contains file info, header info and it's in binary. The second line contains the data and it's plain text.
嗯,比这要复杂一点。
有关 dbf 文件格式的完整说明,请参阅 here。
所以如果能用一个库来读写dbf文件就更好了
如果您真的需要自己做,这里是最重要的部分:
- Dbf 是一种二进制文件格式,因此您必须以二进制形式读写它。例如,记录数存储在一个 32 位整数中,它可以包含零字节。
- 您不能对该二进制数据使用字符串函数。例如
strlen()
将扫描数据直到第一个空字节,该字节存在于该 32 位整数中,并且 return 会得到错误的值。 - 如果拆分文件(记录),则必须调整 header 中的记录数。
- 拆分记录时请记住,每条记录前面都有一个额外的字节,如果记录未删除则为 space
0x20
,如果记录为星号0x2A
被删除。 (例如,如果您有 4 个 10 字节的字段,则每条记录的长度将为 41)- 该值也可用于 header:bytes 10-11 - 16-bit number - Number of bytes in the record. (Least significant byte first)
- 文件可能以 end-of-file 标记
0x1A
结尾,因此您也必须检查一下。