我试图交叉引用写入文本文件的数据使用现有数据库IE(检查写入文本文件的数据是否已存在于数据库中)。
我已经创建了将用户登录数据(名称和密码)写入文本文件的程序,然后我开始编写一个算法来从文本文件中读取数据,但是我有点卡住了我的名字存储在文本文件的第一行和密码(仅限字符串值)存储在下一行。
我不知道如何检查数据是否已存在于数据库中,是否需要先提取数据库的内容?或者你可以直接与数据库交叉引用它?我已经创建了数据库(UserData.accdb),但我尚未将其链接到表单。这就是我到目前为止所做的:
procedure TForm1.btnclickClick(Sender: TObject);
var
tRegister : TextFile;
Sline : String;
Sname,SPword : String;
begin
Assignfile(tRegister,'register.txt');
Try
Reset(tRegister);
except
Showmessage('File Register.txt does not exist');
Exit;
end;
While not EOF(tRegister) do
ReadLn(tRegister,Sline);
Sname:=Copy(Sline);
// This is where i want to add code
end;
end;
end.
请不要苛刻我仍然是Delphi的新手:)
答案 0 :(得分:1)
我从您的问题中了解到,您目前仍在尝试检查数据库中是否存在特定记录。我会非常简短地回答这个问题,因为这个网站上有很多类似的问题可以帮助你充实细节。
然而,您的问题的标题询问"交叉引用数据写入具有现有数据库的文本文件"。从描述中可以看出,您似乎正在尝试协调来自两个来源的数据,并确定哪些匹配,哪些不匹配。我会花更多的时间来回答这个问题,因为我认为这些信息会更有价值。
上述选项因数据库和您正在使用的组件而异。但正如我所说,已有许多类似的问题。通过一些研究,你应该能够弄明白。
如果您遇到问题,可以提出一个更具体的问题,详细说明您尝试过的内容以及哪些内容无效。 (请记住,这不是免费的"为您的服务做好工作",如果看起来像是您期待的,您会得到反对。 )
有几种不同的方法。你选择的那个是完全可以接受的。基本上归结为:
Entry
TheFile
Entry
TheDatabase
Entry
Entry
以上步骤易于理解,因此很容易确信算法是正确的。如果Delphi中没有单行代码来实现这些步骤并不重要。作为程序员,您可以创建所需的任何其他功能/程序。 例程的结构保持简单是非常重要的。
上述任何不能轻易实现的步骤,您需要分解为更小的步骤:2.a。 2.B. ; 3.A. 3.B. 3.C. ;等等(这就是自上而下的设计。)
提示:您希望将所有不同的细分转换为自己的功能和程序。这将使维护您的程序并重复使用已经编写的程序更加容易。
我将专注于分解第2步。如果您的数据库和文本文件变得非常大,那么如何执行此操作非常重要。例如,您可以实现:每次调用函数检查"如果Entry
存在",它会查看数据库中的每条记录。这将非常糟糕,因为如果您的文件中有m
个条目,而数据库中有n
个条目,那么您将进行m x n
次检查。
记得我说过我解释为什么我建议参数化查询?
设计和编写数据库以管理数据。存储和检索数据是它们的主要功能,因此让它来查找您正在寻找的条目是否存在。例如,如果您编写了查询以将所有条目提取到Delphi应用程序中并在那里搜索:
m x n
问题中。使用参数化查询,每次调用if EntryExists(...)
时,您都可以更改参数值并有效地要求数据库查找记录。数据库完成工作,并给你一个答案。所以你可以编写你的函数,如下所示:
function TForm1.EntryExists(const AName: string): Boolean;
begin
qryFindEntry.Close;
qryFindEntry.Parameters.ParamByName('EntryName').Value := AName;
qryFindEntry.Open;
Result := qryFindEntry.RecordCount > 0;
end;
提示:在数据库中的相应列上定义索引非常重要,否则每次打开查询时,它都会搜索每条记录。
注意:另一个非常相似的选项是在数据库上编写存储过程,并使用存储过程组件来调用数据库。
处理文件的例程硬编码为使用register.txt
这使得它目前的形式无法重复使用。而是将代码移动到单独的方法中:procedure ProcessFile(AFileName: string);
。然后在按钮单击事件处理程序调用:ProcessFile('register.txt');
。
提示:事实上,将代码批量从事件处理程序中移出到具有适当参数的方法中通常是个好主意。更改事件处理程序以调用这些方法。这样做可以使您的代码更易于维护,测试和重用。
您的异常处理错误
这是一种非常糟糕的异常处理方法。
首先,您不想编写不必要的异常处理。它只会使您的代码膨胀,使其更难以阅读和维护。引发异常时:
Reset(tRegister);
可能引发异常的唯一可能原因:
如果您想提供有关该例外的更多信息,以下是更好的方法:
try
Reset(tRegister);
except
on E: Exception do
begin
//Note that the message doesn't make any assumptions about the cause of the error.
E.Message := 'Unable to open file "'+AFileName+'": ' + E.Message;
//Reraise the same exception but with extra potentially useful information.
raise;
end;
end;
第二个问题是,即使您告诉用户该错误,您也已将此事实隐藏在程序的其余部分中。我们假设您发现了ProcessFile
方法的更多用途。你现在有一个例程:
如果在ProcessFile
中引发异常并且您吞下(处理)它,则上述例程将删除未处理的文件。这显然是不好的。如果您没有吞下该异常,则上述例程将跳过删除步骤,因为该程序正在寻找下一个最终 / 除块之外。至少通过这种方式,一旦问题得到解决,您仍然可以记录文件以进行故障排除和重新处理。
第三个问题是您的异常处理程序正在假设您的例程总是让用户与之交互。这限制了可重用性,因为如果您现在在服务器端应用程序中调用ProcessFile
,则会弹出一个对话框,没有人关闭它。
让未解决的异常由应用程序异常处理程序处理意味着您只需要更改服务器应用程序中的默认应用程序异常处理程序,并且所有异常都可以记录到文件中 - 而不会弹出对话框。