在应用程序关闭时,我想通过Internet(使用Indy)将文件发送到服务器。如果数据发送正常,我想从计算机中删除该文件。关键部分是我的文件不应同时存储在两个地方(服务器,本地计算机)。
例如,我的应用程序在将文件发送到服务器之后可能会意外停止,并且在从本地磁盘删除文件之前。在这种情况下,文件将存在于两个地方。
由于以下原因,应用程序可能会停止:电源故障,Control + Alt + Del,操作系统关闭,用户关闭,系统挂起(可能还有其他原因我忘了?)。
如何保证文件存储在一个地方?
我认为我们可以考虑将文件写入磁盘是即时的,因为文件非常小。
答案 0 :(得分:2)
不,没有保证。操作系统和控制操作系统的最终用户总是可以终止进程。但是,操作系统通常不会尝试这样的事情,而且用户肯定不会在不知不觉中杀死你的应用程序。
您可以在关机期间运行您喜欢的任何代码(例如,在Form1Close
中)。但是,如果您运行某些代码而不处理消息几秒钟,Windows可能会认为您的应用程序被冻结,并询问用户是否希望将其删除。因此,与往常一样,您应该在自己的线程中执行“慢”代码,以便主应用程序线程仍然具有响应性。 [但是如果最终用户没有要求Windows终止该进程,它可以无限期地运行,即使它表现不佳。]
此外,如果您希望此代码真正运行几秒钟,您最好告诉最终用户发生了什么。例如,您可以显示please wait窗口。
如果我是你,我会在主表单中写一个OnCloseQuery
处理程序。这个设置CanClose := false
,显示状态窗口,并启动关闭线程。当该线程完成时,它将关闭主表单(例如通过向其发送消息)。 OnCloseQuery
处理程序还应检查关闭线程是否正在运行。如果是这样,它应该只设置CanClose := false
但不能启动(另一个)关闭线程。例如,如果最终用户反复单击关闭框,则会发生这种情况。我认为OnCloseQuery
过程将在线程启动主窗体的关闭时运行。这次它应该正常关闭。您可以通过编写一些代码告诉OnCloseQuery
处理程序它是由线程启动的,或者在线程完成时设置ShutdownThreadComplete := true
标志来实现这一点。因此,您将执行CanClose := ShutdownThreadComplete
。
这样的事情:
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if not ShutdownThreadStarted then
begin
CreatePleaseWaitMessage;
StartShutdownThread;
ShutdownThreadStated := true;
CanClose := false;
Exit;
end;
CanClose := ShutdownThreadComplete;
end;
答案 1 :(得分:1)
您可以使用以下Windows API调用来确保将数据写入磁盘:
var
F: TFileStream;
begin
F := TFileStream.Create(....
try
F.Write(...)
(...)
FlushFileBuffers(F.Handle); // this will flush the content to disk
finally
F.Free;
end;
end;
请参阅the official documentation for this API。
附加说明:
在将文件发送到磁盘之前,切勿删除文件内容。 ACID行为的一个公理是保留旧数据,直到新数据可用。对你来说也一样。
一种可能性是后台进程。您可以向后台进程发送消息(作为轻型Windows服务运行,例如),然后退出客户端应用程序。后台进程将负责将文件发送到服务器,并且已从服务器接收到重复单元确认。然后后台进程将能够删除该文件,并等待下一个进程。
客户端只需确保后台进程已处理请求。因为它将是localy,它将是瞬间的。
答案 2 :(得分:1)
我不确定为什么你要求文件不能同时保存在客户端和服务器上。但是,如果您可以略微放宽该限制,您可以在阅读后重命名该文件以指示发送文件正在进行中,然后在确认服务器已收到该文件后最终将其删除。
如果这是不可接受的,您可以使用以下更复杂的步骤:
如果在发送过程中出现错误,则下次应用程序启动时会找到加密文件,然后将加密文件发送到服务器。服务器已经知道最初生成它的解密密钥。
答案 3 :(得分:0)
不,如果在主Form的OnClose(或OnDestroy)中你做了: 1 /写入文件 2 / closeFile 该文件将以完整的方式编写和关闭。 查看closefile帮助以获得更多解释。
答案 4 :(得分:0)
这就是我(部分)解决问题的方法
Delete the file from disk (keep copy in RAM);
Send the file to server;
if server receives file ok
then DoNothing (file was already deleted)
else Write file back to disk;
问题是在第1步和第2步之间,文件无处存在。如果应用程序在该点死亡,则文件丢失(但是,这比在两个地方更容易接受)。不幸的是,步骤1和步骤2之间的延迟是巨大的,因为与远程服务器的通信非常慢(甚至可能长达1-2秒)。