序列化内存中的 Sqlite DB C#

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

我正在尝试序列化内存中的 Sqlite 数据库,以便稍后可以将其转换回文件。我了解如何在 node.js 中序列化数据库“db.serialize”如何在“node-sqlite3”和 C 中工作在 C 中序列化数据库。我只是无法找到一种方法来在 C# 中完成此任务。如果有人有任何见解,将不胜感激! 到目前为止我所拥有的

using System.Data.SQLite; using Newtonsoft.Json; using System.Text; public byte[] SerializeDB(string sql) { using(var con = new SQLiteConnection($"Data Source=:memory:;Version=3;New=True;")) { con.Open(); using(SQLiteCommand cmd = new SQLiteCommand(sql, con)) { cmd.ExecuteNonQuery(); return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(**WHAT SHOULD GO HERE**)); } } }
    
c# sqlite
2个回答
0
投票
进一步研究后,我认为这是不可能的。 SQLite 不允许您访问内存中的文件。如果我愿意备份文件然后访问备份,这可能会很有用。但这样我就不需要内存文件了。


0
投票
几天来我一直在寻找在 C# 中执行此操作的方法。

SQLite 定义了一个方法作为其 C 接口的一部分来执行此操作:

https://www.sqlite.org/c3ref/serialize.html

unsigned char *sqlite3_serialize( sqlite3 *db, /* The database connection */ const char *zSchema, /* Which DB to serialize. ex: "main", "temp", ... */ sqlite3_int64 *piSize, /* Write size of the DB here, if not NULL */ unsigned int mFlags /* Zero or more SQLITE_SERIALIZE_* flags */ );

sqlite3_serialize(D,S,P,F) 接口返回一个指向内存的指针,该指针是数据库连接 D 上的 S 数据库的序列化

对于普通的磁盘数据库文件来说,序列化只是磁盘文件的副本。对于内存数据库或“TEMP”数据库,如果该数据库备份到磁盘,则序列化与写入磁盘的字节序列相同。

但是,我正在使用的 C# 库(sqlite-net-base,以 SQLitePCLRaw.provider.winsqlite3 作为提供程序)不会 DllImport 将此方法作为其提供程序实现的一部分。尽管 SQLite 规范包含该方法,但该方法仍然可用。

因此,我所做的就是自己将方法与库一起导入。这在我的例子中有效(使用 winsqlite3)。您应该能够通过将 DLL 名称更改为您正在使用的名称来执行相同的操作。

[DllImport("winsqlite3", CallingConvention = CallingConvention.StdCall, ExactSpelling = true)] public static extern IntPtr sqlite3_serialize(sqlite3 db, [MarshalAs(UnmanagedType.LPStr)] string a, IntPtr piSize, uint mFlags);
在文档中有一个重要的注释:

调用者负责释放返回值以避免内存泄漏

由于这是调用 C 代码,因此请务必记住,C# 不会为我们进行垃圾收集,直到我们获得它返回给 C# 托管内存的任何内存为止。

因此,可以使用一种方法来包装此调用并使其对 C# 更加友好:

private byte[] SeralizeDb() { var lengthInput = Marshal.AllocHGlobal(sizeof(long)); var unmanagedResult = sqlite3_serialize(this.scannerSqliteDb.Handle, "main", lengthInput, 0); // https://www.sqlite.org/c3ref/serialize.html main is mentioned as an example and is what works // Handle null result or a bad length. var lengthResult = (int)Marshal.ReadInt64(lengthInput); // Cast as int for the Marshel.Copy. Db is only a cache of a few Mb ever in our case var managedResult = new byte[lengthResult]; Marshal.Copy(unmanagedResult, managedResult, 0, lengthResult); // Free unmanaged memory allocations Marshal.FreeHGlobal(lengthInput); Marshal.FreeHGlobal(unmanagedResult); return managedResult; }
    
© www.soinside.com 2019 - 2024. All rights reserved.