我尝试使用Delphi阅读.MEM file。它是FoxPro内存变量文件。我尝试使用TFileStream读取并加载到TStringList中。但是,它只返回第一个单词。
F := TFileStream.Create(sFile, fmOpenRead);
L := TStringList.Create;
try
F.Position := 0;
L.LoadFromStream(F);
ShowMessage(L.Text);
finally
F.Free;
L.Free;
end;
原因是因为我想将一些有用的.MEM值从旧程序迁移到我的新程序。谢谢你的帮助。
答案 0 :(得分:1)
如果它是一次性事件并且您可以访问VFP安装 - 即IDE,而不仅仅是运行时 - 那么David Heffernan的建议肯定是最明智的方式。在这种情况下,您可以通过
加载和检查.MEMrelease all extended && to clear away all existing memvars
restore from foo && assuming the file in question is named FOO.MEM
activate window Locals && inspect the variables...
list memory to foo && or list them to FOO.TXT
modify file foo.txt
但是,LIST MEMORY
(和DISPLAY MEMORY
)还包括所有系统变量 - 以下划线开头的东西 - 需要解析。
如果这是一个持续的事情 - 必须重复进口 - 而且你知道你需要哪些变量,那么有两种相当干净和简单的方法。
第一个仅在运行Delphi程序的计算机上安装了VFP IDE时才有效。在这种情况下,您可以从Delphi实例化VFP(保持不可见),让它读取.MEM然后查询单个变量:
procedure fetch_variables_from_MEM (mem_filename: string; var_list: CFoos);
var
fox: Variant;
foo: CFoo;
begin
fox := CreateOleObject('VisualFoxpro.Application.9');
try
fox.DoCmd('release all extended');
fox.DoCmd('restore from ' + mem_filename);
for foo in var_list do
foo.Value := fox.Eval('m.' + foo.Name);
finally
fox.Quit; // AutoQuit not supported
end;
end;
我掩盖了一些细节,比如在调用它之前需要在某个地方调用CoInitialize()
,我假设了变量列表的合适定义(假设的CFoo对象的列表/集合),但是草绘的轮廓工作 - 即使在64位Delphi中。
优势在于,日期时间值之类的东西因为COM基础设施和变体的使用而以TDateTime形式出现。
第二种简单方法适用于在使用Delphi程序的机器上没有IDE但您可以访问某个IDE的地方,以便您可以构建一个小型COM服务器:
define class FoxWrapper as custom olepublic
function Eval (cExpression as string) as variant
return evaluate(m.cExpression)
procedure DoCmd (cCommand as string)
&cCommand
enddefine
然后可以使用它来代替" VisualFoxPro.Application.9"在上面的例子中。注意:对于64位Delphi,您需要将其构建为进程外服务器(即EXE)。此外,这可能会违反VFP许可条件。
为了直接访问数据,这里有一些快速的&我编写的一些FoxPro的东西,我之前编码并为VFP9更新的脏的Delphi代码。这是原理验证代码,为了说明,简化了数组处理和其他妥协;它缺乏Delphi的半语言定义和季度运行时所需的所有生产质量噪声。
type
TMEMVarHeader = packed record
var_name: array [0..10] of AnsiChar;
mem_type: AnsiChar; // 0ACDHLNOQYacdhlnoqy
big_size: UInt32; // only if mem_type == 'H'
width : Byte; // special meaning if mem_type == 'H'
decimals: Byte;
padding : array [0..13] of Byte; // 0 0 0 0 0 0 0 3 0 0 0 0 0 0
end;
SizeOf_TMEMVarHeader_eq_32 = true .. SizeOf(TMEMVarHeader) = 32;
TMEMVarInfo = record
header: TMEMVarHeader;
null_t: AnsiChar;
name : AnsiString;
value : Variant;
function ReadFromStream (stream: TStream): Boolean; // false if EOF
end;
function TMEMVarInfo.ReadFromStream (stream: TStream): Boolean;
const
DELPHI_EPOCH = 2415019.0;
var
header_bytes_read: Integer;
name_length: UInt16;
text_length: UInt32;
array_dim_1: UInt16;
array_dim_2: UInt16;
d: TDate; // 64-bit double
l: Boolean;
n: Double; // 64-bit double
q: array of Byte;
c: AnsiString;
t: TDateTime; // 64-bit double
y: Int64;
binary: Boolean;
i: Cardinal;
a: array of Variant;
v: TMEMVarInfo;
begin
name := ''; value := Unassigned;
header_bytes_read := stream.Read(header, SizeOf(header));
if header_bytes_read <> Sizeof(header) then begin
if not ((header_bytes_read = 1) and (header.var_name[0] = #26)) then
raise Exception.Create('unexpected MEM file format (problem reading header)');
result := false; // EOF
EXIT;
end;
result := true;
// variable name
if header.var_name[0] = #0 then begin // long variable name
assert(header.mem_type = LoCase(header.mem_type));
stream.ReadBuffer(name_length, Sizeof(name_length));
SetLength(name, name_length);
stream.ReadBuffer(name[1], name_length);
end else begin
assert(header.mem_type = UpCase(header.mem_type));
name := header.var_name;
end;
// variable value
case UpCase(header.mem_type) of
'A':
begin
stream.ReadBuffer(array_dim_1, SizeOf(array_dim_1));
stream.ReadBuffer(array_dim_2, SizeOf(array_dim_2));
if array_dim_2 = 0 then // it's a vector, not an array
array_dim_2 := 1;
SetLength(a, array_dim_1 * array_dim_2);
for i := 0 to array_dim_1 * array_dim_2 - 1 do begin
if not v.ReadFromStream(stream) then
raise Exception.Create('error reading array element');
a[i] := v.value;
end;
value := a;
end;
'0': begin stream.ReadBuffer(null_t, 1); value := Null; end;
'C', 'H', 'Q':
begin
if UpCase(header.mem_type) = 'H' then begin // length > 254
binary := header.width <> 0;
text_length := header.big_size;
end else begin
binary := UpCase(header.mem_type) = 'Q';
text_length := header.width;
end;
if binary then begin
SetLength(q, text_length); stream.ReadBuffer(q[0], text_length); value := q;
end else begin
SetLength(c, text_length); stream.ReadBuffer(c[1], text_length); value := c;
end;
end;
'D': begin stream.ReadBuffer(d, Sizeof(d)); if d > 0 then d := d - DELPHI_EPOCH; VarCast(value, d, varDate); end;
'L': begin stream.ReadBuffer(l, Sizeof(l)); value := l; end;
'N': begin stream.ReadBuffer(n, Sizeof(n)); value := n; end;
'T': begin stream.ReadBuffer(t, Sizeof(t)); if t > 0 then t := t - DELPHI_EPOCH; value := t; end;
'Y': begin stream.ReadBuffer(y, Sizeof(y)); VarCast(value, y / 10000.0, varCurrency); end;
else
raise Exception.Create('unexpected type ''' + header.mem_type + ''' in MEM file');
end;
end;
要阅读.MEM,请创建TFileStream
和TMEMVarInfo
变量,然后逐个读取变量,直到var_info.ReadFromStream(stream)
返回false
。
注意:偏移19h处的字节(在结构注释中显示为3)是代码页标识符。值与those found in .DBF headers相同,即DOS 437为1,Windows 1252为3,依此类推。但是,即使VFP在编写.MEM时存储了这些标识符,但在加载.MEM时,我测试的所有较新版本的VFP 都会完全忽略这些代码页标记。但是,自编的导入程序可以很好地使用代码页标记。
答案 1 :(得分:-1)
读取二进制.mem文件不是正确的继续方法。正确的解决方案是让VFP导出数据。它知道如何阅读它。获取VFP以导出为已知格式,然后阅读。这是数据迁移的标准方法。