如何用PHP阅读FoxPro备忘录?
我必须将.DBF和.FPT文件从Visual FoxPro转换为MySQL。现在,我的脚本适用于.DBF文件,它使用dbase_open和dbase_get_record_以及_名称打开并读取这些文件,然后执行MySQL INSERT命令 但是,这些.DBF文件的某些字段属于MEMO类型,因此存储在以.FPT结尾的单独文件中。如何读取此文件 我在中找到了此文件类型的规范,但我不知道如何使用PHP按字节读取此文件,我更喜欢更简单的解决方案如何用PHP阅读FoxPro备忘录?,php,mysql,foxpro,dbf,Php,Mysql,Foxpro,Dbf,我必须将.DBF和.FPT文件从Visual FoxPro转换为MySQL。现在,我的脚本适用于.DBF文件,它使用dbase_open和dbase_get_record_以及_名称打开并读取这些文件,然后执行MySQL INSERT命令 但是,这些.DBF文件的某些字段属于MEMO类型,因此存储在以.FPT结尾的单独文件中。如何读取此文件 我在中找到了此文件类型的规范,但我不知道如何使用PHP按字节读取此文件,我更喜欢更简单的解决方案 有什么想法吗?我认为PHP中不太可能有FoxPro库 您可
有什么想法吗?我认为PHP中不太可能有FoxPro库 您可能需要从头开始编写代码。有关字节读取,请参见
编辑:似乎有一个问题。您可以通过PDO和该连接器连接到FoxPro数据库。我不知道成功的机会有多大,需要做多少工作 我认为PHP中不太可能有FoxPro库 您可能需要从头开始编写代码。有关字节读取,请参见
编辑:似乎有一个问题。您可以通过PDO和该连接器连接到FoxPro数据库。我不知道成功的机会有多大,需要做多少工作 虽然不是PHP,但VFP是基于1的引用,我认为PHP是基于零的引用,因此您必须进行相应的解密和调整,但这是可行的,希望您能够 完成后发布此部分的版本 VFP中的FILETOSTR将打开一个文件,并将整个内容读入 作为字符串的单个内存变量-所有转义键、高字节字符等都完好无损。你可能需要依赖FOPEN、FSEEK、FCLOSE等 MemoTest.FPT是我的示例备忘录表/文件 fpt1=FILETOSTR MEMOTEST.FPT 首先,您必须检测创建文件时使用的备注块大小。通常这是64个字节,但根据您在文章中的链接 收割台位置6-7标识尺寸VFP,位置7和8。第一个字节是高阶字节
nBlockSize = ASC( SUBSTR( fpt1, 7, 1 )) * 256 + ASC( SUBSTR( fpt1, 8, 1 ))
现在,看看你的个人记录。只要DBF结构中有memo字段,并且每个记录结构中可以有多个字段,那么就有4个字节。在记录字段中,它标识备忘录文件中存储内容的块
MemoBytes=标识字段位置的4个字节。这些将存储为0-255之间的ASCII码。此字段存储时,第一个字节为低位,第四个字节为256^3=16777216。使用过的第一个块将根据memo.fpt文件规范以512的位置偏移开始,该文件规范的头占据位置0-511
因此,如果您的第一个备注字段的内容为8000,其中8是实际的0x08,而不是数字8,即0x38,并且零是0x00
YourMemoField=8000实际上使用ascii,但为了可读性,显示十六进制预期值
First Byte is ASCII value * 1 ( 256 ^ 0 )
Second Byte is ASCII value * 256 (256 ^ 1)
Third Byte is ASCII value * 65536 (256 ^ 2)
Fourth Byte is ASCII value * 16777216 (256 ^ 3)
nMemoBlock = byte1 + ( byte2 * 256 ) + ( byte3 * 65536 ) + ( byte4 * 16777216 )
现在,你需要去看电影
FSEEK( handle, nMemoBlock * nBlockSize +1 )
对于要查找的块的第一个字节。这将指向块标题。在这种情况下,根据规范,前4个字节标识块签名,后4个字节是内容的长度。对于这两个,字节首先以高位字节存储
从您的FSEEK来看,它与上面的nMemoBlock相反,具有高字节。这里的字节1-4来自您的FSEEK位置
nSignature = ( byte1 * 16777216 ) + ( byte2 * 65536 ) + ( byte3 * 256 ) + byte4
nMemoLength = ( byte5 * 16777216 ) + ( byte6 * 65536 ) + ( byte7 * 256 ) + byte8
现在,FSEEK到第9个字节,即刚才读取的签名和备忘录长度头的8个字节之后的数据的第一个实际字符。这是数据的开始
现在,阅读剩下的内容
FSEEK() +9 characters to new position
cFinalMemoData = FREAD( handle, nMemoLength )
我知道这不是完美的,PHP脚本也不是完美的,但关于如何存储东西的伪代码已经足够了,希望能让您顺利上路
同样,在调试过程中,请考虑确保0或1偏移量。为了帮助简化和测试这一点,我创建了一个包含2个字段的简单.DBF。。。一个字符字段和一个备注字段,添加了一些记录和一些基本内容,以确认所有内容、位置等。虽然不是PHP,但VFP是基于1的引用,我认为PHP是基于零的引用,因此您必须进行相应的解密和调整,但这很有效,希望您能够 完成后发布此部分的版本 VFP中的FILETOSTR将打开一个文件,并将整个内容读入 作为字符串的单个内存变量-所有转义键、高字节字符等都完好无损。你可能需要依赖FOPEN、FSEEK、FCLOSE等 MemoTest.FPT是我的示例备忘录表/文件 fpt1=FILETOSTR MEMOTEST.FPT 首先,您必须检测创建文件时使用的备注块大小。通常这是64个字节,但根据您在文章中的链接 收割台位置6-7标识尺寸VFP,位置7和8。第一个字节是高阶字节
nBlockSize = ASC( SUBSTR( fpt1, 7, 1 )) * 256 + ASC( SUBSTR( fpt1, 8, 1 ))
现在,看看你的个人记录。DBF结构中的任何位置都有“备注”字段
每个记录结构可以有多个字节,其中有4个字节。在记录字段中,它标识备忘录文件中存储内容的块
MemoBytes=标识字段位置的4个字节。这些将存储为0-255之间的ASCII码。此字段存储时,第一个字节为低位,第四个字节为256^3=16777216。使用过的第一个块将根据memo.fpt文件规范以512的位置偏移开始,该文件规范的头占据位置0-511
因此,如果您的第一个备注字段的内容为8000,其中8是实际的0x08,而不是数字8,即0x38,并且零是0x00
YourMemoField=8000实际上使用ascii,但为了可读性,显示十六进制预期值
First Byte is ASCII value * 1 ( 256 ^ 0 )
Second Byte is ASCII value * 256 (256 ^ 1)
Third Byte is ASCII value * 65536 (256 ^ 2)
Fourth Byte is ASCII value * 16777216 (256 ^ 3)
nMemoBlock = byte1 + ( byte2 * 256 ) + ( byte3 * 65536 ) + ( byte4 * 16777216 )
现在,你需要去看电影
FSEEK( handle, nMemoBlock * nBlockSize +1 )
对于要查找的块的第一个字节。这将指向块标题。在这种情况下,根据规范,前4个字节标识块签名,后4个字节是内容的长度。对于这两个,字节首先以高位字节存储
从您的FSEEK来看,它与上面的nMemoBlock相反,具有高字节。这里的字节1-4来自您的FSEEK位置
nSignature = ( byte1 * 16777216 ) + ( byte2 * 65536 ) + ( byte3 * 256 ) + byte4
nMemoLength = ( byte5 * 16777216 ) + ( byte6 * 65536 ) + ( byte7 * 256 ) + byte8
现在,FSEEK到第9个字节,即刚才读取的签名和备忘录长度头的8个字节之后的数据的第一个实际字符。这是数据的开始
现在,阅读剩下的内容
FSEEK() +9 characters to new position
cFinalMemoData = FREAD( handle, nMemoLength )
我知道这不是完美的,PHP脚本也不是完美的,但关于如何存储东西的伪代码已经足够了,希望能让您顺利上路
同样,在调试过程中,请考虑确保0或1偏移量。为了帮助简化和测试这一点,我创建了一个包含2个字段的简单.DBF。。。一个字符字段和一个备注字段,添加了一些记录和一些基本内容以确认所有内容、位置等。好的,我仔细研究了DBF和FPT文件结构的MSDN规范,结果是一个漂亮的PHP类,它可以同时打开DBF和可选的FPT备注文件。这个类将给你一条又一条记录,从而从备忘录文件中获取任何备忘录(如果打开的话)
class Prodigy_DBF {
private $Filename, $DB_Type, $DB_Update, $DB_Records, $DB_FirstData, $DB_RecordLength, $DB_Flags, $DB_CodePageMark, $DB_Fields, $FileHandle, $FileOpened;
private $Memo_Handle, $Memo_Opened, $Memo_BlockSize;
private function Initialize() {
if($this->FileOpened) {
fclose($this->FileHandle);
}
if($this->Memo_Opened) {
fclose($this->Memo_Handle);
}
$this->FileOpened = false;
$this->FileHandle = NULL;
$this->Filename = NULL;
$this->DB_Type = NULL;
$this->DB_Update = NULL;
$this->DB_Records = NULL;
$this->DB_FirstData = NULL;
$this->DB_RecordLength = NULL;
$this->DB_CodePageMark = NULL;
$this->DB_Flags = NULL;
$this->DB_Fields = array();
$this->Memo_Handle = NULL;
$this->Memo_Opened = false;
$this->Memo_BlockSize = NULL;
}
public function __construct($Filename, $MemoFilename = NULL) {
$this->Prodigy_DBF($Filename, $MemoFilename);
}
public function Prodigy_DBF($Filename, $MemoFilename = NULL) {
$this->Initialize();
$this->OpenDatabase($Filename, $MemoFilename);
}
public function OpenDatabase($Filename, $MemoFilename = NULL) {
$Return = false;
$this->Initialize();
$this->FileHandle = fopen($Filename, "r");
if($this->FileHandle) {
// DB Open, reading headers
$this->DB_Type = dechex(ord(fread($this->FileHandle, 1)));
$LUPD = fread($this->FileHandle, 3);
$this->DB_Update = ord($LUPD[0])."/".ord($LUPD[1])."/".ord($LUPD[2]);
$Rec = unpack("V", fread($this->FileHandle, 4));
$this->DB_Records = $Rec[1];
$Pos = fread($this->FileHandle, 2);
$this->DB_FirstData = (ord($Pos[0]) + ord($Pos[1]) * 256);
$Len = fread($this->FileHandle, 2);
$this->DB_RecordLength = (ord($Len[0]) + ord($Len[1]) * 256);
fseek($this->FileHandle, 28); // Ignoring "reserved" bytes, jumping to table flags
$this->DB_Flags = dechex(ord(fread($this->FileHandle, 1)));
$this->DB_CodePageMark = ord(fread($this->FileHandle, 1));
fseek($this->FileHandle, 2, SEEK_CUR); // Ignoring next 2 "reserved" bytes
// Now reading field captions and attributes
while(!feof($this->FileHandle)) {
// Checking for end of header
if(ord(fread($this->FileHandle, 1)) == 13) {
break; // End of header!
} else {
// Go back
fseek($this->FileHandle, -1, SEEK_CUR);
}
$Field["Name"] = trim(fread($this->FileHandle, 11));
$Field["Type"] = fread($this->FileHandle, 1);
fseek($this->FileHandle, 4, SEEK_CUR); // Skipping attribute "displacement"
$Field["Size"] = ord(fread($this->FileHandle, 1));
fseek($this->FileHandle, 15, SEEK_CUR); // Skipping any remaining attributes
$this->DB_Fields[] = $Field;
}
// Setting file pointer to the first record
fseek($this->FileHandle, $this->DB_FirstData);
$this->FileOpened = true;
// Open memo file, if exists
if(!empty($MemoFilename) and file_exists($MemoFilename) and preg_match("%^(.+).fpt$%i", $MemoFilename)) {
$this->Memo_Handle = fopen($MemoFilename, "r");
if($this->Memo_Handle) {
$this->Memo_Opened = true;
// Getting block size
fseek($this->Memo_Handle, 6);
$Data = unpack("n", fread($this->Memo_Handle, 2));
$this->Memo_BlockSize = $Data[1];
}
}
}
return $Return;
}
public function GetNextRecord($FieldCaptions = false) {
$Return = NULL;
$Record = array();
if(!$this->FileOpened) {
$Return = false;
} elseif(feof($this->FileHandle)) {
$Return = NULL;
} else {
// File open and not EOF
fseek($this->FileHandle, 1, SEEK_CUR); // Ignoring DELETE flag
foreach($this->DB_Fields as $Field) {
$RawData = fread($this->FileHandle, $Field["Size"]);
// Checking for memo reference
if($Field["Type"] == "M" and $Field["Size"] == 4 and !empty($RawData)) {
// Binary Memo reference
$Memo_BO = unpack("V", $RawData);
if($this->Memo_Opened and $Memo_BO != 0) {
fseek($this->Memo_Handle, $Memo_BO[1] * $this->Memo_BlockSize);
$Type = unpack("N", fread($this->Memo_Handle, 4));
if($Type[1] == "1") {
$Len = unpack("N", fread($this->Memo_Handle, 4));
$Value = trim(fread($this->Memo_Handle, $Len[1]));
} else {
// Pictures will not be shown
$Value = "{BINARY_PICTURE}";
}
} else {
$Value = "{NO_MEMO_FILE_OPEN}";
}
} else {
$Value = trim($RawData);
}
if($FieldCaptions) {
$Record[$Field["Name"]] = $Value;
} else {
$Record[] = $Value;
}
}
$Return = $Record;
}
return $Return;
}
function __destruct() {
// Cleanly close any open files before destruction
$this->Initialize();
}
}
该类可以这样使用:
$Test = new Prodigy_DBF("customer.DBF", "customer.FPT");
while(($Record = $Test->GetNextRecord(true)) and !empty($Record)) {
print_r($Record);
}
这可能不是一门全能的完美课程,但它对我很有用。可以随意使用这段代码,但请注意,该类非常宽容——它不关心fread和fseek是否返回true或其他任何东西——因此您可能希望在使用之前对其进行一些改进
还请注意,有许多私有变量,如记录数、记录大小等,目前尚未使用。好的,我仔细研究了DBF和FPT文件结构的MSDN规范,结果是一个漂亮的PHP类,它可以同时打开DBF和可选的FPT备忘录文件。这个类将给你一条又一条记录,从而从备忘录文件中获取任何备忘录(如果打开的话)
class Prodigy_DBF {
private $Filename, $DB_Type, $DB_Update, $DB_Records, $DB_FirstData, $DB_RecordLength, $DB_Flags, $DB_CodePageMark, $DB_Fields, $FileHandle, $FileOpened;
private $Memo_Handle, $Memo_Opened, $Memo_BlockSize;
private function Initialize() {
if($this->FileOpened) {
fclose($this->FileHandle);
}
if($this->Memo_Opened) {
fclose($this->Memo_Handle);
}
$this->FileOpened = false;
$this->FileHandle = NULL;
$this->Filename = NULL;
$this->DB_Type = NULL;
$this->DB_Update = NULL;
$this->DB_Records = NULL;
$this->DB_FirstData = NULL;
$this->DB_RecordLength = NULL;
$this->DB_CodePageMark = NULL;
$this->DB_Flags = NULL;
$this->DB_Fields = array();
$this->Memo_Handle = NULL;
$this->Memo_Opened = false;
$this->Memo_BlockSize = NULL;
}
public function __construct($Filename, $MemoFilename = NULL) {
$this->Prodigy_DBF($Filename, $MemoFilename);
}
public function Prodigy_DBF($Filename, $MemoFilename = NULL) {
$this->Initialize();
$this->OpenDatabase($Filename, $MemoFilename);
}
public function OpenDatabase($Filename, $MemoFilename = NULL) {
$Return = false;
$this->Initialize();
$this->FileHandle = fopen($Filename, "r");
if($this->FileHandle) {
// DB Open, reading headers
$this->DB_Type = dechex(ord(fread($this->FileHandle, 1)));
$LUPD = fread($this->FileHandle, 3);
$this->DB_Update = ord($LUPD[0])."/".ord($LUPD[1])."/".ord($LUPD[2]);
$Rec = unpack("V", fread($this->FileHandle, 4));
$this->DB_Records = $Rec[1];
$Pos = fread($this->FileHandle, 2);
$this->DB_FirstData = (ord($Pos[0]) + ord($Pos[1]) * 256);
$Len = fread($this->FileHandle, 2);
$this->DB_RecordLength = (ord($Len[0]) + ord($Len[1]) * 256);
fseek($this->FileHandle, 28); // Ignoring "reserved" bytes, jumping to table flags
$this->DB_Flags = dechex(ord(fread($this->FileHandle, 1)));
$this->DB_CodePageMark = ord(fread($this->FileHandle, 1));
fseek($this->FileHandle, 2, SEEK_CUR); // Ignoring next 2 "reserved" bytes
// Now reading field captions and attributes
while(!feof($this->FileHandle)) {
// Checking for end of header
if(ord(fread($this->FileHandle, 1)) == 13) {
break; // End of header!
} else {
// Go back
fseek($this->FileHandle, -1, SEEK_CUR);
}
$Field["Name"] = trim(fread($this->FileHandle, 11));
$Field["Type"] = fread($this->FileHandle, 1);
fseek($this->FileHandle, 4, SEEK_CUR); // Skipping attribute "displacement"
$Field["Size"] = ord(fread($this->FileHandle, 1));
fseek($this->FileHandle, 15, SEEK_CUR); // Skipping any remaining attributes
$this->DB_Fields[] = $Field;
}
// Setting file pointer to the first record
fseek($this->FileHandle, $this->DB_FirstData);
$this->FileOpened = true;
// Open memo file, if exists
if(!empty($MemoFilename) and file_exists($MemoFilename) and preg_match("%^(.+).fpt$%i", $MemoFilename)) {
$this->Memo_Handle = fopen($MemoFilename, "r");
if($this->Memo_Handle) {
$this->Memo_Opened = true;
// Getting block size
fseek($this->Memo_Handle, 6);
$Data = unpack("n", fread($this->Memo_Handle, 2));
$this->Memo_BlockSize = $Data[1];
}
}
}
return $Return;
}
public function GetNextRecord($FieldCaptions = false) {
$Return = NULL;
$Record = array();
if(!$this->FileOpened) {
$Return = false;
} elseif(feof($this->FileHandle)) {
$Return = NULL;
} else {
// File open and not EOF
fseek($this->FileHandle, 1, SEEK_CUR); // Ignoring DELETE flag
foreach($this->DB_Fields as $Field) {
$RawData = fread($this->FileHandle, $Field["Size"]);
// Checking for memo reference
if($Field["Type"] == "M" and $Field["Size"] == 4 and !empty($RawData)) {
// Binary Memo reference
$Memo_BO = unpack("V", $RawData);
if($this->Memo_Opened and $Memo_BO != 0) {
fseek($this->Memo_Handle, $Memo_BO[1] * $this->Memo_BlockSize);
$Type = unpack("N", fread($this->Memo_Handle, 4));
if($Type[1] == "1") {
$Len = unpack("N", fread($this->Memo_Handle, 4));
$Value = trim(fread($this->Memo_Handle, $Len[1]));
} else {
// Pictures will not be shown
$Value = "{BINARY_PICTURE}";
}
} else {
$Value = "{NO_MEMO_FILE_OPEN}";
}
} else {
$Value = trim($RawData);
}
if($FieldCaptions) {
$Record[$Field["Name"]] = $Value;
} else {
$Record[] = $Value;
}
}
$Return = $Record;
}
return $Return;
}
function __destruct() {
// Cleanly close any open files before destruction
$this->Initialize();
}
}
该类可以这样使用:
$Test = new Prodigy_DBF("customer.DBF", "customer.FPT");
while(($Record = $Test->GetNextRecord(true)) and !empty($Record)) {
print_r($Record);
}
这可能不是一门全能的完美课程,但它对我很有用。可以随意使用这段代码,但请注意,该类非常宽容——它不关心fread和fseek是否返回true或其他任何东西——因此您可能希望在使用之前对其进行一些改进
还请注意,有许多私有变量,如记录数、记录大小等,目前未使用。FPT文件包含备忘录数据。在DBF中,有类型为memo的列,该列中的信息是指向FPT文件中条目的指针 如果要查询表中的数据,只需引用备注列即可获得数据。您不需要单独解析FPT文件中的数据。OLE DB驱动程序或ODBC驱动程序(如果您的文件是VFP 6或更早版本)应该只提供此信息 有一个工具可以自动将您的Visual FoxPro数据迁移到MySQL。您可能想查看一下,看看是否可以节省一些时间: 去 并搜索Stru2MySQL_2中用于迁移数据结构的工具和VFP2MySQL数据上传程序中用于帮助迁移的工具
Rick Schummer VFP MVPFPT文件包含备忘录数据。在DBF中,有类型为memo的列,该列中的信息是指向FPT文件中条目的指针 如果要查询表中的数据,只需引用备注列即可获得数据。您不需要单独解析FPT文件中的数据。OLE DB驱动程序或ODBC驱动程序(如果您的文件是VFP 6或更早版本)应该只提供此信息 有一个工具可以自动将您的Visual FoxPro数据迁移到MySQL。您可能想查看一下,看看是否可以节省一些时间: 去 并搜索Stru2MySQL_2中用于迁移数据结构的工具和VFP2MySQL数据上传程序中用于帮助迁移的工具
Rick Schummer VFP MVP您可能还需要检查
PHP数据库库。它们可以很好地处理DBF文件。您可能还需要检查PHP数据库库。它们可以很好地处理DBF文件。我替换了以下代码:
<?
class Prodigy_DBF {
private $Filename, $DB_Type, $DB_Update, $DB_Records, $DB_FirstData, $DB_RecordLength, $DB_Flags, $DB_CodePageMark, $DB_Fields, $FileHandle, $FileOpened;
private $Memo_Handle, $Memo_Opened, $Memo_BlockSize;
private function Initialize() {
if($this->FileOpened) {
fclose($this->FileHandle);
}
if($this->Memo_Opened) {
fclose($this->Memo_Handle);
}
$this->FileOpened = false;
$this->FileHandle = NULL;
$this->Filename = NULL;
$this->DB_Type = NULL;
$this->DB_Update = NULL;
$this->DB_Records = NULL;
$this->DB_FirstData = NULL;
$this->DB_RecordLength = NULL;
$this->DB_CodePageMark = NULL;
$this->DB_Flags = NULL;
$this->DB_Fields = array();
$this->Memo_Handle = NULL;
$this->Memo_Opened = false;
$this->Memo_BlockSize = NULL;
}
public function __construct($Filename, $MemoFilename = NULL) {
$this->Prodigy_DBF($Filename, $MemoFilename);
}
public function Prodigy_DBF($Filename, $MemoFilename = NULL) {
$this->Initialize();
$this->OpenDatabase($Filename, $MemoFilename);
}
public function OpenDatabase($Filename, $MemoFilename = NULL) {
$Return = false;
$this->Initialize();
$this->FileHandle = fopen($Filename, "r");
if($this->FileHandle) {
// DB Open, reading headers
$this->DB_Type = dechex(ord(fread($this->FileHandle, 1)));
$LUPD = fread($this->FileHandle, 3);
$this->DB_Update = ord($LUPD[0])."/".ord($LUPD[1])."/".ord($LUPD[2]);
$Rec = unpack("V", fread($this->FileHandle, 4));
$this->DB_Records = $Rec[1];
$Pos = fread($this->FileHandle, 2);
$this->DB_FirstData = (ord($Pos[0]) + ord($Pos[1]) * 256);
$Len = fread($this->FileHandle, 2);
$this->DB_RecordLength = (ord($Len[0]) + ord($Len[1]) * 256);
fseek($this->FileHandle, 28); // Ignoring "reserved" bytes, jumping to table flags
$this->DB_Flags = dechex(ord(fread($this->FileHandle, 1)));
$this->DB_CodePageMark = ord(fread($this->FileHandle, 1));
fseek($this->FileHandle, 2, SEEK_CUR); // Ignoring next 2 "reserved" bytes
// Now reading field captions and attributes
while(!feof($this->FileHandle)) {
// Checking for end of header
if(ord(fread($this->FileHandle, 1)) == 13) {
break; // End of header!
} else {
// Go back
fseek($this->FileHandle, -1, SEEK_CUR);
}
$Field["Name"] = trim(fread($this->FileHandle, 11));
$Field["Type"] = fread($this->FileHandle, 1);
fseek($this->FileHandle, 4, SEEK_CUR); // Skipping attribute "displacement"
$Field["Size"] = ord(fread($this->FileHandle, 1));
fseek($this->FileHandle, 15, SEEK_CUR); // Skipping any remaining attributes
$this->DB_Fields[] = $Field;
}
// Setting file pointer to the first record
fseek($this->FileHandle, $this->DB_FirstData);
$this->FileOpened = true;
// Open memo file, if exists
if(!empty($MemoFilename) and file_exists($MemoFilename) and preg_match("%^(.+).fpt$%i", $MemoFilename)) {
$this->Memo_Handle = fopen($MemoFilename, "r");
if($this->Memo_Handle) {
$this->Memo_Opened = true;
// Getting block size
fseek($this->Memo_Handle, 6);
$Data = unpack("n", fread($this->Memo_Handle, 2));
$this->Memo_BlockSize = $Data[1];
}
}
}
return $Return;
}
public function GetNextRecord($FieldCaptions = false) {
$Return = NULL;
$Record = array();
if(!$this->FileOpened) {
$Return = false;
} elseif(feof($this->FileHandle)) {
$Return = NULL;
} else {
// File open and not EOF
fseek($this->FileHandle, 1, SEEK_CUR); // Ignoring DELETE flag
foreach($this->DB_Fields as $Field) {
$RawData = fread($this->FileHandle, $Field["Size"]);
// Checking for memo reference
if($Field["Type"] == "M" and $Field["Size"] == 4 and !empty($RawData)) {
// Binary Memo reference
$Memo_BO = unpack("V", $RawData);
if($this->Memo_Opened and $Memo_BO != 0) {
fseek($this->Memo_Handle, $Memo_BO[1] * $this->Memo_BlockSize);
$Type = unpack("N", fread($this->Memo_Handle, 4));
if($Type[1] == "1") {
$Len = unpack("N", fread($this->Memo_Handle, 4));
$Value = trim(fread($this->Memo_Handle, $Len[1]));
} else {
// Pictures will not be shown
$Value = "{BINARY_PICTURE}";
}
} else {
$Value = "{NO_MEMO_FILE_OPEN}";
}
} else {
if($Field["Type"] == "M"){
if(trim($RawData) > 0) {
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+8);
$Value = trim(fread($this->Memo_Handle, $this->Memo_BlockSize));
}
}else{
$Value = trim($RawData);
}
}
if($FieldCaptions) {
$Record[$Field["Name"]] = $Value;
} else {
$Record[] = $Value;
}
}
$Return = $Record;
}
return $Return;
}
function __destruct() {
// Cleanly close any open files before destruction
$this->Initialize();
}
}
?>
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+8);
$Value = trim(fread($this->Memo_Handle, $this->Memo_BlockSize));
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+4);
$Len = unpack("N", fread($this->Memo_Handle, 4));
$Value = trim(fread($this->Memo_Handle, $Len[1] ));
使用此代码:
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+8);
$Value = trim(fread($this->Memo_Handle, $this->Memo_BlockSize));
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+4);
$Len = unpack("N", fread($this->Memo_Handle, 4));
$Value = trim(fread($this->Memo_Handle, $Len[1] ));
这对我有帮助我替换了以下代码:
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+8);
$Value = trim(fread($this->Memo_Handle, $this->Memo_BlockSize));
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+4);
$Len = unpack("N", fread($this->Memo_Handle, 4));
$Value = trim(fread($this->Memo_Handle, $Len[1] ));
使用此代码:
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+8);
$Value = trim(fread($this->Memo_Handle, $this->Memo_BlockSize));
fseek($this->Memo_Handle, (trim($RawData) * $this->Memo_BlockSize)+4);
$Len = unpack("N", fread($this->Memo_Handle, 4));
$Value = trim(fread($this->Memo_Handle, $Len[1] ));
这对我很有帮助谢谢你的快速回答。现在我正试着用fopen和fread读取文件。我在这里面临的唯一问题是,我不知道如何将字节转换为整数。我如何将字节存储在PHP变量中?好的,我做了一些研究,发现了解包函数,它可以将原始数据转换为几种整数或其他格式。如果我能解决这个问题,我会告诉你的。否则,欢迎您提出进一步建议:谢谢您的快速回答。现在我正试着用fopen和fread读取文件。我在这里面临的唯一问题是,我不知道如何将字节转换为整数。我如何将字节存储在PHP变量中?好的,我做了一些研究,发现了解包函数,它可以将原始数据转换为几种整数或其他格式。如果我能解决这个问题,我会告诉你的。否则-欢迎进一步建议:感谢您的详细解释。我正在开发的代码大致如您所述。然而,数据似乎有问题,因为一些记录的字段比其他记录少,这意味着我无法判断记录何时开始和何时结束。你说过DBF会在FPT中识别块,你有更多的信息吗?我使用的是PHP的数据库函数,我认为它们不会返回二进制数据。。。DBF中的备注字段为空。如果为空,则不会有与该条目相关联的备注内容。但是,为备注字段分配的字段字节始终为4字节。如果它有一个值,它将是解析,正如我所描述的指向.FPT文件中的块。感谢您的详细解释。我正在开发的代码大致如您所述。然而,数据似乎有问题,因为一些记录的字段比其他记录少,这意味着我无法判断记录何时开始和何时结束。你说过DBF会在FPT中识别块,你有更多的信息吗?我使用的是PHP的数据库函数,我认为它们不会返回二进制数据。。。DBF中的备注字段为空。如果为空,则不会有与该条目相关联的备注内容。但是,为备注字段分配的字段字节始终为4字节。如果它有一个值,它将是解析,正如我所描述的,指向.FPT文件中的块。是的,您可以使用dbase函数轻松地读取它们,但我发现这些函数不显示备忘录字段中的数据,这些字段很可能存储在单独的文件中。这就是为什么我编写了自己的类,它可以自动读取相应的备忘录文件。是的,您可以使用dbase函数轻松地读取它们,但我发现这些函数不显示备忘录字段中的数据,这些字段很可能存储在单独的文件中。这就是为什么我写了我自己的类,可以自动读取相应的备忘录文件。你解决你的问题了吗?如果是,您修改了哪些行?是的..解决了我的问题。。。。。。。更改此$Value=trim$RawData;到下面。。。这里我添加了:如果$Field[Type]==M{iftrim$RawData>0{fseek$this->Memo_句柄,trim$RawData*$this->Memo_BlockSize+8;$Value=trimfrad$this->Memo_句柄,$this->Memo_BlockSize;}否则{$Value=trim$RawData;}rite做对了吗?但是我解决了我的问题你解决了你的问题吗?如果是,您修改了哪些行?是的..解决了我的问题。。。。。。。更改此$Value=trim$RawData;到下面。。。这里我添加了:如果$Field[Type]==M{iftrim$RawData>0{fseek$this->Memo_句柄,trim$RawData*$this->Memo_BlockSize+8;$Value=trimfrad$this->Memo_句柄,$this->Memo_BlockSize;}否则{$Value=trim$RawData;}rite做对了吗?但是我解决了我的问题。这是上面这个类的一个编辑版本,它也支持dBase 7级DBF格式。下面是上述类的编辑版本,它还支持dBase级别7 DBF格式。