C# 移动文件后访问Sqlite数据库

问题描述 投票:0回答:1

这是一个 .NET (MAUI) 应用程序。作为更新例程的一部分,我下载并替换 Sqlite .db3 文件。

最初,我开始于:

File.Move(oldFile, newFile);
var result = RunQuery();

我注意到在移动操作完全完成之前执行查询时(导致 I/O 错误)。我决定编写我的异步复制功能:

await using (var sourceStream = File.Open(sourceFile, FileMode.Open))
  {
    var options = new FileStreamOptions()
      {
         Mode = FileMode.Create,
         Access = FileAccess.Write,
         BufferSize = 0
      };
    await using (var destinationStream = File.Open(destinationFile, options))
      {
         await sourceStream.CopyToAsync(destinationStream);
         sourceStream.Close();
         destinationStream.Close();
         File.Delete(sourceFile);
      }
  }

这在一定程度上改善了情况,但每隔几次运行,我都会收到

malformed database
或更糟糕的是
table X not found
错误。

如果我在移动和查询之间添加手动延迟,我从来没有遇到过问题。但这不是一个可靠的解决方案。

确认文件已完全写入并准备好查询的好方法是什么?

c# .net sqlite maui
1个回答
0
投票

也许最近情况发生了变化,但在 .NET 中移动文件不会等待 IO 操作完成,因此您需要做一些技巧才能使其工作。过去我使用过静态方法/助手,像这样的东西应该可以解决问题。

代码:

public static class FileMoveHelper
{
    public async Task MoveFileAsync(string sourceFullFilePath, string destinationFullFilePath, int timeoutSeconds = 60)
    {
        // this will be a non-io blocking call
        File.Move(sourceFullFilePath, destinationFullFilePath);

        // Define a task to monitor if the file exists at the destination path
        var fileMovedTask = Task.Run(async () =>
        {
            while (!File.Exists(destinationFullFilePath))
            {
                await Task.Delay(50); // Small delay to prevent CPU-bound loops
            }
            return true;
        });

        // Define a timeout task
        var delayTask = Task.Delay(TimeSpan.FromSeconds(timeoutSeconds));

        // Wait for either the file move completion or timeout
        if (await Task.WhenAny(fileMovedTask, delayTask) == delayTask)
        {
            // Handle timeout scenario
            throw new TimeoutException($"File move operation timed out after {timeoutSeconds} seconds.");
        }

        // Ensure the file move actually completed successfully
        if (!await fileMovedTask)
        {
            throw new IOException("File move operation did not complete successfully.");
        }
    }
}

您可能希望使用取消令牌和更多保护子句稍微扩展它,以确保源文件存在并且您的应用程序可以写入目标文件夹。

用途:

await MoveFileAsync(oldFile, newFile, 30)

希望这有帮助。

PS。我意识到静态方法/类对于单元测试来说是有问题的,所以请随意将其重写为具体的类并使用您喜欢的 DI 库注入它。

© www.soinside.com 2019 - 2024. All rights reserved.