【问题标题】:Cross Referencing Data Written to a text file with a existing Database in Delphi?在 Delphi 中使用现有数据库将交叉引用数据写入文本文件?
【发布时间】:2014-05-24 18:45:27
【问题描述】:

我正在尝试使用现有数据库 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 的新手 :)

【问题讨论】:

  • 请更新您的问题并解释“交叉引用”的含义(例如文本文件/数据库数据)。并请使用一些点来分隔句子。
  • “交叉引用”是什么意思?什么数据库? (您的代码中没有任何迹象。)您能否edit 您的问题更清楚地说明您在问什么?一些标点符号、适当的大写字母和分段符会让您在阅读时更容易阅读。谢谢。
  • OP:its just the Name in the first line,真的吗?那你为什么要找,iPosComma:=Pos(',',Sline);!!
  • 您的编辑添加的信息很少。 // This is where I want to add code?伟大的。您应该在此时添加代码。您还没有解释“数据库”进入事物的位置,或者您所说的“交叉引用”是什么意思。 (实际上,你又添了一点困惑——“我还没有把它联系起来”是什么意思?
  • @KenWhite 我还是新手,所以请不要太苛刻我只想将 Access 数据库表连接到应用程序并让一段代码读取文本的内容文件并检查数据库中是否已经存在这些值,如果它们存在,它将返回一条错误消息,说明用户已经存在,否则它将把文本文件中的新数据写入数据库,这是它背后的逻辑我只是不确定如何实现它希望这更有意义知道

标签: database delphi delphi-7


【解决方案1】:

我从您的问题中了解到,您目前正试图检查数据库中是否存在特定记录。我会非常简短地回答这个问题,因为这个网站上有很多类似的问题可以帮助你充实细节。

但是,您的问题标题询问“交叉引用数据写入具有现有数据库的文本文件”。从描述中听起来好像您正在尝试协调来自两个来源的数据并找出匹配的内容和不匹配的内容。我会花更多时间来回答这个问题,因为我认为会有更多有价值的信息。


要检查数据库中的数据,您需要:

  • 您配置为指向您的数据库的连接组件。
  • 链接到连接组件的查询组件。
  • 查询文本将使用 SQL 语句从数据库中的特定表中选择行。
  • 我建议您对查询进行参数化,以专门选择您要查找的行(我稍后会解释原因。)
  • 注意:您可以使用表格组件而不是查询组件,这将改变您检查现有行的方式。它的优点是您不需要编写 SQL 代码。但编写良好的 SQL 将更具可扩展性。

以上选项因您使用的数据库和组件而异。但正如我所说,已经有很多类似的问题。通过一些研究,您应该能够弄清楚。

如果您遇到困难,您可以提出更具体的问题,详细说明您尝试过的方法和无效的方法。 (请记住,这不是免费的“为你服务”,如果看起来像你所期望的那样,你会受到强烈反对。)


在文本文件和数据库之间协调数据:

有几种不同的方法。你选择的那个是完全可以接受的。基本上可以归结为:

  1. 对于TheFile 中的每个Entry
  2. .. 如果Entry 存在于TheDatabase
  3. .. .. 用Entry 做点什么
  4. .. .. 否则用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;

提示:在数据库中的适当列上定义索引非常重要,否则每次打开查询时,它也会搜索每条记录。

注意:另一个非常相似的选项是在数据库上编写存储过程,并使用存储过程组件来调用数据库。


其他 cmets:

您处理文件的例程被硬编码为使用register.txt

这使得它在当前形式下不可重用。而是将代码移动到一个单独的方法中:procedure ProcessFile(AFileName: string);。然后在您的按钮单击事件处理程序中调用:ProcessFile('register.txt');

提示:事实上,将大量代码从事件处理程序中移出到带有适当参数的方法中通常是个好主意。更改您的事件处理程序以调用这些方法。这样做将使您的代码更易于维护、测试和重用。

你的异常处理有误

这是一种非常糟糕的异常处理方式。

首先,您永远不想编写不必要的异常处理。它只会使您的代码膨胀,使其更难以阅读和维护。引发异常时:

  • 程序开始将代码退出到最里面的 finally/except 块。 (因此异常会退出您的例程 - 正如您添加的代码一样。)
  • 默认情况下,应用程序异常处理程序将处理未处理的异常(意味着您尚未在某处吞下的异常)。默认情况下,这只会显示一个错误对话框。 (正如您添加的代码一样。)
  • 您的代码所做的唯一更改是显示与实际引发的消息不同的消息。问题是您做出了错误的假设。 “文件不存在”不是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 中引发异常并且您吞下(处理)它,则上述例程将删除未处理的文件。这显然会很糟糕。如果您没有吞下异常,上述例程将跳过删除步骤,因为程序正在寻找下一个 finally/except 块。至少这样,一旦问题解决,您仍然有文件的记录,以便进行故障排除和重新处理。

第三个问题是您的异常处理程序假设您的例程将始终与用户进行交互。这限制了可重用性,因为如果您现在在服务器端应用程序中调用 ProcessFile,则会弹出一个对话框,没有人可以关闭它。

将未解决的异常留给应用程序异常处理程序处理意味着您只需要更改服务器应用程序中的默认应用程序异常处理程序,所有异常都可以记录到文件中 - 而不会弹出对话框。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-27
    • 1970-01-01
    • 2013-09-12
    • 2010-12-25
    • 1970-01-01
    相关资源
    最近更新 更多