<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های سعید غفاری</title>
        <link>https://virgool.io/feed/@m_67051010</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-10 12:57:37</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/3399048/avatar/DLHfLq.jpg?height=120&amp;width=120</url>
            <title>سعید غفاری</title>
            <link>https://virgool.io/@m_67051010</link>
        </image>

                    <item>
                <title>تست قرار دادن یک لینک</title>
                <link>https://virgool.io/@m_67051010/%D8%AA%D8%B3%D8%AA-%D9%82%D8%B1%D8%A7%D8%B1-%D8%AF%D8%A7%D8%AF%D9%86-%DB%8C%DA%A9-%D9%84%DB%8C%D9%86%DA%A9-flfbgkcwd1ot</link>
                <description>لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد. کتابهای زیادی در شصت و سه درصد گذشته، حال و آینده شناخت فراوان جامعه و متخصصان را می طلبد تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی و فرهنگ پیشرو در زبان فارسی ایجاد کرد. در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها و شرایط سخت تایپ به پایان رسد وزمان مورد نیاز شامل حروفچینی دستاوردهای اصلی و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد.https://medium.com/</description>
                <category>سعید غفاری</category>
                <author>سعید غفاری</author>
                <pubDate>Wed, 08 Oct 2025 15:26:31 +0330</pubDate>
            </item>
                    <item>
                <title>تست تعداد لینک ممکنن در شکل متن</title>
                <link>https://virgool.io/@m_67051010/%D8%AA%D8%B3%D8%AA-%D8%AA%D8%B9%D8%AF%D8%A7%D8%AF-%D9%84%DB%8C%D9%86%DA%A9-%D9%85%D9%85%DA%A9%D9%86%D9%86-%D8%AF%D8%B1-%D8%B4%DA%A9%D9%84-%D9%85%D8%AA%D9%86-otf7gdg82hnf</link>
                <description>لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد. کتابهای زیادی در شصت و سه درصد گذشته، حال و آینده شناخت فراوان جامعه و متخصصان را می طلبد تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی و فرهنگ پیشرو در زبان فارسی ایجاد کرد. در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها و شرایط سخت تایپ به پایان رسد وزمان مورد نیاز شامل حروفچینی دستاوردهای اصلی و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد.https://medium.com/https://google.comhttp://geeksforgeeks.orghttp://geeksforgeeks.orghttp://geeksforgeeks.orghttps://memoryleaks.ir/</description>
                <category>سعید غفاری</category>
                <author>سعید غفاری</author>
                <pubDate>Wed, 08 Oct 2025 15:22:41 +0330</pubDate>
            </item>
                    <item>
                <title>تست قرار گزاری کد</title>
                <link>https://virgool.io/@m_67051010/%D8%AA%D8%B3%D8%AA-%D9%82%D8%B1%D8%A7%D8%B1-%DA%AF%D8%B2%D8%A7%D8%B1%DB%8C-%DA%A9%D8%AF-mu4zhmonomnt</link>
                <description>&lt;/code&gt; alert&#40;1&#41;لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد. کتابهای زیادی در شصت و سه درصد گذشته، حال و آینده شناخت فراوان جامعه و متخصصان را می طلبد تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی و فرهنگ پیشرو در زبان فارسی ایجاد کرد. در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها و شرایط سخت تایپ به پایان رسد وزمان مورد نیاز شامل حروفچینی دستاوردهای اصلی و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا مورد استفاده قرار گیرد.</description>
                <category>سعید غفاری</category>
                <author>سعید غفاری</author>
                <pubDate>Wed, 08 Oct 2025 15:19:57 +0330</pubDate>
            </item>
                    <item>
                <title>I&#039;m Saeed</title>
                <link>https://virgool.io/@m_67051010/im-saeed-q9xnpafwp4h1</link>
                <description>وحید وحید لوعلللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللللل متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد. کتابهای زیادی در شصت و سه درصد گذشته، حال و آینده شناخت فراوان جامعه و متخصصان را می طلبد تا با نرم افزارها شناخت بیشتری را برای طراحان رایانه ای علی الخصوص طراحان خلاقی و فرهنگ پیشرو در زبان فارسی ایجاد کرد. در این صورت می توان امید داشت که تمام و دشواری موجود در ارائه راهکارها و شرایط سخت تایپ به پایان رسد وزمان مورد نیاز شامل حروفچینی دستاوردهای اصلی و جوابگوی سوالات پیوسته اهل دنیای موجود طراحی اساسا ویرایش نمیشه؟</description>
                <category>سعید غفاری</category>
                <author>سعید غفاری</author>
                <pubDate>Wed, 08 Oct 2025 14:08:32 +0330</pubDate>
            </item>
                    <item>
                <title>دریافت فایل CSV از سرور و انتقال آن به دیتابیس room</title>
                <link>https://virgool.io/@m_67051010/%D8%AF%D8%B1%DB%8C%D8%A7%D9%81%D8%AA-%D9%81%D8%A7%DB%8C%D9%84-csv-%D8%A7%D8%B2-%D8%B3%D8%B1%D9%88%D8%B1-%D9%88-%D8%A7%D9%86%D8%AA%D9%82%D8%A7%D9%84-%D8%A2%D9%86-%D8%A8%D9%87-%D8%AF%DB%8C%D8%AA%D8%A7%D8%A8%DB%8C%D8%B3-room-ukohxsauyidu</link>
                <description>توی پست قبلی درباره پشتیبان گیری از دیتابیس محلی حرف زدیم حالا میخوایم فایل csv که آپلود کردیمو و دانلود کنیم و محتویاتشو انتقال بدیم به دیتابیسمون.بریم شروع کنیم.پیش فرض ما تو این سولوشن استفاده از room و retrofit هست.قبل از همه چیز این خط رو به فایل build.gradle پروژه اضافه کنید و پروژه رو sync کنیدimplementation (&amp;quotcom.opencsv:opencsv:5.5.2&amp;quot)1- دریافت فایل از سرور:مثلا ریکوست من این شکلیه:@GET(&amp;quotbackup/downloadDb&amp;quot)
suspend fun downloadDatabase(
    @Header(&amp;quotAuthorization&amp;quot) token: String?
): Response&lt;ResponseBody&gt;یه توکن Authorization توی هدر فرستادم  و یک جواب گرفتم از نوع ResponseBody 2- بررسی پاسخ و ذخیره فایل دانلود شده:try {    val token = &quot;your token&quot;    val response = retrofitService.downloadDatabase( token = token)    if (response.isSuccessful) {        response.body()?.let { body -&gt; val success = saveFile(body)            if (success) {                val filePath = getCsvFilePath()                        importCsvToDatabase(filePath)                    }}}else {// مدیریت پاسخ ناموفق}}catch (e: Exception) {  e.printStackTrace()}خب تو این قسمت به ترتیب کارای زیر رو انجام دادیم  توکن رو مقدار دهی کردیم  فانکشن رتروفیت رو فراخوانی کردیم  فایل دانلود شده رو با فانکشن saveFile ذخیره کردیم مسیر فایل ذخیره شده رو به importCsvToDatabase دادیم و فراخوانیش کردیم . حالا بریم سراغ بقیش.3-ذخیره فایل دریافتی (فانکشن saveFile):fun saveFile(body: ResponseBody): Boolean {
    return try {
        val file = File&#40;context.filesDir, &amp;quotdownloaded_file.csv&amp;quot&#41;
        var inputStream: InputStream? = null
        var outputStream: FileOutputStream? = null
        try {
            inputStream = body.byteStream()
            outputStream = FileOutputStream(file)
            val buffer = ByteArray(4096)
            var bytesRead: Int
            while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                outputStream.write(buffer, 0, bytesRead)
            }
            outputStream.flush()
            true
        } finally {
            inputStream?.close()
            outputStream?.close()
        }
    } catch (e: Exception) {
        e.printStackTrace()
        false
    }
}خب تو این فانکشن فقط به یه توضیح کلی اکتفا کنم اونم اینکه ResponseBody رو دریافت کردیم و اون رو به صورت استریم تو حافظه دستگاه نوشتیمش و بعد در صورتی که عملیات موفق باشه یه مقدار true برمیگردونیم.4- انتقال محتویات فایل csv به دیتابیس:fun importCsvToDatabase(csvFilePath:String) {

    val csvFile=File&#40;csvFilePath&#41;

    val csvReader = CSVReader(FileReader(csvFile))

    val users= mutableListOf&lt;UserEntity&gt;()
    csvReader.use { reader -&gt;
        reader.readNext() // خواندن عنوان ستونها

        var nextLine: Array&lt;String&gt;?
        while (reader.readNext().also { nextLine = it } != null) {
            // فرض کنید ستونهای CSV با فیلدهای کلاس Userتطابق دارند
            val user= User(
                id = nextLine!![0].toInt(),
                name = nextLine!![1],
                phone=nextLine!![2]
            )
            users.add(user)
        }
    }
    yourDao.insertAllUsers(users)
}خب تو این فاکشن با استفاده از کتابخانه ای که implement کردیم فایل csv رو میخونیم و تو حلقه while برای هر ردیف یک آبجکت user میسازیم و اون رو به یک لیست اضافه میکنیم در آخر هم همه لیستمون رو با فانکشنی که تو کلاس dao خودمون داریم ، insert  می کنیم توی تیبل user :@Insert(onConflict = OnConflictStrategy.REPLACE)
  suspend fun insertAllUsers(users: List&lt;UserEntity&gt;)نکته: بهتره یک مدل domain بسازیم که مجزای از entity ما باشه و اول csv رو به مدل domain تبدیل کنیم بعد اون رو مپ کنیم به entity که مربوط به مباحث clean architecture میشه . ولی من تو اینجا مستقیما از entity استفاده کردم . امیدوارم  مفید بوده باشه . ممنون که این مطلب رو مطالعه کردین :)</description>
                <category>سعید غفاری</category>
                <author>سعید غفاری</author>
                <pubDate>Fri, 16 Aug 2024 19:06:30 +0330</pubDate>
            </item>
                    <item>
                <title>پشتیبان گیری از دیتابیس محلی (Android/.NET)</title>
                <link>https://virgool.io/@m_67051010/%D9%BE%D8%B4%D8%AA%DB%8C%D8%A8%D8%A7%D9%86-%DA%AF%DB%8C%D8%B1%DB%8C-%D8%A7%D8%B2-%D8%AF%DB%8C%D8%AA%D8%A7%D8%A8%DB%8C%D8%B3-%D9%85%D8%AD%D9%84%DB%8C-androidnet-molmplwci0ty</link>
                <description>سلام.یکی از روش های کارآمد برای پشتیبان گیری از دیتابیس محلی آپلود کردن یک فایل CSV روی سروره این روش مزایا و معایب خاص خودشو داره که بررسی میکنیم بعد میریم سراغ پیاده سازی .مزایاسادگی و خوانایی: فایلهای CSV ساده هستند و به راحتی میشه اونا رو تو هر ویرایشگر متنی باز کرد. ساختار متن ساده این فایلها باعث میشه که همه بتونن به راحتی محتواشو بفهمن.قابلیت انتقال: فایلهای CSV میتونن به راحتی بین سیستمهای مختلف منتقل شن. اکثر نرمافزارهای دیتابیس و ابزارهای تحلیل داده میتونن فایلهای CSV رو وارد یا صادر کنن.حجم کم: در مقایسه با فرمتهای دیگه، فایل های CSV معمولاً حجم کمتری دارن چون شامل اطلاعات اضافی مثل متادیتا نیستن.سازگاری گسترده: تقریباً همه زبانهای برنامهنویسی و سیستمهای دیتابیس میتونن با فایلهای CSV کار کنن.معایبعدم پشتیبانی از ساختارهای پیچیده: فایلهای CSV فقط دادههای جدولی رو ذخیره میکنن و نمیتونن ساختارهای پیچیده مثل انواع دادههای تودرتو یا سلسله مراتبی رو مدیریت کنن.عدم پشتیبانی از انواع دادهها: تو فایلهای CSV همه دادهها به صورت رشته ذخیره میشن و نوع واقعی دادهها (مثل تاریخ، عدد صحیح، عدد اعشاری) از بین میره. این مسئله میتونه مشکل ساز بشه.نبود امنیت: فایلهای CSV به طور پیشفرض مکانیزم امنیتی و رمز نگاری ندارن. بنابراین اطلاعات حساس تو این روش ممکنه در معرض خطر باشه.نبود استاندارد واحد: هرچند فایلهای CSV استاندارد مشخصی دارن، ولی در عمل ممکنه تفاوتایی تو نحوهی پشتیبانی و تفسیر این فرمت بین ابزارها و سیستمهای مختلف وجود داشته باشه.که می تونه مشکل ساز بشه.پشتیبانی ضعیف از دادههای بزرگ: اگه دیتابیس شما حجم زیادی داشته باشه ، استفاده از فایلهای CSV ممکنه مناسب نباشه و زمان زیادی برای پشتیبانگیری و بازیابی دادهها لازم باشه.با توجه به مزایا و معایبی که گفتم بستگی به نوع پروژه شما و تصمیم خودتون داره که از این روش استفاده کنین یا نه . به هر حال بریم سراغ پیاده سازی .پیاده سازی سمت اندرویدپیش فرض ما تو این سولوشن استفاده از room و retrofit هست. قبل از همه چیز این خط رو به فایل build.gradle پروژه اضافه کنید و پروژه رو sync کنیدimplementation (&amp;quotcom.opencsv:opencsv:5.5.2&amp;quot) برای اینکه قابل فهم تر باشه از بیرونی ترین فانکشن  شروع کنیم و پیش بریم. 1- یه فانکشن بکاپ میسازیم مثل کد زیر:fun backupDb() {
        try {
            val dataBasePart = getDatabaseAsPart()
            val result = retrofitService.uploadDatabase( dataBasePart )
            if (result.isSuccessful) {
              //پیاده سازی لازم
            } else {
          //پیاده سازی لازم
            }

        } catch (e: Exception) {
   e.printStackTrace()
        }
}
}تو این فانکشن دوتا فانکشن دیگه فراخوانی شده یکی کال رتروفیت سرویسمونه یکی دیگه هم فانکشن getDatabaseAsPart . اول چند تا نکته رو بگم بعد بریم سراغ این دوتا فانکشن .نکته اول: retrofitService رو باید تو کلاسی که این فانکشن هست اینیشیالایز کنید یا اینجکت کنید که اینجا من نیاوردم.نکته دوم: باید فایلی که قراره آپلودش کنیم در قالب یک Part به رتروفیت کال داده بشه که فانکشن getDatabaseAsPart این کارو انجام خواهد داد.نکته سوم: بهتره و یا لازمه که تو آپلود از متدای امنیتی و Authentication و همچینین rate Limiter استفاده کنید که باز برای اینکه قیمه ها رو نریزیم تو ماستا من اینجا نیاوردم.2- فانکشن رتروفیت سرویس:@Multipart
@POST(&amp;quotbackup/uploadDb&amp;quot)
suspend fun uploadDatabase(
    @Part dataBase: MultipartBody.Part
): Response&lt;String&gt;
3- فانکشن getDatabaseAsPart:fun getDatabaseAsPart(
): MultipartBody.Part {
    val dbFile: File = csvExportUtil.exportDatabaseToCsv() //این کلاس در ادامه ساخته خواهد شد 
    val requestFile = RequestBody.create(&amp;quotapplication/octet-stream&amp;quot.toMediaTypeOrNull(), dbFile)
    return MultipartBody.Part.createFormData(&amp;quotDatabaseFile&amp;quot, dbFile.name, requestFile)
}خب بزارید این فانکشنو یه ذره دقیق تر بررسی کنیم . تو مرحله اول یه مقدار داریم از نوع File که فانکشن exportDatabaseToCsv اون رو به ما حواهد داد که یه فایل csvهست. بعد یه RequestBody از فایلمون میسازیم توسط فانکشن create که دو تا ورودی میگیره و مرحله آخر پارتی که میخواستیمو بر میگردونه.باز یادتون باشه کلاس csvExportUtil رو که خواهیم ساخت  در کلاس این فانکشن اینیشیالایز یا اینجکت کنیدبیشتر بدانید!!: &quot;application/octet-stream&quot;&quot; این MIME type نشاندهنده این است که دادهها به عنوان یک جریان باینری (Binary Stream) هستند و نوع خاصی از دادهها مشخص نشده است. ()toMediaTypeOrNull این تابع رشته را به یک شیء MediaType تبدیل میکند. اگر تبدیل موفق نباشد، null برمیگرداند.خب بریم سراغ فانکشن exportDatabaseToCsv3- کلاس csvExportUtil و  فانکشن exportDatabaseToCsv:class CsvExportUtil() {
    fun exportDatabaseToCsv(context:Context):File {
        val csvFile = File&#40;context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS&#41;, &amp;quotname.csv&amp;quot)
        var csvWriter: CSVWriter? = null
        try {
            csvWriter = CSVWriter(FileWriter(csvFile))
            var cursor: Cursor? =yourDao.getAllUsersCursor()  // فرض کنید این متد تمام ردیفهای جدول را باز میگرداند
// نوشتن سطر عنوانها
     csvWriter.writeNext(cursor!!.columnNames)
        // نوشتن دادههای جدول
        while (cursor.moveToNext()) {
            val row = Array(cursor.columnCount) { i -&gt; cursor.getString(i) }
            csvWriter.writeNext(row)
        }
        cursor.close()
    } catch (e: Exception) {
        e.printStackTrace()
    } finally {
        try {
            csvWriter?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
    return csvFile
}
}خب توضیحات این فانکشن اینطوریه که: یه context میگیره که برا کلاس File لازمش داریم .csvFile یه فایل تو پوشه داکیومنت میسازه با پسوند csv و اسم name .یه مقدار میسازیم از نوع CSVWriter که فایل رو تو تابع FileWriter از ما به عنوان ورودی می گیره. بعد یه cursor میسازیم که اطلاعاتو از جدول مورد نظرمون میخونه که فانکشنشو تو ادامه مینویسم براتون .حالا به تابع csvWriter  دستور میدیم که اسم ستون های جدولمون رو ت سطر اول بنویسه بعدش هم با یه loop خط به خط  اطلاعات جدولمون رو تو فایل csv می نویسیم . ( برا اینکه مسئله روشنتر شه یه نمونه فایل csv رو ببینید) .در آخر هم cursor و writer رو بستیم  که دچار memory leak نشیم.بیشتر بدانید:نمونه فایل csv4- فانکشن getAllUsersCursor :@Query(&amp;quotSELECT * FROM users&amp;quot)
   fun getAllUsersCursor(): Cursor تو این فانکشن همه یوزر هامونو در قالب یک Cursor از تیبل میکشیم بیرون و تقریبا کارمون با اندروید تمومه.پیاده سازی سمت Dot Netخب از اونجاییکه من android developer هستم  فقط فانکشن های سمت بک اند رو بدون توضیح کلی در اختیارتون میزارم و اگر اشتباهی تو این موارد هست از  شما و متخصصینش عذر خواهی میکنم. 1-کنترلر backup endpointpublic static class BackUpEndPoints
{
public static RouteGroupBuilder MapBackupEndPoints(this IEndpointRouteBuilder routes)
{
    var group = routes.MapGroup(&amp;quot/backup&amp;quot).WithParameterValidation();
group.MapPost(&amp;quot/uploadDb&amp;quot,async (
          IFileService iFileService,
          [FromForm] GetDatabaseDto dbDto
          )=&gt;{     
            if (dbDto.DatabaseFile != null)
            {
                var fileResult = 
                    iFileService.SaveDatabase(dbDto.DatabaseFile,&amp;quotfolder name&amp;quot );
                if (fileResult.Item1 == 1)
                {
                    return Results.Ok(&amp;quotبا موفقیت آپلود شد&amp;quot);
                }
                else
                {
                    return Results.Conflict(new { error = fileResult.Item2});
                }
            }
            else
            {
                return Results.Conflict(new { error = &amp;quotفایل خالی است&amp;quot});

            }


      });
return group;
}
} 2- اینترفیس   IFileServicepublic interface IFileService
{
    public Tuple&lt;int, string&gt; SaveDatabase(IFormFile sqlightDb,String userphone);
//تابع پایینی برای دیافت بکاپ از سرور
    public Tuple&lt;int, string&gt; GetDatabasePath(String userphone);
}3- پیاده سازی اینترفیس IFileServicepublic class FileService:IFileService
{
    private IWebHostEnvironment _environment;

    public FileService(IWebHostEnvironment environment)
    {
        _environment = environment;
    }
    
    private readonly string _backupPath = &amp;quot/app/files/backups&amp;quot
    public Tuple&lt;int, string&gt; SaveDatabase(IFormFile sqlightDb, string folderName)
    {
        try
        {
                var contentPath = this._environment.ContentRootPath;
                var path = Path.Combine(_backupPath, folderName);
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                
                var ext = Path.GetExtension(sqlightDb.FileName);
                var allowedExtensions = new string[] { &amp;quot.csv&amp;quot };
                if (!allowedExtensions.Contains(ext))
                {
                    string msg = string.Format(&amp;quotOnly {0} extensions are allowed&amp;quot,
                        string.Join(&amp;quot,&amp;quot, allowedExtensions));
                    return new Tuple&lt;int, string&gt;(0, msg);
                }

                var newFileName = &amp;quotusers&amp;quot
                var fileWithPath = Path.Combine(path, newFileName);
                if (System.IO.File.Exists(fileWithPath))
                {
                    System.IO.File.Delete(fileWithPath);
                }

                using (var stream = new FileStream(fileWithPath, FileMode.Create))
                {
                    sqlightDb.CopyTo(stream);
                }
                
                return new Tuple&lt;int, string&gt;(1, &amp;quotbackups/&amp;quot + folderName+ &amp;quot/&amp;quot + newFileName);
                
        }
        catch (Exception ex)
        {
            return new Tuple&lt;int, string&gt;(0, &amp;quotError has occured&amp;quot);
        }
    }
}در آخر این چند خط رو به program .cs اضافه کنید://var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped&lt;IFileService, FileService&gt;();
//var app = builder.Build();
app.MapBackupEndPoints();مجددا عرض کنم خدمتتون من متخصص دات نت نیستم و این چند خط رو ارائه کردم برا شما عزیزان اندروید دولوپری که خودتون بک اند رو میزنین . فقط خواستم یه ذهنیتی براتون ایجاد بشه نه اینکه دقیقا این کد رو پیاده سازی کنین.تو پست بعدی توضیحات دریافت فایل  پشتیبان رو منتشر می کنم . امیدوارم که تا اینجاش قابل فهم بوده باشه و اگر اشکالی هست ممنون میشم تو نظرات بهم بگین . فعلا خدا حافظ...</description>
                <category>سعید غفاری</category>
                <author>سعید غفاری</author>
                <pubDate>Wed, 31 Jul 2024 11:52:24 +0330</pubDate>
            </item>
                    <item>
                <title>مهاجرت از sqlite به room در اندروید</title>
                <link>https://virgool.io/@m_67051010/%D9%85%D9%87%D8%A7%D8%AC%D8%B1%D8%AA-%D8%A7%D8%B2-sqlite-%D8%A8%D9%87-room-%D8%AF%D8%B1-%D8%A7%D9%86%D8%AF%D8%B1%D9%88%DB%8C%D8%AF-q2rnkld3nygb</link>
                <description>سلام شاید شما هم یه برنامه قدیمی دارید که تو یه مارکت منتشر کردید و از ابزار های قدیمی توی برنامه تون استفاده کردین، مثلا با جاوا کد زدین از volley استفاده کردین یا کلی چیز دیگه که بعضی از اینا رو میشه به راحتی تغییر داد .مثلا کد جدید که ریفکتور کردین رو با retrofit بزنین. اما تو بعضی موارد  نیازه یه کارایی بکنین تا از ابزار جدید بشه استفاده کرد. یکی از همین موارد اینه که بخواین از دیتابیس sqlite به room مهاجرت کنین . تو این مورد باید حواستون باشه اطلاعات قدیمی کاربر بعد به روز رسانی حذف نشن یه وقت و یه عالمه فیدبک منفی نگیرین . مستقیما بریم سمت راه حل و اینکه جیکار باید بکنیم.مرحله اول: مدل‌ها و DAOهای جدیدتون رو  تو  کاتلین تعریف کنید. به عنوان مثال://model@Entity(tableName = &amp;quotyour_table&amp;quot)
data class YourEntity(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = &amp;quotid&amp;quot)
    var id: Int,

    @ColumnInfo(name = &amp;quotname&amp;quot)
    var name:String ,

    @ColumnInfo(name = &amp;quotphone&amp;quot)
    var phone:String?
)//DAO@Dao 
interface YourDao {   
@Query(&amp;quotSELECT * FROM your_table&amp;quot) fun getAll(): List&lt;YourEntity&gt;
}مرحله دوم: ایجاد کلاس RoomDatabaseنکته: برای نوشتن کد مهاجرت (Migration) از SQLite به Room، باید مطمئن شید که ساختار جدول و نام ستون‌ها تو هر دو نسخه یکسان هستند. با توجه به اسکیمای دیتابیس قدیمی و اینتیتی جدید، می‌تونید کد مهاجرت رو به صورت زیر بنویسید:اگر از hilt به عنوان dependency injection استفاده می کنید کلاس AppDatabase خودتون را به شکل زیر provide کنید:@Singleton
@Provides
 fun provideDb(@ApplicationContext context: Context, ): AppDatabase {
        return Room.databaseBuilder(context, AppDatabase::class.java, AppDatabase.DATABASE_NAME)
            .allowMainThreadQueries()
            .fallbackToDestructiveMigration()
            .addMigrations(AppDatabase.MIGRATION_1_2)
            .build()
}و کلاس AppDataBase رو به شکل زیر بسازید:@Database(
    entities = [
        YourEntity::class
       ],
    version = 2
)
abstract class AppDatabase : RoomDatabase() {

    abstract fun yourDao(): YourDao 
    companion object {
//حواستون باشه اسم دیتابیس همون چیزی باشه که تو ورژن قبلی بود
        val DATABASE_NAME: String = &amp;quotنام دیتابیس&amp;quot
        val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
//پیاده سازی در ادامه توضیح داده خواهد شد
}
}اما اگه از hilt استفاده نمی کنید کلاس AppDatabsae شما به این شکل میشه:@Database(entities = [YourEntity::class], version = 2) 
abstract class AppDatabase : RoomDatabase() {   
 abstract fun yourDao(): YourDao    
 companion object {     
    @Volatile
 private var INSTANCE: AppDatabase? = null
 fun getDatabase(context: Context): AppDatabase {     
        return INSTANCE ?: synchronized(this) {       
          val instance = Room.databaseBuilder(         
            context.applicationContext, 
AppDatabase::class.java, 
//حواستون باشه اسم دیتابیس همون چیزی باشه که تو ورژن قبلی بود
 &amp;quotنام دیتابیس&amp;quot          
      ).addMigrations(MIGRATION_1_2).build()       
          INSTANCE = instance       
          instance             
}        
 }     
     val MIGRATION_1_2 = object : Migration(1, 2) {             
override fun migrate(database: SupportSQLiteDatabase) {
//پیاده سازی در ادامه
}
}نکته اول: آبجکتی که از نوع Migration ساختیم دوتا int توی کانسترکتور خودش می گیره که اولی نسخه قبلی دیتابیستونه و دومی نسخییه که الان داریم اگه این دوتا درست نباشن مهاجرت اتفاق نمیفته.نکته دوم:کلمه کلیدی @Volatile برای تضمین این استفاده می‌شه که متغیر INSTANCE همیشه به‌روزترین مقدار خودش رو  برای تمام نخ‌ها (threads) به اشتراک بگذاره. با این کار، از شرایط رقابتی (race conditions) جلوگیری می‌شه که ممکنه باعث شه چندین نمونه از کلاس AppDatabase ایجاد شه.مرحله سوم : override کردن فانکشن migrateتو این مرحله که تقریبا مرحله آخرمونه توی فانکشن migrate که override کردیم کوئری هی خودمون رو می نویسیم مثل این مثال :override fun migrate(database: SupportSQLiteDatabase) {   

              // Create the new table          
      database.execSQL(&amp;quot&amp;quot&amp;quotCREATE TABLE IF NOT EXISTS `your_new_table` (            
             `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,                    
     `name` TEXT NOT NULL,
`phone` TEXT ) 
   &amp;quot&amp;quot&amp;quot.trimIndent())    
     // Copy the data            
    database.execSQL(&amp;quot&amp;quot&amp;quot INSERT INTO `your_new_table` (`id`, `name`, `phone`)                     SELECT `id`, `name`, `phone`  FROM `your_table` 
 &amp;quot&amp;quot&amp;quot.trimIndent())          

        // Remove the old table         
       database.execSQL(&amp;quotDROP TABLE `your_table`&amp;quot)     

             // Rename the new table to the old table name        
        database.execSQL(&amp;quotALTER TABLE `your_new_table` RENAME TO `your_table`&amp;quot)      
       }خب کاری که کردیم اینه :یه table جدید ساختیم با یه اسم جدید( مثلا به آخر همون اسم table قدیمی یه new اضافه کنید.)اطلاعات table قدیمی رو کپی کردیم تو table جدید.بعد table قدیمی رو پاک کردیم در آخر اسم table جدید رو همونی کردیم که تو ورژن قبلی بود (حواستون به اسم table باشه با ورژن قدیمی متفاوت نباشه )تمام شد به همین راحتی فقط یه مورد دیگه اضافه کنم  اگر table جدیدی به دیتابیستون اضافه شده تو متد migrate باید بسازیدش (فقط CREATE TABLE IF NOT EXISTS)امیدوارم این مطلب براتون مفید باشه و لذت برده باشید. تا دیداری دیگر بدرود...</description>
                <category>سعید غفاری</category>
                <author>سعید غفاری</author>
                <pubDate>Tue, 23 Jul 2024 18:44:28 +0330</pubDate>
            </item>
            </channel>
</rss>