2

如何解锁或删除正在使用的文件,以便删除它?有问题的文件由我自己的应用程序使用。

更具体地说,我的应用程序使用的是免费软件 Zeos Lib。打开和保存我的数据库时,sqlite3.dll 文件必须与我的应用程序位于同一目录中才能正常工作。

我希望我的应用程序是 100% 独立的,所以我将 sqlite3.dll 作为 RC_DATA 添加到我的项目中,并且每当我需要使用它(即打开或保存数据库)时,我将它提取到与我的应用程序相同的文件夹中. 一旦打开或保存操作完成,我想删除 sqlite3.dll 文件,甚至没有人知道它在那里或者不必担心缺少库等。(虽然我可以理解你们中的一些人可能不喜欢将库存储在应用程序中的想法,我有这样做的理由:我不希望我的最终用户知道我的应用程序 (SQL) 的功能背后是什么,他们也不需要担心缺少动态链接库。)

问题是,我可以成功提取 sqlite3.dll 并将其用于我的操作,但该文件被我的应用程序锁定(直到我关闭我的应用程序),这让我:

  1. 强制解锁 sqlite3.dll 文件,而不关闭我的应用程序

  2. 强制删除 sqlite3.dll 文件

除非当然有其他建议?

这是提取和使用它的示例。我不需要直接调用诸如 LoadLibrary 等;Zeos Lib 单元必须注意这一点,只要 sqlite3.dll 与应用程序位于同一目录中。

procedure ExtractResource(ResName: String; Filename: String);
var
  ResStream: TResourceStream;
begin
  ResStream:= TResourceStream.Create(HInstance, ResName, RT_RCDATA);
  try
    ResStream.Position:= 0;
    ResStream.SaveToFile(Filename);
  finally
    ResStream.Free;
  end;
end;

//Open procedure
var
  sFileName: String = ExtractFilePath(ParamStr(0)) + 'Sqlite3.dll';    

if OpenDialog1.Execute then
begin
  ExtractResource('RES_SQLITE3', sFileName);
  ... //process my database
  ...
  ... // finished opening database
  if FileExists(sFileName) then
        DeleteFile(sFileName);
end;

编辑

我认为我试图做的不是很实用,这不是一个好主意,正如 STATUS_ACCESS_DENIED 之前评论的那样。我已经决定最好不要继续我打算做的事情。

4

6 回答 6

2

您应该更好地使用SQLite3 引擎的静态链接,而不是依赖外部 dll。通过将 .obj 包含到您的 .dcu SQLite3 单元中。

它还将添加一些不错的功能,例如使用 FastMM4 作为 SQlite3 引擎的内存管理器的能力(加速),以及潜在的一些不错的低级功能(如加密)。

参见例如:

于 2011-05-17T07:54:00.727 回答
1

很简单,不要这样做。文件被锁定是有原因的。通常这是一个很好的理由,例如某些其他进程(甚至您自己的)仍在使用它。找出是什么使文件保持锁定状态(例如,使用 Process Explorer),只要它是您的进程,请确保您释放了所有内容。例如FreeLibrary之后LoadLibrary等...

如果您绝对必须删除该文件,请尝试DeleteFile在失败时调用MoveFileExMOVEFILE_DELAY_UNTIL_REBOOT在重新启动时删除该文件。

您可以让另一个MoveFileMoveFileEx介于两者之间的文件在使用时“重命名”文件(这通常适用于同一个分区)。但这仅在您依赖文件名时才有必要,因此如果旧的(锁定的)陈旧文件仍然存在,则程序的另一个实例可能会被阻止。

一些方法可以做你想做的事,但它们不应该以发布给最终用户的代码而告终。它基本上归结为黑客,例如 - 使用注入的线程来关闭/解锁实体中的文件,这些文件将它们锁定。但这是不好的形式。尽量避免它。

于 2011-05-16T17:30:07.547 回答
0

虽然您无法删除正在使用的文件,但您可以重命名它。只需将 dll 重命名为 SQLITE3.DELETE.guid 之类的名称即可。在启动时,您可以让您的应用程序尝试删除任何 sqlite.delete.* 文件,以便在文件释放后它会消失。-大学教师

于 2011-05-16T17:24:17.080 回答
0

看起来LibraryLoaderZPlainSqLite3.pas 中的内容正在加载 DLL。在尝试删除 DLL 之前,您可以尝试从 finalization 部分运行代码:

  if Assigned(LibraryLoader) then
     LibraryLoader.Free;
于 2011-05-16T17:45:30.347 回答
0

您应该首先确保该文件未仍在使用中。在您的情况下,它仍在使用中,因为数据库库加载了 DLL 并且尚未释放它。由于您已经与数据库断开连接,它可能还没有处于活动状态,但操作系统不知道——如果加载了 DLL,操作系统会假定它仍然需要并不允许删除。

当您连接到数据库时,Zeos 会找到相应的数据库驱动程序(在本例中TZSQLiteDriver,来自ZDbcSqLite.pas)并要求它加载其功能。但是当您断开与数据库的连接时,Zeos 不会要求数据库驱动程序卸载其功能。这在一个典型的程序中是浪费的,在程序的生命周期中可能会建立和销毁多个连接。

如果您确定没有与数据库的打开连接,您可以自己卸载这些函数。SQLite 的加载器位于ZPlainSqLite3.pas中。尽管您可以完全释放 loader 对象,但这可能会在以后引起问题,因为 Zeos 的其他部分希望它在需要时仍然存在。相反,只需告诉它卸载:

ZPlainSqLite3.Loader.FreeNativeLibrary;

这会导致对象设置标志指示它已卸载,因此如果您需要再次使用它,它将重新加载所有内容。


如果您真的想变得花哨,您可以尝试编写自己的TZNativeLibraryLoader后代,在加载时自动从资源中获取 DLL,并在卸载时删除文件。那么您就无需担心程序其余部分的数据库连接生命周期了。您可以像其他人一样连接和断开连接。

于 2011-05-16T17:51:21.203 回答
0

有几个可用的解决方案允许您将 SQLite 库编译您的 exe 中,而不是使用 DLL。如果您确实必须拥有一个可执行文件,我认为这将是一种更好的方法。你基本上试图通过提取/删除 DLL 来复制的是安装程序的功能,你真的不应该。这种方法只是寻求支持问题。

另请记住,您的应用程序可能需要以管理员权限运行才能提取 dll 并将其保存到程序文件目录中。

如果您可以忍受与可执行文件一起安装的 DLL,您可以将 DLL 文件重命名为其他文件(即 Database.dll),并在 zeos 代码中进行更改,使其指向新的 DLL 名称。然后 SQLite 功能不会立即显现出来。

于 2011-05-17T05:36:45.677 回答