0

在我的 Windows 窗体应用程序中,我能够像这样构建我的 SQLite 连接字符串(在通过 Add > Existing Item 将 .db 文件添加到我的项目之后):

string connStr = string.Format(@"Data source={0}F4F.db", Application.StartupPath);

所以我在我的 UWP 项目中尝试了同样的事情,代码如下:

string connStr = string.Format(@"Data source={0}Cartographer.db", Application.StartupPath);
SqliteConnection conn = new SqliteConnection(connStr);

...但是没有“StartupPath”属性。我应该改用什么?

这些是 Application 对象的可用成员:

在此处输入图像描述

我应该使用“当前”吗?

更新

作为对彼得的回答的回应,并作为我对该答案的评论的补充,这是我现在拥有的代码:

public sealed partial class MainPage : Page
{
        StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
        string connStrBase = @"Data source={0}Cartographer.db";
        string connStr = string.Empty;
        string path = string.Empty;    
        . . .
}

. . .

path = folder.Path;
connStr = string.Format(connStrBase, path);

...我至少接近正确吗?

4

1 回答 1

2

要对打包为应用程序一部分的文件进行读写访问,您需要在ApplicationData.LocalFolder应用程序首次运行时将其复制到您的目录,然后您可以从那里更新它。然后,您可以使用该LocalFolder.Path属性使用正确的位置初始化连接字符串。原始文件将位于您的Package.InstalledLocation.

这是一个基本示例,使用一个帮助类,您可以使用该类将任何文件从包中的任意位置复制到本地文件夹中的镜像位置,然后返回生成的文件名。

该示例是异步的,以防您在启动等过程中复制大文件,但如果您只需要包目录中的文件,则可以轻松地使其同步。此外,即使 API 是异步的,如果您愿意,也可以 100% 安全地阻止它(如下图所示)。

class LocalDataUtils
{
    static readonly string destinationDirectory = 
        ApplicationData.Current.LocalFolder.Path;
    static readonly string sourceDirectory = 
        Package.Current.InstalledPath;

    static Dictionary<string, TaskCompletionSource<string>> fileCompletionTasks = 
        new Dictionary<string, TaskCompletionSource<string>>();

    public static Task<string> GetFilenameAsync(string relativePath)
    {
        TaskCompletionSource<string> completion;

        if (!fileCompletionTasks.TryGetValue(relativePath, out completion))
        {
            lock (fileCompletionTasks)
            {
                // Check again in case there was a race.
                if (!fileCompletionTasks.TryGetValue(relativePath, out completion))
                {
                    completion = new TaskCompletionSource<string>();
                    fileCompletionTasks.Add(relativePath, completion);

                    // This is async in case you ever need to copy from locations 
                    // other than your local folders or you are copying files
                    // that might take a while.
                    // You can simplify and make it not-async if you like.
                    Task.Run(() => CopyFileAndGetFilename(relativePath, completion));
                }
            }
        }

        return completion.Task;
    }

    static void CopyFileAndGetFilename(string relativePath, 
        TaskCompletionSource<string> completion)
    {
        try
        {
            // Also a fun movie :)
            var finalDestination = Path.Combine(destinationDirectory, relativePath);

            if (!File.Exists(finalDestination))
            {
                var originalLocation = Path.Combine(sourceDirectory, relativePath);
                Directory.CreateDirectory(Path.GetDirectoryName(finalDestination));
                File.Copy(originalLocation, finalDestination);
            }

            completion.SetResult(finalDestination);
        }
        catch (Exception ex)
        {
            completion.SetException(ex);
        }
    }
}

使用它非常简单:

var name = await LocalDataUtils.GetFilenameAsync(@"Database\test.db");
var text = File.ReadAllText(name);
Debug.Write(text);

// Note: no 'await' here for illustrative purposes; subsequent calls
// for the same file will always return immediately.
var otherNameTask = LocalDataUtils.GetFilenameAsync(@"Database\test.db");
Debug.Assert(otherNameTask.IsCompletedSuccessfully);

// Don't call 'await' and instead block on the 'Result'
// This is not safe in general for async methods, but is fine in this case.
var name2 = LocalDataUtils.GetFilenameAsync(@"Assets\StoreLogo.png").Result;
var size = new FileInfo(name2).Length;
Debug.WriteLine($"{Path.GetFileName(name2)} is {size} bytes long.");
于 2020-12-02T14:22:12.870 回答