Советы по работе с базами данных
SQLite 3 в действии: как использовать API доступа к файловой системе

Поняв, как создавать, изменять и загружать базу данных SQLite 3 в браузере, сегодня я хочу попытаться понять, как открывать, читать и изменять локально сохраненную базу данных. Меня интересует эмуляция поведения настольного приложения, сохраняющего данные в базу данных SQLite 3. Для этого я снова буду использовать версию SQLite 3 на JavaScript, скомпилированную в WebAssembly. Также я буду использовать API доступа к файловой системе. Для обработки графики я буду использовать Svelte.
Но сначала рекомендую прочитать первую и вторую части этой серии:
- SQLite 3 в действии: руководство для начинающих по использованию реляционной базы данных в браузере
- SQLite 3 в действии: как открыть локальную базу данных с помощью JavaScript и WebAssembly
Как открыть локальную базу данных
В отличие от сообщения, опубликованного несколько дней назад, я намерен использовать API доступа к файловой системе. Таким образом, я могу получить доступ к локальному файлу, прочитать его, изменить и затем сохранить. Конечным результатом является опыт, очень похожий на настольное приложение.
Сначала мне нужна функция, которая может открыть локальный файл. Эта функция очень проста:
let fileHandle;
const openFile = async () => {
[fileHandle] = await globalThis.showOpenFilePicker();
const file = await fileHandle.getFile();
const contents = await file.arrayBuffer();
};
По сути, функция showOpenFilePicker открывает диалоговое окно, позволяющее выбрать файл. После выбора возвращается объект FileHandle. Этот объект содержит выбранный файл. Чтобы прочитать файл, я использую метод getFile, а затем arrayBuffer для получения содержимого файла. В дополнение к arrayBuffer существуют также методы text и stream, которые возвращают содержимое файла в виде строки и ReadableStream соответственно.
Чтобы получить базу данных из файла, я могу повторно использовать функцию readDatabase():
const readDatabase = (arrayBuffer) => {
const sqlite3 = self["sqlite3"];
let bytes = new Uint8Array(arrayBuffer);
const p = sqlite3.wasm.allocFromTypedArray(bytes);
let db = new sqlite3.oo1.DB();
let rc = sqlite3.capi.sqlite3_deserialize(
db.pointer,
"main",
p,
bytes.length,
bytes.length,
sqlite3.capi.SQLITE_DESERIALIZE_FREEONCLOSE |
sqlite3.capi.SQLITE_DESERIALIZE_RESIZEABLE
);
db.checkRc(rc);
return db;
};
Таким образом я получаю:
let fileHandle;
const openFile = async () => {
[fileHandle] = await globalThis.showOpenFilePicker();
const file = await fileHandle.getFile();
const contents = await file.arrayBuffer();
const db = readDatabase(contents);
return db;
};
Я держу переменную fileHandle вне функции, потому что использую ее для сохранения файла. Теперь я могу создать специальную кнопку для открытия файла:
<button
on:click={async () => {
db = await openFile();
listTable = [...getTableList(db)];
}}
>Open File</button>
Как сохранить базу данных SQLite 3
Чтобы сохранить базу данных SQLite 3, я снова использую API доступа к файловой системе. Сначала я получаю дескриптор файла и делаю его доступным для записи:
const writable = await handle.createWritable();
Я использую метод sqlite3_js_db_export для получения массива байтов:
const byteArray = self["sqlite3"].capi.sqlite3_js_db_export(db.pointer);
Наконец, я создаю большой двоичный объект и записываю его в файл:
const blob = new Blob([byteArray.buffer], {
type: "application/x-sqlite3",
});
await writable.write(blob);
await writable.close();
Окончательный результат:
const saveFile = async (handle, db) => {
const writable = await handle.createWritable();
const byteArray = self["sqlite3"].capi.sqlite3_js_db_export(db.pointer);
const blob = new Blob([byteArray.buffer], {
type: "application/x-sqlite3",
});
await writable.write(blob);
await writable.close();
};
Теперь я могу добавить кнопку для сохранения файла:
<button on:click={async () => await saveFile(fileHandle, db)}
>Save File</button
>
Как сохранить базу данных SQLite 3 в новый файл
Я могу сохранить базу данных SQLite 3 в новом файле. Для этого я снова использую API доступа к файловой системе. Я также могу использовать функцию saveFile, которую я определил ранее, но сначала мне нужен новый дескриптор файла:
const showSaveFilePicker = async () => {
const options = {
types: [
{
description: "SQLite 3",
accept: {
"application/x-sqlite3": [".sqlite", ".sqlite3", ".db"],
},
},
],
};
const handle = await globalThis.showSaveFilePicker(options);
return handle;
};
Итак, я добавляю кнопку:
<button
on:click={async () => {
const handle = await showSaveFilePicker();
await saveFile(handle, db);
}}>Save File As</button
>
И это все, по крайней мере, на сегодня.
Спасибо за прочтение! Оставайтесь с нами, чтобы узнать больше.
Не пропустите мою следующую статью — подпишитесь на мой средний список адресов электронной почты
Дополнительные материалы на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord .
Заинтересованы в масштабировании запуска вашего программного обеспечения? Ознакомьтесь с разделом Схема.