TFileStream.Create 使用某些设备语言在 iOS 上失败
TFileStream.Create fails on iOS with certain device languages
当我将 iOS 设备设置为例如越南语,那么下面的代码会失败sometimes:
var
lFilePath: String
...
lFilePath := TPath.GetTempPath + '/MyDBfile.db';
lFileStream := TFileStream.Create(lFilePath, fmOpenReadWrite or fmShareExclusive or fmCreate);
TFileStream.Create 调用引发断言:"EFCreateError: Cannot create file "/private/var/mobile/Containers/Data/Application/{containerID}/tmp/MyDBfile.db"
没有这样的文件或目录。
只有当设备设置为某些语言(包括越南语)时,断言才不会在西欧语言中出现。
我将创建代码追溯到 System.SysUtils
中 FileCreate
函数的这一行:
FileHandle := Integer(__open(M.AsAnsi(FileName, CP_UTF8).ToPointer,
O_RDWR or O_CREAT or O_TRUNC or Exclusive[(Mode and [=13=]04) shr 2], Rights));
引发断言时文件句柄为 -1。
有什么问题吗?
PS:为了弄清楚发生了什么,我添加了一个 Fileexists
调用:
lFilePath := TPath.GetTempPath + '/MyDBfile.db';
if Fileexists(lFilePath) then
System.Sysutils.DeleteFile(lFilePath);
lFileStream := TFileStream.Create(lFilePath, fmOpenReadWrite or fmShareExclusive or fmCreate);
现在,在代码失败的情况下,我有以下奇怪的发现:
在XCode中,可以显示App的Container,显示Container中的文件tmp/MyDBfile.db
,即文件确实存在(该文件只是引用代码创建的,所以创建了一个代码成功的次数)。但是,同时 Fileexists
returns false.
该文件是一个 SQLite 文件,稍后由 sqlite3_open_v2
打开并在不久后由 sqlite3_close
关闭。 SQLite 是否可以将文件置于 Fileexists returns false 的状态? (重启应用后状态依旧)
问题是 TPath.GetTempPath
的当前实施。它使用通用 Posix 方法 ExpandFileName('~/tmp/')
。不过Apple推荐的方法是使用NSTemporaryDirectory
.
两种方法 return tmp
目录的路径,但是 NSTemporaryDirectory
如果文件夹不存在,也会创建该文件夹 - 这似乎是不同之处。奇怪的是 Delphi 实现仅在某些 iOS 设备语言(包括越南语)下失败。我没有进一步调查,但现在的解决方案是简单地将 TPath.GetTempPath
替换为 Delphi 代码:
NSStrToStr(TNSString.Wrap(NSTemporaryDirectory))
当我将 iOS 设备设置为例如越南语,那么下面的代码会失败sometimes:
var
lFilePath: String
...
lFilePath := TPath.GetTempPath + '/MyDBfile.db';
lFileStream := TFileStream.Create(lFilePath, fmOpenReadWrite or fmShareExclusive or fmCreate);
TFileStream.Create 调用引发断言:"EFCreateError: Cannot create file "/private/var/mobile/Containers/Data/Application/{containerID}/tmp/MyDBfile.db" 没有这样的文件或目录。 只有当设备设置为某些语言(包括越南语)时,断言才不会在西欧语言中出现。
我将创建代码追溯到 System.SysUtils
中 FileCreate
函数的这一行:
FileHandle := Integer(__open(M.AsAnsi(FileName, CP_UTF8).ToPointer,
O_RDWR or O_CREAT or O_TRUNC or Exclusive[(Mode and [=13=]04) shr 2], Rights));
引发断言时文件句柄为 -1。
有什么问题吗?
PS:为了弄清楚发生了什么,我添加了一个 Fileexists
调用:
lFilePath := TPath.GetTempPath + '/MyDBfile.db';
if Fileexists(lFilePath) then
System.Sysutils.DeleteFile(lFilePath);
lFileStream := TFileStream.Create(lFilePath, fmOpenReadWrite or fmShareExclusive or fmCreate);
现在,在代码失败的情况下,我有以下奇怪的发现:
在XCode中,可以显示App的Container,显示Container中的文件tmp/MyDBfile.db
,即文件确实存在(该文件只是引用代码创建的,所以创建了一个代码成功的次数)。但是,同时 Fileexists
returns false.
该文件是一个 SQLite 文件,稍后由 sqlite3_open_v2
打开并在不久后由 sqlite3_close
关闭。 SQLite 是否可以将文件置于 Fileexists returns false 的状态? (重启应用后状态依旧)
问题是 TPath.GetTempPath
的当前实施。它使用通用 Posix 方法 ExpandFileName('~/tmp/')
。不过Apple推荐的方法是使用NSTemporaryDirectory
.
两种方法 return tmp
目录的路径,但是 NSTemporaryDirectory
如果文件夹不存在,也会创建该文件夹 - 这似乎是不同之处。奇怪的是 Delphi 实现仅在某些 iOS 设备语言(包括越南语)下失败。我没有进一步调查,但现在的解决方案是简单地将 TPath.GetTempPath
替换为 Delphi 代码:
NSStrToStr(TNSString.Wrap(NSTemporaryDirectory))