كيف تختار مكان حفظ بيانات تطبيق Windows محليّاً ── جدول قرار بين SQLite وJSON وRegistry وAccess

· آخر تحديث: · · SQLite, Windows, .NET, C#, تخزين البيانات, Registry, Access, التصميم, جدول القرار, الاستشارات التقنية

سجل التعديلات (3 تحديثات، آخر تحديث 2 Sep، 2026)

سجل بالتغييرات التي أُجريت على هذا المقال. وحيثما حُفظت نسخة سابقة، تبقى متاحة للقراءة عبر رابط دائم يحمل معرّف DOI.

أُصلِحت روابط الخلاصة وCTA الخدمة ورسالة رفض قاعدة البيانات الأحدث. قراءة النسخة السابقة لهذا التحديث (DOI: 10.5281/zenodo.22240982)
أُعيدَت الترجمة العربية كترجمة كاملة عن النص الياباني الأصلي، وأُضيفَت خريطة المعرفة.
أعيدت الترجمة كترجمة كاملة عن النص الياباني الأصلي. كانت النسخة العربية السابقة مختصراً يسقط أبواباً وجداول ورسوم Mermaid وتعليقات الأشكال وFAQ. أُعيدت هذه العناصر وفق الأصل الياباني، والادّعاءات التقنية مطابقة للنسخة اليابانية.
النشر الأول
الاستشهاد بهذا المقال(DOI: 10.5281/zenodo.21621593)

هذا المقال محفوظ على Zenodo. يرد أدناه معرّف DOI الذي يشير دائمًا إلى أحدث نسخة، ومعرّف DOI المثبَّت على النسخة التي تقرؤها.

غو كومورا (2026). كيف تختار مكان حفظ بيانات تطبيق Windows محليّاً ── جدول قرار بين SQLite وJSON وRegistry وAccess. شركة كومورا سوفت ذ.م.م.. https://doi.org/10.5281/zenodo.21621593 https://comcomponent.com/ar/blog/windows-app-local-data-storage-decision-table/

DOI (أحدث نسخة)
10.5281/zenodo.21621593
DOI (هذه النسخة)
10.5281/zenodo.22243194

«هل يكفي استخدام ملفّ INI للإعدادات؟» «بيانات السجلّ التاريخيّ تزايدت، أريد نقلها إلى Access» «كيف يُفاضَل بين Registry وملفّ الإعدادات؟». عند بناء تطبيقات أعمال لِـ Windows، يمثّل اختيار مكان حفظ البيانات طريقاً لا مفرّ من المرور به. لكن هذا الاختيار غالباً ما يُحسَم في البداية بشكل عفويّ ثمّ لا يُعاد النظر فيه، فتظهر المشكلة بعد سنوات على هيئة «ملفّ JSON تضخّم إلى عشرات الميغابايتات فبطُؤ بدء التشغيل»، أو «ملفّ Access في مجلّد مشترك يتلف مرّة في الأسبوع»، أو «الكتابة مباشرةً تحت Program Files تمنع التشغيل في بيئة Windows 11».

في هذا المقال، نرتّب حفظ البيانات المحلّيّة لتطبيقات أعمال Windows بفصل «أين توضَع» (اختيار المجلّد) عن «بماذا تُحفَظ» (اختيار الصيغة/المحرّك). وباستخدام صيغة جدول القرار التي استخدمناها عدّة مرّات في هذه المدوّنة، نلخّص مجالات تفوّق وعيوب كلّ من SQLite وJSON وRegistry وAccess.

1. الخلاصة أوّلاً

  • اختيار مكان الحفظ قرارٌ مستقلٌّ ذو شقّين: «أين توضَع» و«بماذا تُحفَظ». الخطأ في الأوّل يؤدّي إلى مشكلات الصلاحيّات وتعدّد المستخدمين، والخطأ في الثاني يؤدّي إلى مشكلات التلف والأداء والصيانة.
  • أساس اختيار المكان: لبيانات وإعدادات كلّ مستخدم على حدة استخدم %LOCALAPPDATA% (Environment.SpecialFolder.LocalApplicationData)، ولمشاركة جميع المستخدمين استخدم %PROGRAMDATA%، ولا تكتب أبداً في المجلّد نفسه الذي يوجد فيه ملفّ exe (تحت Program Files).1
  • الخيار الأوّل للصيغة بسيط ويتلخّص في اثنين: الإعدادات الصغيرة المهيكَلة تُحفَظ في ملفّ JSON، والبيانات المتنامية للأعمال والسجلّ التاريخيّ والبيانات التي تحتاج بحثاً تُحفَظ في SQLite. وبهذين الاثنين وحدهما تُغطّى غالبيّة حالات الحفظ المحلّيّ لتطبيقات الأعمال.2
  • الـ Registry هو «مكان لوضع أعلام صغيرة أو معلومات تكامل مع Windows نفسه»، وليس مخزن بيانات للتطبيق. استخدامه دون فهم إعادة التوجيه بين 32-bit و64-bit (Wow6432Node) يوقعك في مشكلة «القيمة التي كتبتها لا تظهر».3
  • لم يعد هناك سبب يُذكَر لاختيار Access (.accdb) كمخزن بيانات في تطوير جديد. وحتّى عند استخدامه للتكامل مع أصول قائمة، يلازمه قيد على مستوى التوزيع، وهو ضرورة تطابق عدد بتّات موفّر ACE.4
  • أيًّا كانت الصيغة، المعلومات السرّيّة (كلمات المرور، مفاتيح API) وحدها تُعامَل معاملةً مختلفة. لا تضعها كنصّ صريح في JSON أو Registry، بل احمِها بواسطة DPAPI. اعتبر DPAPI (Data Protection API) وظيفة في نظام التشغيل تُتيح ترك إدارة مفاتيح التشفير لـ Windows. يمرّر التطبيق النصّ الصريح إلى ProtectedData.Protect ويستلم بايتات مشفَّرة، ولا يحفظ سوى تلك البايتات. المفتاح مرتبط بالمستخدم المسجَّل دخوله (أو بالجهاز المعنيّ) ويديره نظام التشغيل، فلا حاجة إلى دفن مفتاح في التطبيق. وبالمقابل، الخاصّيّة الأساسيّة هي أنّ فكّ التشفير لا ينجح إلّا للمستخدم نفسه على الجهاز نفسه، وهذا يؤثّر في تصميم ترحيل الأجهزة والنسخ الاحتياطيّ (القسم 6.3).5 لتفاصيل الاستخدام راجع المقال «حفظ المعلومات السرّيّة في تطبيقات Windows - تجنّب الإعدادات النصّيّة الصريحة عبر DPAPI».

في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 22، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle

2. تصنيف البيانات المطلوب حفظها إلى 4 أنواع

قبل تحديد بماذا تُحفَظ، نصنّف طبيعة البيانات التي نريد حفظها. تنقسم البيانات المحلّيّة لتطبيقات الأعمال عادةً إلى الأنواع الأربعة التالية.

التصنيف مثال الخصائص
الإعدادات جهة الاتّصال، تخطيط الشاشة، آخر مجلّد تمّ فتحه صغيرة الحجم. تُقرَأ بالكامل عند بدء التشغيل. قد يريد المستخدم تحريرها مباشرةً أحياناً
بيانات الأعمال والسجلّ التاريخيّ نتائج القياس، سجلّ المعالجة، نسخة محلّيّة من البيانات الرئيسيّة تتزايد باستمرار. يُراد البحث فيها وتجميعها. تلفها يُحدِث أثراً كبيراً على العمل
التخزين المؤقّت (Cache) الصور المصغّرة، الموارد التي جرى تنزيلها يمكن إعادة توليدها إن فُقدت. تحتاج إدارة للسعة
المعلومات السرّيّة كلمات المرور المحفوظة، الرموز المميّزة (tokens) كمّيّتها قليلة. يجب عدم وضعها كنصّ صريح

جوهر هذا المقال هو أنّ مكان الوضع والصيغة المناسبَين يختلفان باختلاف كلّ تصنيف. والتطبيقات التي «تضع الإعدادات والسجلّ التاريخيّ كلّها في ملفّ XML واحد» يكون أوّل خطوة للتحسين لديها هو إعادة هذا التصنيف من جديد.

3. أين توضَع ── أساسيّات اختيار المجلّد

في .NET، اجعل الأساس هو المواقع التي يمكن الحصول عليها عبر Environment.GetFolderPath.6

المكان طريقة الحصول عليه الاستخدام
%LOCALAPPDATA%\اسم الشركة\اسم التطبيق SpecialFolder.LocalApplicationData الخيار الافتراضيّ لبيانات كلّ مستخدم. ابدأ من هنا
%APPDATA%\اسم الشركة\اسم التطبيق (Roaming) SpecialFolder.ApplicationData فقط للإعدادات التي يُراد أن تتبع المستخدم في بيئة ملفّات التعريف المتنقّلة (Roaming Profiles)
%PROGRAMDATA%\اسم الشركة\اسم التطبيق SpecialFolder.CommonApplicationData بيانات مشتركة بين جميع المستخدمين. تحتاج تصميم ACL
تحت مجلّد المستندات SpecialFolder.MyDocuments فقط للمخرجات التي يتعامل معها المستخدم بوصفها ملفّاته الخاصّة (كالتقارير المُصدَّرة مثلاً)

هذا كلّ ما يلزم في الشيفرة، لكنّ جعل إدراج طبقة «اسم الشركة\اسم التطبيق» وإنشاء المجلّد عند أوّل مرّة جزءاً من معالجة مشتركة يمنع تكاثر أماكن الحفظ بشكل عشوائيّ.

public static class AppPaths
{
    public static string DataDir { get; } = CreateDir(
        Environment.SpecialFolder.LocalApplicationData);

    private static string CreateDir(Environment.SpecialFolder root)
    {
        var dir = Path.Combine(
            Environment.GetFolderPath(root), "KomuraSoft", "MyApp");
        Directory.CreateDirectory(dir);  // 既に存在すれば何もしない
        return dir;
    }
}

استخدام Environment.GetFolderPath بدل تجميع متغيّر البيئة %LOCALAPPDATA% بربط النصوص هو لأنّه يُعيد المكان الصحيح حتّى مع حساب خدمة، أو التشغيل بمستخدم آخر، أو بيئة تمّ فيها ضبط إعادة توجيه المجلّدات. وهذا يتجنّب أيضاً حادثة «تغيّر المسار بمجرّد التشغيل بحساب مختلف من Task Scheduler» (وهي أحد أشكال مشكلة «يعمل يدويّاً فقط» التي وردت في الفصل 5 من مقال Task Scheduler).

نذكر ثلاثة مطبّات:

  • لا تكتب في المجلّد الذي يوجد فيه exe. لا يمكن للمستخدم القياسيّ الكتابة تحت Program Files. وفي التطبيقات القديمة ذات 32-bit، قد تُعاد التوجيه بصمت إلى VirtualStore بفضل افتراضيّة الملفّات، وهي ميزة توافق في UAC (User Account Control، التحكّم بحساب المستخدم)، ما يسبِّب عرضاً غريباً وهو «اختلاف محتوى ملفّ الإعدادات بين التشغيل كمدير والتشغيل كمستخدم قياسيّ».
  • ProgramData «يمكن الكتابة فيه لكنّه ليس آمناً». قد تكون قوائم التحكّم بالوصول (ACL) الافتراضيّة بحيث لا يستطيع مستخدم تعديل ملفّ أنشأه مستخدم آخر. إن أردت القراءة والكتابة بمشاركة جميع المستخدمين، أنشئ المجلّد عبر المثبِّت واضبط ACL صراحةً.
  • لا تجعل Roaming الخيار الافتراضيّ. في بيئة ملفّات التعريف المتنقّلة الخاضعة لنطاق (domain)، تتمّ مزامنة ما تحت Roaming عند تسجيل الدخول والخروج. وضع بيانات كبيرة الحجم أو خاصّة بالجهاز (كالتخزين المؤقّت أو إعدادات العتاد) في Roaming يسبِّب تأخّر المزامنة أو «تلوّث» جهاز آخر. عند التردّد، اختر Local.

3.1 كيف تتحوّل الكتابة إلى VirtualStore

نرسم آليّة المطبّ الأوّل فقط. افتراضيّة ملفّات UAC ميزة توافق تعمل عندما يحاول تطبيق 32-bit لا يحمل requestedExecutionLevel في الـ manifest الكتابة إلى مكان محميّ مثل Program Files: بدل إفشال العملية، تُبدَّل وجهة الكتابة إلى داخل ملفّ تعريف المستخدم. والقراءة أيضاً تفضّل المكان الافتراضيّ، فيبدو للكاتب نفسه أنّ «الكتابة نجحت».7

تشغيل كمديرمستخدم قياسينعملا = تطبيق 32-bit بلا رفعالتطبيق يكتب إلى settings.ini تحت Program Filesهل توجد صلاحية الكتابة؟يُكتب في الموقع الأصليهل هو 64-bit أو محدَّد requestedExecutionLevel؟يفشل برفض الوصول بوضوحتُفعَّل افتراضيّة ملفّات UACتُنشأ نسخة لكل مستخدم تحت VirtualStore في LOCALAPPDATAالقراءة تفضّل النسخة الافتراضيّة فيبدو للكاتب أن الكتابة نجحتالملف المقروء يختلف بين التشغيل كمدير والتشغيل كمستخدم قياسي

وجهة النقل الفعليّة هي %LOCALAPPDATA%\VirtualStore\Program Files\.... وبما أنّ الافتراضيّة تُنشئ نسخة منفصلة لكلّ مستخدم، فقد يظهر العرض أيضاً على هيئة «الإعدادات تبقى على جهاز أحمد، لكن عند تسجيل دخول شخص آخر على جهاز مشترك تعود القيم الابتدائيّة». هذه وظيفة مؤقّتة لإنقاذ التطبيقات القديمة، ولا تعمل مع عمليّات 64-bit ولا العمليّات المرفوعة ولا العمليّات التي تحمل manifest.7 والآليّة نفسها على جانب Registry (نقل HKLM\Software إلى HKCU\Software\Classes\VirtualStore) مفصَّلة في «مطبّات إعادة توجيه Registry بين 32-bit و64-bit والافتراضيّة».

3.2 التحقّق على جهاز حقيقيّ من أنّ الكتابة ممكنة

تصميم مكان الحفظ لا يُعدّ تحقّقاً ما دمت تشغّل التطبيق بحساب مدير على جهاز التطوير. قبل الإصدار مرِّر الاختبارات الثلاثة التالية.

  1. شغِّل بمستخدم قياسيّ. أنشئ حساباً محلّيّاً قياسيّاً على جهاز التطوير، وسجِّل الدخول به، وأكمل دورة التثبيت ثمّ التشغيل ثمّ الحفظ ثمّ إعادة التشغيل. مجرّد إلغاء «التشغيل كمدير» من حساب مدير يعيد إنتاج غياب رفع UAC، لكنّ انتماء ذلك المستخدم إلى مجموعة المدراء لا يتغيّر، لذا فهو غير كافٍ كتحقّق من ACL.
  2. أكّد أين يُكتَب عبر Process Monitor. صفِّ عمليّة التطبيق، وضيِّق العمليّات إلى CreateFile / WriteFile. انظر هل المكان المقصود يظهر ACCESS DENIED، وهل عمود Path يحتوي مساراً فيه VirtualStore. يعرض Procmon المسار الفعليّ بعد حلّ إعادة التوجيه، فيظهر الفرق بين «المكان الذي ظننت أنّك كتبت فيه» و«المكان الذي كُتب فيه فعلاً» كما هو. طريقة الاستخدام في «دليل عمليّ لـ Process Monitor (ProcMon)».
  3. اقرأ ACL. نفِّذ icacls "C:\ProgramData\KomuraSoft\MyApp" وتأكّد أنّ المستخدمين والمجموعات المتوقَّعة يملكون الكتابة. إذا جعلت ما تحت ProgramData منطقة قراءة وكتابة مشتركة بين جميع المستخدمين، انظر أيضاً أنّ ACL الذي ضبطه المثبِّت ظاهر هنا.

إن لم تعلق في هذه الثلاثة، فستتجنّب على الأقلّ حوادث من نوع «لا يمكن الحفظ فور التوزيع».

4. بماذا تُحفَظ ── طبيعة الخيارات الأربعة

4.1 ملفّ JSON ── الخيار الأوّل للإعدادات

يمكن قراءته وكتابته ببساطة عبر System.Text.Json، وهو قابل للقراءة من قبل الإنسان، ويسهل إدارته عبر Git ومقارنة الفروقات، وهذه كلّها مزايا تجتمع لصالح استخدامه في الإعدادات. توجد نقطتان تستحقّان الانتباه.

اتّخذ إجراءً وقائيّاً ضدّ التلف. إذا انقطعت الطاقة أثناء الكتابة وبقي ملفّ ناقص، يصبح غير قابل للقراءة عند التشغيل التالي. الأسلوب المتعارف عليه هو «الكتابة إلى ملفّ مؤقّت ثمّ الاستبدال»، وفي .NET يوفّر File.Replace استبدالاً مصحوباً بنسخة احتياطيّة.

var json = JsonSerializer.Serialize(settings, options);
var tmp = path + ".tmp";
File.WriteAllText(tmp, json);
if (File.Exists(path))
    File.Replace(tmp, path, path + ".bak");
else
    File.Move(tmp, path);

تضمين سلوك تدهور تدريجيّ من البداية في جانب القراءة أيضاً — أي «إن كان تالفاً جرِّب .bak، وإن فشل ذلك أيضاً ابدأ التشغيل بالقيم الافتراضيّة مع تحذير» — يمنع تلف ملفّ الإعدادات من أن يتحوّل إلى حالة دعم فنّيّ.

لا تجعله مخزن بيانات. نطاق تطبيق JSON هو الحجم الذي يصحّ فيه «قراءة كلّ شيء عند البدء وكتابة كلّ شيء عند الإنهاء» (كمعيار تقريبيّ: حتّى بضع مئات من الكيلوبايتات). إن بدأتَ بوضع سجلّ تاريخيّ يستمرّ بالإضافة إليه أو بيانات تحتاج البحث في السجلّات داخل JSON، فتلك إشارة للانتقال إلى SQLite التالي.

4.2 SQLite ── الخيار الأوّل للبيانات المتزايدة والبيانات المطلوب البحث فيها

SQLite قاعدة بيانات مضمَّنة لا تحتاج خادماً، وتتكوّن من ملفّ واحد، وهي في النطاق العامّ (public domain)، ويمكن التعامل معها من .NET عبر موفّر ADO.NET الذي تصونه Microsoft وهو Microsoft.Data.Sqlite، أو عبر موفّر SQLite الخاصّ بـ EF Core.2 وتوصي بها Microsoft نفسها بوصفها وسيلة لحفظ البيانات المحلّيّة في تطبيقات Windows8، لذا فمن المقبول اعتبار SQLite الخيار الأوّل لأيّ «بيانات مهيكَلة تتزايد محلّيّاً».

أوّلاً، نوضّح بالشيفرة مدى سهولة استخدامه. بإضافة Microsoft.Data.Sqlite عبر NuGet، لا حاجة إلى إعداد خادم ولا شاشة إدارة لسلسلة الاتّصال، ويكفي تحديد مسار الملفّ للبدء في الاستخدام.

using Microsoft.Data.Sqlite;

var dbPath = Path.Combine(AppPaths.DataDir, "app.db");
using var conn = new SqliteConnection($"Data Source={dbPath}");
conn.Open();

// 初回のみ: WALモード有効化とテーブル作成
using (var cmd = conn.CreateCommand())
{
    cmd.CommandText = """
        PRAGMA journal_mode=WAL;
        CREATE TABLE IF NOT EXISTS measurement (
            id         INTEGER PRIMARY KEY AUTOINCREMENT,
            device_id  TEXT    NOT NULL,
            value      REAL    NOT NULL,
            created_at TEXT    NOT NULL DEFAULT (datetime('now'))
        );
        CREATE INDEX IF NOT EXISTS ix_measurement_device
            ON measurement(device_id, created_at);
        """;
    cmd.ExecuteNonQuery();
}

// 挿入はパラメーター必須(文字列連結でSQLを組み立てない)
using (var cmd = conn.CreateCommand())
{
    cmd.CommandText =
        "INSERT INTO measurement (device_id, value) VALUES ($device, $value)";
    cmd.Parameters.AddWithValue("$device", "CAM-01");
    cmd.Parameters.AddWithValue("$value", 23.5);
    cmd.ExecuteNonQuery();
}

يتبيّن أنّ بجهد لا يختلف كثيراً عن «الإلحاق المستمرّ بملفّ JSON» تحصل على بحث وتجميع مفهرسَين وسجلّ تاريخيّ بلا سقف لعدد الصفوف. وإن أردت طبقة ORM، فإنّ موفّر SQLite في EF Core يجلس فوق هذه المكتبة.

بعد ذلك نختصر نقاط العمل الفعليّ.

  • فعِّل وضع WAL. هذا هو PRAGMA journal_mode=WAL; في الشيفرة أعلاه. WAL اختصار Write-Ahead Logging (سجلّ الكتابة المسبقة)، ويعني عدم كتابة التغييرات مباشرة في ملفّ قاعدة البيانات نفسه، بل إلحاقها بملفّ -wal يُنشأ بجانبه، ثمّ عكسها لاحقاً دفعة واحدة على الملفّ الأصليّ. الكاتب يلحق في النهاية فقط فلا يعيق القارئ، ويمكن المضيّ بالقراءة والكتابة معاً.9 ولهذا يقلّ الازدحام حتّى عندما يلمس خيط واجهة المستخدم ومعالجة خلفيّة قاعدة البيانات نفسها. إعداد WAL يُحفَظ في ملفّ قاعدة البيانات نفسه، فلا حاجة إلى إصداره في كلّ اتّصال (بعد ضبطه مرّة يبقى WAL حتّى بعد الإغلاق وإعادة الفتح).9 ومن الآثار الجانبيّة أنّ قاعدة البيانات لم تعد ملفّاً واحداً مكتملاً: يظهر بجانب app.db الملفّان app.db-wal وapp.db-shm. ولهذا يكون النسخ الاحتياطيّ بنسخ app.db وحده أثناء التشغيل محفوفاً بالمخاطر (القسم 6.3).
  • اجمع الكتابة في مسار واحد لكلّ عمليّة. كتابة SQLite حصريّة على مستوى قاعدة البيانات. إن كتبت من خيوط عدّة، فالتصميم الآمن هو توحيد جهة الكتابة عبر طابور. كذلك عند تنفيذ كمّ كبير من INSERT الصغيرة، تجميعها في معاملة صريحة أسرع بمراتب من الالتزام سطراً بسطر.
  • لا تضعها على مشاركة شبكيّة. قفل الملفّات عبر SMB كثير المشكلات المرتبطة بالبيئة، وحتّى مشروع SQLite الرسميّ يذكر المشاركة على أنظمة الملفّات الشبكيّة كأوّل سبب للتلف.10 ووضع WAL أصلاً يفترض أنّ العمليّات التي تستخدم قاعدة البيانات نفسها على الجهاز نفسه، ولا يعمل على نظام ملفّات شبكيّ (لأنّه يستخدم ذاكرة مشتركة بين العمليّات).9 إذا رغبت في استخدام متزامن من أجهزة ومستخدمين عدّة، فذلك مجال قاعدة بيانات من نوع عميل-خادم (مثل SQL Server Express).
  • اعرف أنّ الأنواع أربعة فقط. كيان SQLite هو INTEGER / REAL / TEXT / BLOB، وتُحفَظ التواريخ وGUID كـ TEXT. مراجعة اصطلاح تخطيط الأنواع في Microsoft.Data.Sqlite مرّة واحدة تجنّبك الحيرة في مقارنة التواريخ وترتيبها.11 وفي المثال أعلاه جُعل created_at بـ datetime('now') (UTC) لأنّ خلط التوقيت المحلّي يفسد الترتيب وعبور التوقيت الصيفيّ. التحويل إلى التوقيت المحلّي عند العرض هو النهج الآمن.
  • النسخ الاحتياطيّ ليس «نسخ ملفّ» بل VACUUM INTO أو Backup API. النسخ البسيط لملفّ قاعدة البيانات أثناء التشغيل قد يلتقط عدم اتّساق بين WAL والملفّ الأصليّ (التفاصيل في الفصل 6).

4.3 Registry ── فقط للأعلام الصغيرة ومعلومات التكامل مع Windows

يكون Registry مناسباً لمعلومات التكامل مع Windows نفسه — مثل «هل ثُبِّت التطبيق» وتسجيل بدء التشغيل وربط الملفّات — وكذلك لإعدادات مستخدم صغيرة جدّاً فقط. المبدأ: الإعدادات التي يستخدمها التطبيق لنفسه تُكتَب تحت HKCU، والمعلومات المشتركة للجهاز يكتبها المثبِّت في HKLM (تجنّب تصميماً يكتب إلى HKLM وقت التشغيل لأنّه يتطلّب امتيازات مدير).

أكبر مطبّ هو عدد البتّات. في Windows 64-bit، يُعاد توجيه HKLM\Software كما تراه عمليّة 32-bit إلى HKLM\Software\Wow6432Node.3 أعراض «القيمة موجودة في محرِّر Registry لكن التطبيق لا يقرأها» أو «القيمة التي كتبها تطبيق 32-bit لا يراها أداة صيانة 64-bit» تعود في الغالب إلى هذا. يظهر عند الانتقال إلى AnyCPU أو التحويل إلى 64-bit، فافهمه في السياق نفسه لمشكلة 32-bit/64-bit في COM وActiveX («مطبّات التسجيل وbitness في تطوير COM/OCX/ActiveX»).

إذا احتجت من .NET إلى قراءة عرض بعدد بتّات مختلف (مثل تطبيق ما زال 32-bit يقرأ قيمة سُجِّلت في جانب 64-bit)، يمكن تحديد العرض صراحةً بـ RegistryView.

using Microsoft.Win32;

// 32bitプロセスから 64bit ビューの HKLM を読む
using var hklm64 = RegistryKey.OpenBaseKey(
    RegistryHive.LocalMachine, RegistryView.Registry64);
using var key = hklm64.OpenSubKey(@"SOFTWARE\KomuraSoft\MyApp");
var installDir = key?.GetValue("InstallDir") as string;

وبالعكس، لحظة احتياجك إلى هذا التحديد علامة على أنّك تؤجّل قرار التصميم: «أيّ الجانبين 32-bit أم 64-bit هو الجانب الصحيح للكتابة». النهج السليم هو توحيد عدد بتّات جهة الكتابة وجهة القراءة.

وضع بيانات تتجاوز بضعة كيلوبايتات أو بيانات شبيهة بالمصفوفات في Registry غير مُجدٍ في النسخ الاحتياطيّ والترحيل والتشخيص. اترك ذلك للملفّات (JSON / SQLite).

4.4 Access (.accdb) ── تقريباً لا اعتماد جديد عليه، وللتكامل مع الأنظمة القائمة تعامل معه بحسم

كان Access (JET/ACE) في الماضي مرادف قاعدة البيانات المحلّيّة لتطبيقات الأعمال، لكن أسباب اختياره في تطوير جديد شبه معدومة اليوم. السبب الأساسيّ هو التوزيع. للوصول إلى .accdb من الشيفرة تحتاج موفّر ACE (Access Database Engine)، ولا يمكن الاتّصال ما لم يتطابق عدد بتّات التطبيق مع عدد بتّات ACE.4 ويُضاف تعارض التعايش مع عدد بتّات Office، فحالة الدعم الكلاسيكيّة هي «يعمل على جهاز التطوير ويفشل عند العميل برسالة Microsoft.ACE.OLEDB.12.0 プロバイダーがローカルコンピューターに登録されていません». كما أنّ الحاجة إلى حزمة قابلة لإعادة التوزيع (Access Database Engine 2016 Redistributable) تزيد مكوّنات التوزيع.12

ومع ذلك تظهر مشاهد يتداخل فيها Access فعلاً: تكامل بيانات مع نظام أعمال قائم على Access، أو قراءة بيانات رئيسيّة صُنعت في Access. في تلك الحالة يُستحسَن الحسم كالتالي:

  • ثبِّت عدد بتّات العمليّة التي تقرأ وتكتب (تثبيت x86 غالباً هو الواقعيّ)، وتأكّد عبر المثبِّت من وجود ACE الموافق
  • تجنّب كتصميم الكتابة المتزامنة من أشخاص عدّة إلى .accdb موضوع في مجلّد مشترك (تكلفة الإصلاح عند التلف لا تتناسب)
  • احتفظ على المدى البعيد بمسار ترحيل إلى SQLite أو قاعدة بيانات من نوع خادم

معالجة الأصول القائمة بما فيها Excel/VBA مرتَّبة أيضاً في «ما هو VBA - حدوده ومستقبله والمواضع التي ينبغي استبداله فيها».

5. جدول القرار

5.1 جدول سريع: التصنيف × الصيغة

نضع أوّلاً جدولاً يقابل تصنيفات الفصل 2 الأربعة بصيغ الفصل 4 الأربع. الغرض سطر واحد يقول «بياناتي من هذا التصنيف، إذن هذه الصيغة وهذا المكان».

التصنيف (الفصل 2) ملفّ JSON SQLite Registry Access المكان الافتراضيّ (الفصل 3)
الإعدادات ◎ الخيار الأوّل ○ إن كانت ستزيد مستقبلاً فابدأ من هنا △ أعلام صغيرة جدّاً ومعلومات تكامل Windows فقط %LOCALAPPDATA% (Roaming فقط للإعدادات التي يُراد أن تتبع المستخدم)
بيانات الأعمال والسجلّ التاريخيّ ✕ ينهار افتراض القراءة الكاملة ◎ الخيار الأوّل △ فقط عند التكامل مع أصل Access قائم %LOCALAPPDATA% (للمشاركة بين جميع المستخدمين %PROGRAMDATA% مع تصميم ACL)
التخزين المؤقّت △ للصغير فقط ○ إن كثر العدد %LOCALAPPDATA% (لا تضعه في Roaming)
المعلومات السرّيّة ○ كوعاء لقيم محميّة بـ DPAPI ○ كذلك △ كذلك، لكن للصغيرة فقط لا تضعها كنصّ صريح. احمِها بـ DPAPI (الفصل 1)

للقراءة وجهان. الأوّل: لا تحشر التصنيفات في وعاء واحد عبر الصفوف. «الإعدادات والسجلّ التاريخيّ والتخزين المؤقّت كلّها في JSON واحد» تصميم نمطيّ يظهر أثره لاحقاً. الثاني: صفّ المعلومات السرّيّة جوهره ليس «أيّ صيغة تختار» بل «هل شُفِّرت بـ DPAPI قبل الحفظ»، ويمكن اختيار الوعاء وفق التصنيفات الثلاثة الباقية.

5.2 طبيعة كلّ صيغة

الجانب ملفّ JSON SQLite Registry Access (.accdb)
البيانات التي يتفوّق فيها إعدادات صغيرة بيانات مهيكَلة متزايدة، بحث وتجميع أعلام صغيرة، تكامل Windows التكامل مع أصول Access القائمة
معيار كمّيّة البيانات حتّى بضع مئات كيلوبايت حتّى عشرات غيغابايت حتّى بضعة كيلوبايت حتّى 2 غيغابايت (الحدّ في المواصفة)
البحث والتجميع ✕ (يفترض القراءة الكاملة) ◎ (SQL) ○ (SQL)
قابل للقراءة مباشرة من الإنسان △ (يحتاج أداة) △ (يحتاج Access)
القوّة أمام التلف △ (إجراء وقائيّ ذاتيّ) ○ (معاملات)
وصول متزامن من عمليّات عدّة ○ (داخل الجهاز نفسه)
المشاركة من أجهزة عدّة ✕ (عملياً)
مكوّنات توزيع إضافيّة لا شيء لا شيء (مضمَّن في NuGet) لا شيء موفّر ACE إلزاميّ

كما يبيّن الصفّ الأخير، لا تصلح أيّ تقنيّة من تقنيّات الحفظ المحلّيّ للمشاركة من أجهزة عدّة. وضعها في مجلّد مشترك يبدو وكأنّه يتيح المشاركة، لكن JSON بلا حصر، وقفل SQLite عبر SMB غير موثوق، وAccess يبلغ حدّه مصحوباً بمخاطر التلف. إذا ظهر متطلّب تعامل مواقع ومستخدمين عدّة مع البيانات نفسها، فاعتبره خطّ القرار لإقامة قاعدة بيانات من نوع خادم مثل SQL Server Express أو إقامة Web API.

6. لا يتلف، وقابل للترحيل، وقابل للاستعادة ── تصميم مشترك بصرف النظر عن الصيغة

أيّاً كانت الصيغة، هناك ثلاثة تصاميم لا غنى عنها إذا امتدّ التشغيل سنوات. إدخالها في الإصدار الأوّل أو إغفالها يغيّر تكلفة الصيانة لاحقاً تغييراً كبيراً.

6.1 إلحاق رقم إصدار بالمخطّط (schema) والصيغة

تحديث التطبيق يغيّر شكل البيانات المحفوظة. لحظة «نسخة جديدة تقرأ بيانات كتبتها نسخة قديمة» آتية لا محالة، فاجعل لجانب البيانات رقم صيغة.

في SQLite، PRAGMA user_version معدّ لهذا الغرض تحديداً.

int GetVersion(SqliteConnection conn)
{
    using var cmd = conn.CreateCommand();
    cmd.CommandText = "PRAGMA user_version";
    return Convert.ToInt32(cmd.ExecuteScalar());
}

void Migrate(SqliteConnection conn)
{
    void Exec(string sql)
    {
        using var cmd = conn.CreateCommand();
        cmd.CommandText = sql;
        cmd.ExecuteNonQuery();
    }

    var v = GetVersion(conn);
    if (v > 2)
        // حالة فتح تطبيق قديم لقاعدة أنشأها تطبيق أحدث.
        // لا تلمس مخططاً مجهولاً؛ أوقف هنا فهذا أأمن
        throw new InvalidOperationException(
            $"أُنشئت قاعدة البيانات هذه (الإصدار {v}) بتطبيق أحدث.");

    using var tx = conn.BeginTransaction();
    if (v < 1) Exec("ALTER TABLE measurement ADD COLUMN unit TEXT");
    if (v < 2) Exec("CREATE TABLE operator (id INTEGER PRIMARY KEY, name TEXT)");
    Exec("PRAGMA user_version = 2");
    tx.Commit();
}

هذا الحدّ الأدنى للترحيل: انظر الإصدار عند البدء وطبِّق الفرق فقط. رفض «إصدار أحدث منّا» في البداية يمنع حادثة أن تكتب الشيفرة القديمة، بعد التراجع (rollback) إلى نسخة أقدم من التطبيق، في مخطّط لا تعرفه فتفسده. والفكرة نفسها في JSON: ضع "version": 2 في الجذر، وأدخل تحويلاً من الصيغ القديمة عند القراءة، وارفض الصيغ الأحدث من اللازم. «لا تُخرج إلى الناس صيغة بيانات بلا رقم إصدار» — بهذا وحده ينجو مستقبلك.

6.2 حدِّد سلفاً سلوك التدهور التدريجيّ عند التلف

تحدّثنا في الفصل 4 عن الوقاية من التلف لكلّ صيغة (الكتابة الذرّيّة لـ JSON، ومعاملات SQLite)، ومع ذلك ستصادف «بيانات لا تُقرأ». عطل قرص، حجر برمجيّات مكافحة الفيروسات بإنذار كاذب، تحرير يدويّ من المستخدم. إن لم تقرّر كيف يتصرّف التطبيق عندئذٍ، يصبح تطبيقاً لا يبدأ أصلاً.

  • تعذّر قراءة الإعدادات ← ابدأ بالقيم الافتراضيّة وأبلغ المستخدم (الصمت بالقيم الافتراضيّة يولّد استفسارات «اختفت الإعدادات»)
  • تعذّر قراءة بيانات الأعمال ← اعرض وضع قراءة فقط أو شاشة خطأ تبيّن «أيّ ملفّ تالف». لا تُصلِح بالكتابة فوقه تلقائيّاً (تختفي الأدلّة)
  • إن وُجدت نسخة احتياطيّة ← اقترح الاستعادة. لكن الاستعادة التلقائيّة وجهها الآخر خطر «إنذار كاذب بالتلف فيُرجَع إلى بيانات قديمة»، لذا المبدأ إدخال عمليّة من المستخدم

6.3 النسخ الاحتياطيّ: «هل يمكن الاستعادة؟» أهمّ من «هل أُخِذ؟»

البيانات المحلّيّة، بخلاف قاعدة بيانات على خادم، لا ينسخها أحد نيابة عنك. إن تولّى التطبيق الأمر، فاحسم النقاط الثلاث التالية.

  • ماذا: بيانات الأعمال مشمولة، التخزين المؤقّت مستثنى، والمعلومات السرّيّة — بحكم طبيعة DPAPI — لا تُفكّ إلّا للمستخدم نفسه على الجهاز نفسه (يلزم إجراء ترحيل منفصل إلى جهاز آخر)
  • متى وإلى أين: عند البدء أو يوميّاً، إلى مجلّد backup داخل %LOCALAPPDATA% مع أجيال. وهل تُحمَل أيضاً إلى مجلّد مشترك أو مجلّد يشمله النسخ الاحتياطيّ الحاليّ للحاسوب فقرار تشغيليّ
  • كيف: في SQLite يُمنَع النسخ البسيط للملفّ أثناء التشغيل. VACUUM INTO 'backup.db' يعطيك لقطة متّسقة بجملة واحدة
// VACUUM INTO は親フォルダーを作らず、出力先が既に存在するとエラーになる。
// フォルダー作成と重複しないファイル名の決定を先に済ませておく
var backupDir = Path.Combine(AppPaths.DataDir, "backup");
Directory.CreateDirectory(backupDir);
var backupPath = Path.Combine(backupDir, $"app-{DateTime.Now:yyyyMMdd-HHmmss}.db");

using var cmd = conn.CreateCommand();
cmd.CommandText = "VACUUM INTO $path";
cmd.Parameters.AddWithValue("$path", backupPath);
cmd.ExecuteNonQuery();

الأجيال تتراكم، فأدرج مع النسخ الاحتياطيّ معالجة «أبقِ أحدث N أجيال واحذف الأقدم».

ثمّ درِّب الاستعادة مرّة على الأقلّ. وجود ملفّ النسخة دون أن يعرف أحد كيف يُعيده أو دون أن يجرِّبه أحد، أمر شائع في أنظمة الأعمال. كتابة إجراء نقل البيانات إلى جهاز جديد عند استبدال الحاسوب تكشف عادة ثغرات التصميم (بيانات الاعتماد المحميّة بـ DPAPI لا تنتقل، المسار يتضمّن اسم المستخدم فينكسر عند مستخدم آخر، إلخ). لطريقة محو البيانات عند التخلّص من الحاسوب راجع أيضاً «ما ينبغي فعله قبل التخلّص من حاسوب Windows».

7. إرشادات للحالات الشائعة الّتي يصعب فيها الحسم

  • «إعدادات لكنّها قد تزيد مستقبلاً» ── إن كان استخدام «قراءة الكلّ عند البدء» مرشّحاً للانهيار، فابدأ بـ SQLite من الأوّل. إنشاء «جدول settings» في SQLite ليس عيباً.
  • «الترحيل من INI/XML» ── إن كان الاستبدال صيغة فقط فإلى JSON، وإن اختلطت عندها بيانات سجلّ تاريخيّ فافصلها إلى SQLite. إبقاء احتياطيّ للصيغ القديمة في جانب القراءة لإصدار أو اثنين يجعل الترحيل آمناً.
  • «يُطلب أن تُرى في Excel» ── لا تجعل مخزن البيانات Excel/Access، بل احفظ في SQLite وأضِف وظيفة تصدير إلى CSV/Excel؛ بذلك تُلبّى موثوقيّة البيانات والطلب معاً. طريقة بناء إخراج التقارير في «كيف تبني إخراج تقارير Excel».
  • «نريد قراءة وكتابة الملفّ نفسه من عمليّات عدّة» ── داخل الجهاز نفسه يمكن لـ SQLite (WAL) أن يصمد كثيراً، لكن يلزم تصميم تعارض الكتابة. وإن كان التكامل عبر ملفّات فاستخدم أنماط الحصر في «أفضل ممارسات تكامل الملفّات والقفل».
  • «نريد المشاركة بين أجهزة عدّة» ── هذا تخرّج من الحفظ المحلّيّ. الخيار الأوّل بنية عميل-خادم بإقامة SQL Server Express (مجّانيّ، حتّى 10 غيغابايت لقاعدة البيانات) على جهاز يقوم مقام خادم ملفّات. وSQL Server «LocalDB»، رغم الاسم، بيئة مستخدم واحد موجَّهة للتطوير فلا تُختار لغرض المشاركة. إذا امتدّ الأمر عبر المواقع أو من خارج الشركة، فذلك خطّ النظر في إدخال Web API.

8. الخلاصة

اختيار مكان الحفظ يُحسَم في معظم الحالات بلا تردّد إذا فصلته إلى «أين توضَع» (LocalAppData / ProgramData، وعدم الكتابة في Program Files) و«بماذا تُحفَظ» (الإعدادات JSON، البيانات المتزايدة SQLite، Registry في الحدّ الأدنى، Access للتكامل القائم فقط).

بعد ذلك، أدخل في الإصدار الأوّل الثلاثيّة المشتركة في الفصل 6 — رقم إصدار الصيغة، وسلوك التدهور عند التلف، ونسخة احتياطيّة يمكن استعادتها. والمعلومات السرّيّة دائماً في مسار منفصل إلى DPAPI. بجدول القرار والتصميم المشترك في هذا المقال تتجنّب تقريباً التركيبات الباهظة لاحقاً مثل «JSON نما إلى عشرات الميغابايت» و«Access مشترك يتلف أسبوعيّاً». إن ساورك القلق من طريقة الحفظ في تطبيق قائم، فابدأ بجرد «ماذا يُحفَظ وأين».

مقالات ذات صلة

مجالات الاستشارة ذات الصلة

تتعامل شركة كومورا سوفت ذ.م.م. مع إعادة النظر في طريقة حفظ بيانات تطبيقات الأعمال (بما في ذلك تصميم الترحيل من INI/XML/Access)، وتحقيق أسباب تلف البيانات وتدهور الأداء.

المراجع

  1. Microsoft Learn, KNOWNFOLDERID. حول تعريف مجلّدات Windows المعروفة مثل LocalAppData وRoamingAppData وProgramData. 

  2. Microsoft Learn, Microsoft.Data.Sqlite overview. حول لمحة عن موفّر ADO.NET الخاصّ بـ SQLite الذي تصونه Microsoft، وكونه أساساً لموفّر EF Core SQLite.  2

  3. Microsoft Learn, Registry Redirector. حول آليّة إعادة توجيه وصول Registry لعمليّات 32-bit إلى Wow6432Node في Windows 64-bit.  2

  4. Microsoft Learn, Can’t establish a connection to Access Database Engine OLE DB. حول ضرورة تطابق عدد بتّات موفّر ACE OLE DB مع عدد بتّات العمليّة التي تصل إليه.  2

  5. Microsoft Learn, DataProtectionScope Enum. تعريف نطاق الحماية المحدَّد لـ ProtectedData.Protect / Unprotect. في CurrentUser لا يفكّ التشفير إلّا خيط يعمل في سياق المستخدم الحاليّ، وفي LocalMachine يمكن لأيّ عمليّة على ذلك الحاسوب فكّ التشفير لذا ينبغي قصره على الحالات التي تُوثَق فيها جميع حسابات ذلك الجهاز، وفي معظم المشاهد ينبغي استخدام CurrentUser

  6. Microsoft Learn, Environment.SpecialFolder Enum. حول التعداد المستخدَم للحصول على المجلّدات المعروفة من .NET. 

  7. Microsoft Learn, UAC Architecture. حول إعادة توجيه افتراضيّة الملفّات/السجلّ في UAC لطلبات الكتابة على مستوى الجهاز إلى مكان لكلّ مستخدم، وتفضيل القراءة للمكان الافتراضيّ، واستخدام نسخة داخل ملفّ تعريف المستخدم عند الكتابة إلى مجلّد محميّ مثل Program Files بحيث تكون النسخة مختلفة لكلّ مستخدم، واقتصار الافتراضيّة على تطبيقات 32-bit وتعطيلها في العمليّات المرفوعة والتطبيقات ذات الـ manifest الذي يحمل requestedExecutionLevel (فتفشل تطبيقات 64-bit غير المرفوعة برفض وصول)، وكونها ميزة توافق مؤقّتة لا ينبغي الاعتماد عليها.  2

  8. Microsoft Learn, Use a SQLite database in a Windows app. البرنامج التعليميّ الرسميّ الذي يوصي باستخدام SQLite وMicrosoft.Data.Sqlite / EF Core لحفظ البيانات المحلّيّة في تطبيقات Windows. 

  9. SQLite, Write-Ahead Logging. حول آليّة إلحاق التغييرات بملفّ WAL بدل الملفّ الأصليّ، وتمكّن الكاتب من العمل مع القارئ في آن لأنّه يلحق فقط، واستمرار journal_mode=WAL بعد إعادة الفتح لأنّه دائم، ومرافقة الملفَّين -wal و-shm، وضرورة أن تكون العمليّات التي تستخدم قاعدة البيانات نفسها على الجهاز نفسه، وعدم عمل WAL على أنظمة الملفّات الشبكيّة.  2 3

  10. SQLite, How To Corrupt An SQLite Database File. حول كون خلل القفل على أنظمة الملفّات الشبكيّة سبباً رئيسيّاً لتلف قاعدة البيانات. 

  11. Microsoft Learn, Data types (Microsoft.Data.Sqlite). حول الأنواع الأربعة الأساسيّة لِـ SQLite، وقاعدة تخطيط DateTime وGuid إلى TEXT. 

  12. Microsoft, Microsoft Access Database Engine 2016 Redistributable. حول الحزمة القابلة لإعادة التوزيع (32-bit/64-bit) للوصول إلى .accdb / .mdb. 

أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.

ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.

الأسئلة الشائعة

أسئلة شائعة حول موضوع هذه المقالة.

أين ينبغي حفظ ملفّ إعدادات تطبيق Windows؟
بالنسبة لإعدادات وبيانات كلّ مستخدم على حدة، فالأساس هو الوضع تحت %LOCALAPPDATA% (Environment.SpecialFolder.LocalApplicationData) بترتيب هرميّ «اسم الشركة\اسم التطبيق». أمّا للمشاركة بين جميع المستخدمين فيُستخدَم %PROGRAMDATA%، لكنّ قوائم التحكّم بالوصول (ACL) الافتراضيّة قد تجعل البنية بحيث لا يستطيع مستخدم آخر تعديلها، لذا يُضبَط ACL صراحةً عبر المثبِّت. ولا يجوز أبداً الكتابة في المجلّد نفسه الذي يوجد فيه exe (تحت Program Files). فالمستخدم القياسيّ لا يستطيع الكتابة هناك، وفي التطبيقات القديمة ذات 32-bit تحدث إعادة توجيه صامتة إلى VirtualStore، ما يسبِّب عرضاً غامضاً لا يمكن تفسيره.
هل ينبغي حفظ الإعدادات بصيغة JSON أم SQLite؟
الإعدادات الصغيرة المهيكَلة تُحفَظ في ملفّ JSON، وبيانات الأعمال المتزايدة والسجلّ التاريخيّ والبيانات التي يُراد البحث فيها تُحفَظ في SQLite كخيار أوّل، وبهذين الاثنين تُغطّى غالبيّة حالات الحفظ المحلّيّ لتطبيقات الأعمال. نطاق تطبيق JSON يمتدّ إلى الحجم الذي يصحّ فيه «قراءة كلّ شيء عند بدء التشغيل وكتابة كلّ شيء عند الإنهاء»، أي حتّى بضع مئات من الكيلوبايتات كمعيار تقريبيّ. وإن بدأتَ بوضع سجلّ تاريخيّ يستمرّ بالإضافة إليه أو بيانات تحتاج بحثاً في السجلّات داخل JSON، فتلك إشارة للانتقال إلى SQLite. وحتّى الإعدادات، إن كان يُتوقّع تزايدها مستقبلاً، فلا مشكلة في إنشاء جدول settings في SQLite منذ البداية.
هل يجوز وضع قاعدة بيانات SQLite في مجلّد مشترك على الشبكة؟
ينبغي تجنّب ذلك. قفل الملفّات عبر SMB كثير المشكلات المرتبطة بالبيئة، وحتّى مشروع SQLite الرسميّ يذكر المشاركة على أنظمة الملفّات الشبكيّة كأوّل سبب لتلف قاعدة البيانات. وJSON لا يملك آليّة حصر، وAccess أيضاً يصل إلى حدوده مصحوباً بمخاطر التلف، فلا تصلح أيّ تقنيّة من تقنيّات الحفظ المحلّيّ للمشاركة من عدّة أجهزة. وإذا ظهر متطلّب تعدّد المواقع والمستخدمين للتعامل مع البيانات نفسها، فذلك خطّ القرار للانتقال إلى قاعدة بيانات من نوع خادم كـ SQL Server Express (مجّانيّة، حتّى 10 غيغابايت لقاعدة البيانات) أو إقامة Web API.
هل يجوز حفظ بيانات التطبيق في Registry؟
يكون Registry مناسباً لمعلومات التكامل مع Windows نفسه — كالتسجيل في بدء التشغيل وربط الملفّات — وكذلك لإعدادات مستخدم صغيرة جدّاً فقط. والبيانات التي تتجاوز بضعة كيلوبايتات أو البيانات الشبيهة بالمصفوفات غير مُجدية فيه من ناحية النسخ الاحتياطيّ والترحيل والتشخيص على حدّ سواء، فتُترَك لِـ JSON أو SQLite. كما أنّه في Windows 64-bit يُعاد توجيه HKLM\Software كما تراه عمليّة 32-bit إلى Wow6432Node، ما يسبِّب عرض «القيمة موجودة عند النظر عبر محرِّر Registry لكن لا يمكن للتطبيق قراءتها». والنهج السليم هو توحيد عدد بتّات جهة الكتابة وجهة القراءة.

الملف الشخصي للمؤلف

صفحة الملف الشخصي لمؤلف المقالة.

غو كومورا

مؤسّس شركة كومورا سوفت ذ.م.م.

يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.

العودة إلى المدونة