How to solve [FireDAC][Phys][SQLite] ERROR: unable to open database file, When app is installed in programFiles?
How to solve [FireDAC][Phys][SQLite] ERROR: unable to open database file, When app is installed in programFiles?
我开发了一个使用 Firedac 的工具,数据库为 SQLite。
完成项目并制作安装程序 (InnoSetup) 后出现错误
[FireDAC][Phys][SQLite] ERROR: unable to open database file
当我启动应用程序时(双击)。
这是我使用的连接参数
constructor TDbInteract.Create(const aDatabasePath: string; const aOnNeedCredentials: TOnNeedCredentials);
var
aParams: array of string;
begin
if not TFile.Exists(aDatabasePath) then
raise Exception.Create('Database file not found');
aParams := ['DriverID=SQLite',
'Database=' + aDatabasePath,
'OpenMode=CreateUTF16',
'LockingMode=Normal',
'JournalMode=WAL',
'StringFormat=Unicode',
'Synchronous=Full',
'UpdateOptions.LockWait=True',
'BusyTimeout=30000',
'SQLiteAdvanced=temp_store=MEMORY;page_size=4096;auto_vacuum=FULL'];
InitiateResource(aParams, aOnNeedCredentials);
end;
procedure TDbInteract.InitiateResource(const aParams: array of string; const aOnNeedCredentials: TOnNeedCredentials);
var
I: Integer;
Credentials: TStringDynArray;
begin
FRowsAffected := 0;
FIsForeignKeyHonored := True;
FOwnsResultDataSets := True;
FDataSetContainer := TDataSetContainer.Create(nil);
FConnection := TFDConnection.Create(nil);
try
for I := Low(aParams) to High(aParams) do
begin
FConnection.Params.Add(aParams[I]);
end;
if Assigned(aOnNeedCredentials) then
begin
aOnNeedCredentials(Self, Credentials);
for I := Low(Credentials) to High(Credentials) do
begin
FConnection.Params.Add(Credentials[I]);
end;
end;
FConnection.Open;
except
raise;
end;
end;
**发现的问题:
- 我在某处读到(不记得我所在的页面)SQLite 引擎需要完全锁定它要写入的目录。这就是问题所在。我如何 运行 该工具作为调用者并且我的帐户是管理员,所以这不是问题。我也有用 c# 编写的相同工具,但这个问题从未发生过。
我找到的解决方案:
- 运行管理员身份的工具
- 不要在 ProgramFiles 目录中安装该工具
我真的不喜欢这些解决方案。并希望 运行 我的工具来自程序文件目录,因为它是一个更大项目的一部分。
注意:数据库文件在programdata目录下。它是由工具创建的(有效)。
编辑: 我刚刚尝试将 DB 文件放在 C:\Users\Nacereddine\AppData\Roaming\MyTool
中,当工具安装在 C:\Program Files (x86)\MyTool
[= 中时,我仍然遇到同样的问题15=]
这是我创建数据库文件的方式
class procedure TDbInteract.CreateSQLiteDb(const aDatabasePath: string; const aTables: TStringDynArray);
var
I: Integer;
aParams: array of string;
aConnection: TFDConnection;
begin
aParams := ['DriverID=SQLite',
'Database=' + aDatabasePath,
'OpenMode=CreateUTF16',
'LockingMode=Normal',
'JournalMode=WAL',
'StringFormat=Unicode',
'Synchronous=Full',
'UpdateOptions.LockWait=True',
'BusyTimeout=30000',
'SQLiteAdvanced=temp_store=MEMORY;page_size=4096;auto_vacuum=FULL'];
aConnection := TFDConnection.Create(nil);
try
for I := Low(aParams) to High(aParams) do
begin
aConnection.Params.Add(aParams[I]);
end;
aConnection.Open();
for I := Low(aTables) to High(aTables) do
begin
aConnection.ExecSQL(aTables[I]);
end;
finally
aConnection.Close;
aConnection.Free;
end;
end;
注意:我不知道这是否有任何区别,但 Db 文件已加密。
抱歉给大家带来麻烦了。
问题是我们在 ProgramFiles 中使用该工具安装了本地化 db 文件。
让我将其排除在调查之外的原因是,在打开此文件时,我将 OpenMode
设置为 ReadOnly
FConnection.Params.Add('OpenMode=ReadOnly');
但正如我之前在我的问题中所说,SQLite 引擎需要对包含 db 文件的文件夹的完全访问权限,因此它会对其进行锁定(仍然没有找到我阅读这篇文章的页面)。
我通过尝试打开模式并每次调试该工具来检查这一点。
一旦我更改了文件和目录的权限,错误就消失了。
最后我决定将本地化文件与主 db 文件一起移动到 programData 目录,一切都很好。
我意识到(感谢@Ken 和@David)programData 目录也需要管理员权限才能写入,因此我会将 db 文件移动到更合适的目录(即用户)。
这个问题的有用之处在于,即使您使用 OpenMode=ReadOnly
连接到 Sqlite 数据库文件,您仍然需要对该文件的路径进行写访问。
我开发了一个使用 Firedac 的工具,数据库为 SQLite。
完成项目并制作安装程序 (InnoSetup) 后出现错误
[FireDAC][Phys][SQLite] ERROR: unable to open database file
当我启动应用程序时(双击)。
这是我使用的连接参数
constructor TDbInteract.Create(const aDatabasePath: string; const aOnNeedCredentials: TOnNeedCredentials);
var
aParams: array of string;
begin
if not TFile.Exists(aDatabasePath) then
raise Exception.Create('Database file not found');
aParams := ['DriverID=SQLite',
'Database=' + aDatabasePath,
'OpenMode=CreateUTF16',
'LockingMode=Normal',
'JournalMode=WAL',
'StringFormat=Unicode',
'Synchronous=Full',
'UpdateOptions.LockWait=True',
'BusyTimeout=30000',
'SQLiteAdvanced=temp_store=MEMORY;page_size=4096;auto_vacuum=FULL'];
InitiateResource(aParams, aOnNeedCredentials);
end;
procedure TDbInteract.InitiateResource(const aParams: array of string; const aOnNeedCredentials: TOnNeedCredentials);
var
I: Integer;
Credentials: TStringDynArray;
begin
FRowsAffected := 0;
FIsForeignKeyHonored := True;
FOwnsResultDataSets := True;
FDataSetContainer := TDataSetContainer.Create(nil);
FConnection := TFDConnection.Create(nil);
try
for I := Low(aParams) to High(aParams) do
begin
FConnection.Params.Add(aParams[I]);
end;
if Assigned(aOnNeedCredentials) then
begin
aOnNeedCredentials(Self, Credentials);
for I := Low(Credentials) to High(Credentials) do
begin
FConnection.Params.Add(Credentials[I]);
end;
end;
FConnection.Open;
except
raise;
end;
end;
**发现的问题:
- 我在某处读到(不记得我所在的页面)SQLite 引擎需要完全锁定它要写入的目录。这就是问题所在。我如何 运行 该工具作为调用者并且我的帐户是管理员,所以这不是问题。我也有用 c# 编写的相同工具,但这个问题从未发生过。
我找到的解决方案:
- 运行管理员身份的工具
- 不要在 ProgramFiles 目录中安装该工具
我真的不喜欢这些解决方案。并希望 运行 我的工具来自程序文件目录,因为它是一个更大项目的一部分。
注意:数据库文件在programdata目录下。它是由工具创建的(有效)。
编辑: 我刚刚尝试将 DB 文件放在 C:\Users\Nacereddine\AppData\Roaming\MyTool
中,当工具安装在 C:\Program Files (x86)\MyTool
[= 中时,我仍然遇到同样的问题15=]
这是我创建数据库文件的方式
class procedure TDbInteract.CreateSQLiteDb(const aDatabasePath: string; const aTables: TStringDynArray);
var
I: Integer;
aParams: array of string;
aConnection: TFDConnection;
begin
aParams := ['DriverID=SQLite',
'Database=' + aDatabasePath,
'OpenMode=CreateUTF16',
'LockingMode=Normal',
'JournalMode=WAL',
'StringFormat=Unicode',
'Synchronous=Full',
'UpdateOptions.LockWait=True',
'BusyTimeout=30000',
'SQLiteAdvanced=temp_store=MEMORY;page_size=4096;auto_vacuum=FULL'];
aConnection := TFDConnection.Create(nil);
try
for I := Low(aParams) to High(aParams) do
begin
aConnection.Params.Add(aParams[I]);
end;
aConnection.Open();
for I := Low(aTables) to High(aTables) do
begin
aConnection.ExecSQL(aTables[I]);
end;
finally
aConnection.Close;
aConnection.Free;
end;
end;
注意:我不知道这是否有任何区别,但 Db 文件已加密。
抱歉给大家带来麻烦了。
问题是我们在 ProgramFiles 中使用该工具安装了本地化 db 文件。
让我将其排除在调查之外的原因是,在打开此文件时,我将 OpenMode
设置为 ReadOnly
FConnection.Params.Add('OpenMode=ReadOnly');
但正如我之前在我的问题中所说,SQLite 引擎需要对包含 db 文件的文件夹的完全访问权限,因此它会对其进行锁定(仍然没有找到我阅读这篇文章的页面)。
我通过尝试打开模式并每次调试该工具来检查这一点。 一旦我更改了文件和目录的权限,错误就消失了。
最后我决定将本地化文件与主 db 文件一起移动到 programData 目录,一切都很好。
我意识到(感谢@Ken 和@David)programData 目录也需要管理员权限才能写入,因此我会将 db 文件移动到更合适的目录(即用户)。
这个问题的有用之处在于,即使您使用 OpenMode=ReadOnly
连接到 Sqlite 数据库文件,您仍然需要对该文件的路径进行写访问。