使用File.WriteAllBytes()创建的文件在程序结束后未保留
嵌入式SQLite数据库复制后目标路径无文件生成的问题
我跟着旧版sqlite-net-pcl教程操作,尝试用代码把嵌入式资源数据库复制到C://Users/我的用户/AppData/Local路径下,但程序运行结束后目标路径里没生成新文件。不过通过GetObject函数能确认数据库已正确复制,文件路径也没问题,是不是我对相关机制有根本性误解?
相关代码片段
MainPage.xaml.cs
using System.Collections.ObjectModel; using System.Reflection; using TestApp.Models; namespace TestApp { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly; using (Stream stream = assembly.GetManifestResourceStream("TestApp.Inventory.db")) { using (MemoryStream MemStr = new MemoryStream()) { stream.CopyTo(MemStr); File.WriteAllBytes(ObjectRepository.DbPath, MemStr.ToArray()); } } ObjectRepository repository = new ObjectRepository(); foreach (var @object in repository.List()) { Objects.Add(@object); } } } }
ObjectRepository.cs
using System.Reflection; using TestApp.Models; namespace TestApp.Data { public class ObjectRepository { private readonly SQLiteConnection _Database; public static string DbPath { get; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Inventory.db"); public ObjectRepository() { _Database = new SQLiteConnection(DbPath); _Database.CreateTable<Object>(); } public Object GetObject(string ObjectNumber) { return _Database.FindWithQuery<Object>("select * from Objects where ObjectNumber = ?", [ObjectNumber]); } } }
TestApp/Models/Object.cs
using SQLite; namespace TestApp.Models { [Table("Objects")] public class Object { [PrimaryKey] public string ObjectNumber { get; set; } = string.Empty; } }
问题原因及解决方案
1. SQLite自动创建空库的干扰
当你实例化SQLiteConnection时,如果指定路径的文件不存在,SQLite会自动创建一个空数据库文件。这会导致你产生误解:GetObject能正常执行不代表原嵌入式数据库的内容被复制,只是SQLite生成了空库,而非你期望的带数据的数据库。
2. 嵌入式资源读取可能失败
GetManifestResourceStream的参数必须是完整的资源全名(格式:[程序集名].[资源所在目录].[文件名]),如果资源路径写错,stream会为null,但后续SQLite的自动建库逻辑会掩盖这个错误。
可以通过以下代码验证资源名称是否正确:
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly; foreach (var resName in assembly.GetManifestResourceNames()) { Console.WriteLine(resName); // 输出所有嵌入式资源名称,找到你的数据库对应的正确名称 }
3. 未判断文件是否已存在
当前代码每次启动都会直接写入文件,但如果文件已存在,File.WriteAllBytes会直接覆盖。但更合理的逻辑是仅在文件不存在时复制,避免重复操作:
if (!File.Exists(ObjectRepository.DbPath)) { // 执行数据库复制逻辑 }
4. 路径验证错误
你手动查找的C://Users/我的用户/AppData/Local可能和Environment.SpecialFolder.LocalApplicationData实际指向的路径有差异,可以通过代码打印实际路径确认:
Console.WriteLine(ObjectRepository.DbPath); // 复制这个路径去查找文件
修正后的完整代码示例
MainPage.xaml.cs
using System.Collections.ObjectModel; using System.Reflection; using TestApp.Models; using TestApp.Data; namespace TestApp { public partial class MainPage : ContentPage { public ObservableCollection<Object> Objects { get; set; } = new ObservableCollection<Object>(); public MainPage() { InitializeComponent(); BindingContext = this; EnsureDatabaseReady(); ObjectRepository repository = new ObjectRepository(); foreach (var @object in repository.List()) { Objects.Add(@object); } } private void EnsureDatabaseReady() { if (File.Exists(ObjectRepository.DbPath)) { Console.WriteLine("数据库已存在,跳过复制"); return; } var assembly = IntrospectionExtensions.GetTypeInfo(typeof(App)).Assembly; // 验证资源名称 foreach (var resName in assembly.GetManifestResourceNames()) { Console.WriteLine($"嵌入式资源:{resName}"); } using (Stream stream = assembly.GetManifestResourceStream("TestApp.Inventory.db")) { if (stream == null) { Console.WriteLine("未找到指定的嵌入式数据库资源"); return; } using (MemoryStream memStr = new MemoryStream()) { stream.CopyTo(memStr); File.WriteAllBytes(ObjectRepository.DbPath, memStr.ToArray()); Console.WriteLine($"数据库已复制到:{ObjectRepository.DbPath}"); } } } } }
补充ObjectRepository的List方法
原代码中ObjectRepository缺少List()方法,需要补充实现:
public List<Object> List() { return _Database.Table<Object>().ToList(); }
内容的提问来源于stack exchange,提问作者Frasher Gray
相关产品推荐
相关产品推荐

