Android数据存储技术

一、文件存储

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent" ><EditTextandroid:id="@+id/editText"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="Type something here"/>
</LinearLayout>
package com.jpc.filepersistencetestimport android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.EditText
import android.widget.Toast
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.lang.StringBuilderclass MainActivity : AppCompatActivity() {private lateinit var editText: EditTextoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)editText = findViewById<EditText>(R.id.editText)val fileData = load()if (fileData.isNotEmpty()) {// 调用EditText的setText()方法将内容填充到EditText//里,并调用setSelection()方法将输入光标移动到文本的末尾位置以便继续输入editText.setText(fileData)editText.setSelection(fileData.length)Toast.makeText(this, "数据已恢复", Toast.LENGTH_SHORT).show()}}// 在销毁时保存数据到文件中
//    override fun onDestroy() {
//        super.onDestroy()
//        val inputText = editText.text.toString()
//        save(inputText)
//    }private fun save(inputText: String){// 保存数据到TXT文件中,文件名dataval output = openFileOutput("data", Context.MODE_PRIVATE)val writer = BufferedWriter(OutputStreamWriter(output))writer.use {it.write(inputText)}}// 从文件中加载数据private fun load():String {val builder = StringBuilder()val input = openFileInput("data")val reader = BufferedReader(InputStreamReader(input))reader.use {reader.forEachLine {builder.append(it)}}return builder.toString()}
}

二、SharedPreferences存储

不同于文件的存储方式,SharedPreferences是使用键值对的方式来存储数据的。当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过这个键把相应的值取出来。SharedPreferences还支持多种不同的数据类型存储,如果存储的数据类型是整型,那么读取出来的数据也是整型的;如果存储的数据是一个字符串,那么读取出来的数据仍然是字符串。

<Buttonandroid:id="@+id/btn_save_SharedPreferences"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="保存数据"/>
// 指定SharedPreferences的文件名为data,并得到了//SharedPreferences.Editor对象。接着向这个对象中添加了3条不同类型的数据,最//后调用apply()方法进行提交,从而完成了数据存储的操作val btnSave: Button = findViewById<Button>(R.id.btn_save_SharedPreferences)btnSave.setOnClickListener{val editor = getSharedPreferences("data", Context.MODE_PRIVATE).edit()editor.putString("name", "Tom")editor.putInt("age", 28)editor.putBoolean("married", false)editor.apply()}
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map><string name="name">Tom</string><boolean name="married" value="false" /><int name="age" value="28" />
</map>

SharedPreferences对象中提供了一系列的get方法,用于读取存储的数据,每种get方法都对应了SharedPreferences.Editor中的一种put方法,比如读取一个布尔型数据就使用getBoolean()方法,读取一个字符串就使用getString()方法。这些get方法都接收两个参数:第一个参数是键,传入存储数据时使用的键就可以得到相应的值了;第二个参数是默认值,即表示当传入的键找不到对应的值时会以什么样的默认值进行返回。

val btnRestore = findViewById<Button>(R.id.btn_restore_SharedPreferences)btnRestore.setOnClickListener{val prefs = getSharedPreferences("data", Context.MODE_PRIVATE)val name = prefs.getString("name", "")val age = prefs.getInt("age", 0)val married = prefs.getBoolean("married", false)Toast.makeText(this, "我的信息:${name}-${age}-${married}", Toast.LENGTH_SHORT).show()}
1、记住密码功能
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><CheckBoxandroid:id="@+id/rememberPass"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="18sp"android:text="Remember password" /></LinearLayout><Buttonandroid:id="@+id/login"android:layout_width="match_parent"android:layout_height="60dp"android:text="Login" />
</LinearLayout>
class LoginActivity : BaseActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_login)val prefs = getPreferences(Context.MODE_PRIVATE)
www.blogss.cnval isRemember = prefs.getBoolean("remember_password", false)if (isRemember) {// 将账号和密码都设置到文本框中val account = prefs.getString("account", "")val password = prefs.getString("password", "")accountEdit.setText(account)passwordEdit.setText(password)rememberPass.isChecked = true}login.setOnClickListener {val account = accountEdit.text.toString()val password = passwordEdit.text.toString()// 如果账号是admin且密码是123456,就认为登录成功if (account == "admin" && password == "123456") {val editor = prefs.edit()if (rememberPass.isChecked) { // 检查复选框是否被选中editor.putBoolean("remember_password", true)editor.putString("account", account)editor.putString("password", password)} else {// 如果没有被选中,就简单地调用一下clear()方法,
// 将SharedPreferences文件中的数据全部清除掉。editor.clear()}editor.apply()val intent = Intent(this, MainActivity::class.java)startActivity(intent)finish()} else {Toast.makeText(this, "account or password is invalid",Toast.LENGTH_SHORT).show()}}}
}

三、 SQLite数据库存储

显然,文件存储和SharedPreferences存储只适用于保存一些简单的数据和键值对。
但是,Android系统是内置了数据库的,SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百KB的内存就足够了,因而特别适合在移动设备上使用。SQLite不仅支持标准的SQL语法,还遵循了数据库的ACID事务。

1、创建数据库
package com.jpc.filepersistencetestimport android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toastclass MyDatabaseHelper(private val context: Context, name: String, version: Int):SQLiteOpenHelper(context, name, null, version) {// 建表语句private val createBook = "create table Book (" +"id integer primary key autoincrement," +"name text," +"author text," +"price real," +"pages integer)"override fun onCreate(db: SQLiteDatabase?) {db?.execSQL(createBook)Toast.makeText(context, "建表成功", Toast.LENGTH_SHORT).show()}override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {}
}
// 构建了一个MyDatabaseHelper对象,并且通过构造函数的参//数将数据库名指定为BookStore.db,版本号指定为1,然后在“Create Database”按钮的点击//事件里调用了getWritableDatabase()方法。val btnCreateDataBase = findViewById<Button>(R.id.btn_create_database)val databaseHelper = MyDatabaseHelper(this, "BookStore.db", 1)btnCreateDataBase.setOnClickListener{databaseHelper.writableDatabase}
2、升级数据库

SQLiteOpenHelper的构造方法里接收的第四个参数,它表示当前数据库的版本号,之前我们传入的是1,现在只要传入
一个比1大的数,就可以让onUpgrade()方法得到执行了。

package com.jpc.filepersistencetestimport android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.widget.Toastclass MyDatabaseHelper(private val context: Context, name: String, version: Int):SQLiteOpenHelper(context, name, null, version) {// 建表语句private val createBook = "create table Book (" +"id integer primary key autoincrement," +"name text," +"author text," +"price real," +"pages integer)"private val createCategory = "create table Category (" +"id integer primary key autoincrement," +"category_name text," +"category_code integer)"override fun onCreate(db: SQLiteDatabase?) {db?.execSQL(createBook)db?.execSQL(createCategory)Toast.makeText(context, "建表成功", Toast.LENGTH_SHORT).show()}override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {// 先删除已经存在的表db?.execSQL("drop table if exists Book")db?.execSQL("drop table if exists Category")// 再重新创建onCreate(db)}
}
// 第一次创建数据库,版本version为1// val databaseHelper = MyDatabaseHelper(this, "BookStore.db", 1)// 升级数据库,将版本改为比上一次大的数值,就会调用onUpgrade方法val databaseHelper = MyDatabaseHelper(this, "BookStore.db", 2)btnCreateDataBase.setOnClickListener{databaseHelper.writableDatabase}
3、添加数据

调用SQLiteOpenHelper的getReadableDatabase()或
getWritableDatabase()方法是可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个SQLiteDatabase对象,借助这个对象就可以对数据进行CRUD操作了。
SQLiteDatabase中提供了一个 insert() 方法,专门用于添加数据。它接收3个参数:第一个参数是表名,我们希望向哪张表里添加数据,这里就传入该表的名字;第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般我们用不到这个功能,直接传入null即可;第三个参数是一个ContentValues对象,它提供了一系列的put()方法重载,用于向ContentValues中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。

<Buttonandroid:id="@+id/btn_add_data"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="向表添加数据"/>
// 添加数据val btnAddData = findViewById<Button>(R.id.btn_add_data)btnAddData.setOnClickListener{val db = databaseHelper.writableDatabaseval data1 = ContentValues().apply {// 第一条数据// 不需要给id赋值,因为id自增put("name", "The Da Vinci Code")put("author", "Dan Brown")put("pages", 454)put("price", 16.96)}// 插入第一条数据db.insert("Book", null, data1)val values2 = ContentValues().apply {// 开始组装第二条数据put("name", "The Lost Symbol")put("author", "Dan Brown")put("pages", 510)put("price", 19.95)}db.insert("Book", null, values2) // 插入第二条数据}
4、修改数据

SQLiteDatabase中提供了一个非常好用的update()方法,用于对数据进行更新。这个方法接收4个参数:第一个参数和insert()方法一样,也是表名,指定更新哪张表里的数据;第二个参数是ContentValues对象,要把更新数据在这里组装进去;第三、第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认会更新所有行。

// 修改数据val btnUpdate = findViewById<Button>(R.id.btn_update_data)btnUpdate.setOnClickListener{val db = databaseHelper.writableDatabaseval contentValues = ContentValues()contentValues.put("price", 10.99)// 第三、第四个参数来指定具体更新//哪几行。第三个参数对应的是SQL语句的where部分,表示更新所有name等于?的行,而?是一//个占位符,可以通过第四个参数提供的一个字符串数组为第三个参数中的每个占位符指定相应//的内容,arrayOf()方法是Kotlin提供的一种用于便捷创建数组的内置方法db.update("Book", contentValues, "name = ?", arrayOf("The Da Vinci Code"))}
5、删除数据

SQLiteDatabase中提供了一个delete()方法,专门用于删除数据。这个方法接收3个参数:第一个参数仍然是表名,这个没什么好说的;第二、第三个参数用于约束删除某一行或某几行的数据,不指定的话默认会删除所有行。

// 删除数据val btnDelete = findViewById<Button>(R.id.btn_delete_data)btnDelete.setOnClickListener{val db = databaseHelper.writableDatabase// 指定删除条件,即where字句,如果不指定就会删除表中所有的数据db.delete("Book", "pages > ?", arrayOf("500"))}
6、查询数据

SQLiteDatabase中还提供了一个query()方法用于对数据进行查询。这个方法的参数非常复杂,最短的一个方法重载也需要传入7个参数。那我们就先来看一下这7个参数各自的含义吧。第一个参数不用说,当然还是表名,表示我们希望从哪张表中查询数据。
第二个参数用于指定去查询哪几列,如果不指定则默认查询所有列。第三、第四个参数用于约束查询某一行或某几行的数据,不指定则默认查询所有行的数据。第五个参数用于指定需要去group by的列,不指定则表示不对查询结果进行group by操作。第六个参数用于对group by之后的数据进行进一步的过滤,不指定则表示不进行过滤。第七个参数用于指定查询结果的排序方式,不指定则表示使用默认的排序方式。调用query()方法后会返回一个Cursor对象,查询到的所有数据都将从这个对象中取出。
在这里插入图片描述

        // 查询数据val btnQuery = findViewById<Button>(R.id.btn_query_data)btnQuery.setOnClickListener{val db = databaseHelper.writableDatabase// 查询Book表中的所有数据val cursor = db.query("Book", null, null, null, null, null, null)if (cursor.moveToFirst()) {do {// 遍历Cursor对象,取出数据并打印// 要检查参数,不然报错var index1 = if (cursor.getColumnIndex("name") >= 0) cursor.getColumnIndex("name") else 0val name = cursor.getString(index1)index1 = if (cursor.getColumnIndex("author") >= 0) cursor.getColumnIndex("author") else 0val author = cursor.getString(index1)index1 = if (cursor.getColumnIndex("pages") >= 0) cursor.getColumnIndex("pages") else 0val pages = cursor.getInt(index1)index1 = if (cursor.getColumnIndex("price") >= 0) cursor.getColumnIndex("price") else 0val price = cursor.getDouble(index1)Toast.makeText(this, "查询到数据:${name}-${author}-${pages}-${price}", Toast.LENGTH_SHORT).show()}while (cursor.moveToNext())}// 需要关闭Cursor对象cursor.close()}
7、使用SQL语句操作数据库
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",arrayOf("The Da Vinci Code", "Dan Brown", "454", "16.96")
)
db.execSQL("insert into Book (name, author, pages, price) values(?, ?, ?, ?)",arrayOf("The Lost Symbol", "Dan Brown", "510", "19.95")
)db.execSQL("update Book set price = ? where name = ?", arrayOf("10.99", "The Da Vinci Code"))db.execSQL("delete from Book where pages > ?", arrayOf("500"))val cursor = db.rawQuery("select * from Book", null)
8、使用事务
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val dbHelper = MyDatabaseHelper(this, "BookStore.db", 2)...replaceData.setOnClickListener {val db = dbHelper.writableDatabasedb.beginTransaction() // 开启事务try {db.delete("Book", null, null)
if (true) {// 手动抛出一个异常,让事务失败throw NullPointerException()}val values = ContentValues().apply {put("name", "Game of Thrones")put("author", "George Martin")put("pages", 720)put("price", 20.85)}db.insert("Book", null, values)db.setTransactionSuccessful() // 事务已经执行成功} catch (e: Exception) {e.printStackTrace()} finally {db.endTransaction() // 结束事务}}}
}
9、升级数据库的最佳写法
class MyDatabaseHelper(val context: Context, name: String, version: Int):SQLiteOpenHelper(context, name, null, version) {private val createBook = "create table Book (" +" id integer primary key autoincrement," +"author text," +"price real," +"pages integer," +"name text," +"category_id integer)"private val createCategory = "create table Category (" +"id integer primary key autoincrement," +"category_name text," +"category_code integer)"override fun onCreate(db: SQLiteDatabase) {db.execSQL(createBook)db.execSQL(createCategory)}override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {if (oldVersion <= 1) {db.execSQL(createCategory)}if (oldVersion <= 2) {db.execSQL("alter table Book add column category_id integer")}}
}

可以看到,首先我们在Book表的建表语句中添加了一个category_id列,这样当用户直接安装第3版的程序时,这个新增的列就已经自动添加成功了。然而,如果用户之前已经安装了某一版本的程序,现在需要覆盖安装,就会进入升级数据库的操作中。在onUpgrade()方法里,我们添加了一个新的条件,如果当前数据库的版本号是2,就会执行alter命令,为Book表新增一个category_id列。这里请注意一个非常重要的细节:每当升级一个数据库版本的时候,onUpgrade()方法里都一定要写一个相应的if判断语句。为什么要这么做呢?这是为了保证App在跨版本升级的时候,每一次的数据库修改都能被全部执行。比如用户当前是从第2版升级到第3版,那么只有第二条判断语句会执行,而如果用户是直接从第1版升级到第3版,那么两条判断语句都会执行。使用这种方式来维护数据库的升级,不管版本怎样更新,都可以保证数据库的表结构是最新的,而且表中的数据完全不会丢失。

10、简化写法
// 简化后的写法getSharedPreferences("data", Context.MODE_PRIVATE).edit{putString("name", "Tom")putInt("age", 28)putBoolean("married", false)}
// 使用更新的函数val values = contentValuesOf("name" to "Game of Thrones", "author" to "George Martin","pages" to 720, "price" to 20.85)db.insert("Book", null, values)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/794782.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac 切换 jdk

查看 mac 上都有哪些版本 /usr/libexec/java_home -V看准版本切换 按前缀切换 比如 export JAVA_HOME/usr/libexec/java_home -v 1.8这样会随机一个 1.8 的 如果想再确定一个比如 openjdk export JAVA_HOME/usr/libexec/java_home -v 1.8.0_292这个方式是临时的&#xff0c…

【力扣刷题日记】1421.净现值查询

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1421.净现值查询 表&#xff1a;NPV 列名类型idintyearintnpvint (id, year) 是该表主键(具有唯一值的列的…

用友NC Cloud importhttpscer 任意文件上传漏洞复现

0x01 产品简介 用友 NC Cloud 是一种商业级的企业资源规划云平台,为企业提供全面的管理解决方案,包括财务管理、采购管理、销售管理、人力资源管理等功能,基于云原生架构,深度应用新一代数字技术,打造开放、 互联、融合、智能的一体化云平台,支持公有云、混合云、专属云…

AI绘画:实例-利用Stable Diffusion ComfyUI实现多图连接:区域化提示词与条件设置

在Stable Diffusion ComfyUI中&#xff0c;有一种高级技巧可以让用户通过细致的区域化提示词来控制图像的不同部分&#xff0c;从而实现多图连接的效果。这种方法允许艺术家在同一画布上展现多个场景&#xff0c;创造出富有层次和故事性的图像。以下是实现这一效果的详细步骤。…

Leetcode链表刷题总结(Java版)

链表 1、移除链表元素&#xff08;考虑全情况&#xff09; 问题需求&#xff1a;根据给定的val值&#xff0c;移除链表中值是这个val的节点 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 这里有一个问题就是&#xff0c;如果需要被移除的节点不是中间的某个节点…

Tuxera2023 NTFS for Mac下载,安装和序列号激活

对于必须在Windows电脑和Mac电脑之间来回切换的Mac朋友来说&#xff0c;跨平台不兼容一直是一个巨大的障碍&#xff0c;尤其是当我们需要使用NTFS格式的硬盘在Windows和macOS之间共享文件时。因为Mac默认不支持写入NTFS磁盘。 为了解决这一问题&#xff0c;很多朋友会选择很便捷…

【Java基础知识总结 | 第十篇】HashSet底层实现原理

文章目录 10.HashSet底层实现原理10.1HashSet特点10.2HashSet源码10.3 add流程10.4总结 10.HashSet底层实现原理 10.1HashSet特点 存储对象&#xff1a;HashSet 存储对象采用哈希表的方式&#xff0c;它不允许重复元素&#xff0c;即集合中不会包含相同的元素。当向 HashSet …

数据挖掘中的PCA和KMeans:Airbnb房源案例研究

目录 一、PCA简介 二、数据集概览 三、数据预处理步骤 四、PCA申请 五、KMeans 聚类 六、PCA成分分析 七、逆变换 八、质心分析 九、结论 十、深入探究 10.1 第 1 步&#xff1a;确定 PCA 组件的最佳数量 10.2 第 2 步&#xff1a;使用 9 个组件重做 PCA 10.3 解释 PCA 加载和特…

【微服务】------核心组件架构选型

1.微服务简介 微服务架构&#xff08;Microservice Architecture&#xff09;是一种架构概念&#xff0c;旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦&#xff0c;从而降低系统的耦合性&#xff0c;并提供更加灵活的服务支持。 2.微服务技术选型 区域内容…

Kotlin学习日志(一)TextView、Button、Toast的使用(1)

android:layout_width“wrap_content” android:layout_height“wrap_content”/> import kotlinx.android.synthetic.main.activity_main.* 这句话的意思是引进Kotlin的的控件变量自动映射功能&#xff0c;接下来只要是这个activity_main.xml文件中的控件&#xff0c;我…

蓝桥杯第十四届C++A组(未完)

【规律题】平方差 题目描述 给定 L, R&#xff0c;问 L ≤ x ≤ R 中有多少个数 x 满足存在整数 y,z 使得 。 输入格式 输入一行包含两个整数 L, R&#xff0c;用一个空格分隔。 输出格式 输出一行包含一个整数满足题目给定条件的 x 的数量。 样例输入 1 5 样例输出 …

OpenTofu路在何方:定量分析Terraform issue数据,洞察用户需求|OpenTofu Day 闪电演讲

数澈软件 Seal 首席架构师李平辉提交的演讲议题“Alias TerraformTofu. Job’s Done, Now What?”入选 KubeCon EU 同场活动 OpenTofu Day&#xff0c;本文为演讲实录。 大家好&#xff0c;我是 Lawrence&#xff0c;是 Seal 的首席架构师。今天将由我为大家带来 Lightening T…

后端开发框架Spring Boot快速入门

写在前面 推荐将本文与Spring Boot 相关知识和工具类一文结合起来看&#xff0c;本文为主&#xff0c;上面那篇文章为辅&#xff0c;一起食用&#xff0c;以达到最佳效果&#xff0c;当然&#xff0c;大佬随意。 IDEA创建Spring Boot工程 关于Spring Boot框架项目&#xff0…

第二节课《轻松玩转书生·浦语大模型趣味 Demo》

比较匆忙&#xff0c;假期前仿照第一期课程的内容好像被清空了&#xff0c;重新搭建一次。 https://github.com/InternLM/Tutorial/blob/camp2/helloworld/hello_world.md 按照那老师写好的&#xff0c;一步步复制就好了 浦语灵笔2的大概率是会超出显存&#xff0c;先不测试了…

MySQL-排序与分页

1. 排序 如果没有使用排序操作&#xff0c;默认情况下查询返回的数据是按照添加数据的顺序显示的。 SELECT * FROM employees;1.1 基本使用 1&#xff09;使用 ORDER BY 对查询到的数据进行排序操作。 升序&#xff1a;ASC(ascend)降序&#xff1a;DESC (descend) 练习&am…

2024.4.4-[作业记录]-day09-CSS 布局模型(标准流模型、浮动模型)

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 作业 2024.4.4-学习笔记1 CSS 布局模型1.1 标准流1.2 CSS 浮动1.3 去除塌陷 2…

【零基础学数据结构】顺序表实现书籍存储

目录 书籍存储的实现规划 ​编辑 前置准备&#xff1a; 书籍结构体&#xff1a; 书籍展示的初始化和文件加载 书籍展示的销毁和文件保存 书籍展示的容量检查 书籍展示的尾插实现 书籍展示的书籍增加 书籍展示的书籍打印 书籍删除展示数据 书籍展示修改数据 在指定位置之前…

SpamSieve mac垃圾邮件过滤器 直装激活版

SpamSieve通过强大的垃圾邮件过滤技术&#xff0c;帮助用户有效管理和消除不想要的电子邮件。它能与多种电子邮件客户端无缝集成&#xff0c;如Apple Mail、Microsoft Outlook、Airmail等。 软件下载&#xff1a;SpamSieve mac直装激活版下载 该软件利用先进的算法和机器学习技…

深度学习方法;乳腺癌分类

乳腺癌的类型很多&#xff0c;但大多数常见的是浸润性导管癌、导管原位癌和浸润性小叶癌。浸润性导管癌(IDC)是最常见的乳腺癌类型。这些都是恶性肿瘤的亚型。大约80%的乳腺癌是浸润性导管癌(IDC)&#xff0c;它起源于乳腺的乳管。 浸润性是指癌症已经“侵袭”或扩散到周围的乳…

TR3 - Transformer算法详解

目录 文本输入处理词向量位置向量 编码器 EncoderSelf-Attention多头注意力机制残差连接 解码器 Decoder线性层与Softmax损失函数总结与心得体会 这周来看一下Transformer是怎么将文本转换成向量&#xff0c;然后又输入到模型处理并得到最终的输出的。 文本输入处理 词向量 …