Android Kotlin语言下的文件存储

目录

将数据存储到文件中

创建文件和保存数据

读取文件

SharedPreferences存储

存储数据到SharedPreferences中

Context类中的getSharedPreferences()方法

Activity类中的getPreferences()方法

从SharedPreferences中读取数据

SQLite数据库存储

创建数据库

调用数据库

操作数据库

升级数据库


将数据存储到文件中

创建文件和保存数据

Context类中提供了一个openFileOutput()方法,可以用于将数据存储到指定的文件中。这个方法接收两个参数:第一个参数是文件名,在文件创建的时候使用,注意这里指定的文件名不可以包含路径,因为所有的文件都默认存储到/data/data/<package name>/files/目录下;第二个参数是文件的操作模式,主要有MODE_PRIVATEMODE_APPEND两种模式可选,默认是MODE_PRIVATE,表示当指定相同文件名的时候,所写入的内容将会覆盖原文件中的内容,而MODE_APPEND则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件。其实文件的操作模式本来还有另外两种:MODE_WORLD_READABLEMODE_WORLD_WRITEABLE。这两种模式表示允许其他应用程序对我们程序中的文件进行读写操作,不过由于这两种模式过于危险,很容易引起应用的安全漏洞,已在Android 4.2版本中被废弃。

openFileOutput()方法返回的是一个FileOutputStream对象,得到这个对象之后就可以使用Java流的方式将数据写入文件中了。以下是一段简单的代码示例,展示了如何将一段文本内容保存到文件中:

Kotlin 复制代码
    fun saveFile(saveString: String) {
        val output = openFileOutput("fileName", Context.MODE_PRIVATE)
        val writer = BufferedWriter(OutputStreamWriter(output))
        writer.use {
            it.write(saveString)
        }
    }

这里通过openFileOutput()方法能够得到一个FileOutputStream对象,然后借助它构建出一个OutputStreamWriter对象,接着再使用OutputStreamWriter构建出一个BufferedWriter对象,这样你就可以通过BufferedWriter将文本内容写入文件中了。

注意,这里还使用了一个use函数,这是Kotlin提供的一个内置扩展函数。它会保证在Lambda表达式中的代码全部执行完之后自动将外层的流关闭,这样就不需要我们再编写一个finally语句,手动去关闭流了,是一个非常好用的扩展函数。

另外,Kotlin是没有异常检查机制(checked exception)的。这意味着使用Kotlin编写的所有代码都不会强制要求你进行异常捕获或异常抛出。即使你不写try catch代码块,在Kotlin中依然可以编译通过。

读取文件

类似于将数据存储到文件中,Context类中还提供了一个openFileInput()方法,用于从文件中读取数据。这个方法要比openFileOutput()简单一些,它只接收一个参数,即要读取的文件名,然后系统会自动到/data/data/<package name>/files/目录下加载这个文件,并返回一个FileInputStream对象,得到这个对象之后,再通过流的方式就可以将数据读取出来了。

以下是一段简单的代码示例,展示了如何从文件中读取文本数据:

Kotlin 复制代码
    fun loadFile(): String {
        val stringBuilder = StringBuilder()
        val input = openFileInput("fileName")
        val reader = BufferedReader(InputStreamReader(input))
        reader.use {
            reader.forEachLine {
                stringBuilder.append(it)
            }
        }
        return stringBuilder.toString()
    }

在这段代码中,首先通过openFileInput()方法获取了一个FileInputStream对象,然后借助它又构建出了一个InputStreamReader对象,接着再使用InputStreamReader构建出一个BufferedReader对象,这样我们就可以通过BufferedReader将文件中的数据一行行读取出来,并拼接到StringBuilder对象当中,最后将读取的内容返回就可以了。

注意,这里从文件中读取数据使用了一个forEachLine函数,这也是Kotlin提供的一个内置扩展函数,它会将读到的每行内容都回调到Lambda表达式中,我们在Lambda表达式中完成拼接逻辑即可。

SharedPreferences存储

存储数据到SharedPreferences中

要想使用SharedPreferences存储数据,首先需要获取SharedPreferences对象。Android中主要提供了以下两种方法用于得到SharedPreferences对象。

Context类中的getSharedPreferences()方法

此方法接收两个参数:第一个参数用于指定SharedPreferences文件的名称,如果指定的文件不存在则会创建一个,SharedPreferences文件都是存放在/data/data/<package name>/shared_prefs/目录下的;第二个参数用于指定操作模式,目前只有默认的MODE_PRIVATE这一种模式可选,它和直接传入0的效果是相同的,表示只有当前的应用程序才可以对这个SharedPreferences文件进行读写。其他几种操作模式均已被废弃,MODE_WORLD_READABLEMODE_WORLD_WRITEABLE这两种模式是在Android 4.2版本中被废弃的,MODE_MULTI_PROCESS模式是在Android 6.0版本中被废弃的。
2.

Activity类中的getPreferences()方法

这个方法和Context中的getSharedPreferences()方法很相似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前Activity的类名作为SharedPreferences的文件名。

得到了SharedPreferences对象之后,就可以开始向SharedPreferences文件中存储数据了,主要可以分为3步实现。

(1) 调用SharedPreferences对象的edit()方法获取一个SharedPreferences.Editor对象。

(2) 向SharedPreferences.Editor对象中添加数据,比如添加一个布尔型数据就使用putBoolean()方法,添加一个字符串则使用putString()方法,以此类推。

(3) 调用apply()方法将添加的数据提交,从而完成数据存储操作。

代码示例如下

Kotlin 复制代码
    fun saveSharedPreferences(saveString: String){
        val edit = getSharedPreferences("fileName",Context.MODE_PRIVATE).edit()
        edit.putString("editName","editValue")
        edit.apply()
    }

从SharedPreferences中读取数据

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

代码示例如下

Kotlin 复制代码
    fun loadSharedPreferences(): String {
        val sharedPreferences = getSharedPreferences("fileName", Context.MODE_PRIVATE)
        return sharedPreferences.getString("editName", "defValue")!!
    }

SQLite数据库存储

创建数据库

Android为了让我们能够更加方便地管理数据库,专门提供了一个SQLiteOpenHelper帮助类,借助这个类可以非常简单地对数据库进行创建和升级。既然有好东西可以直接使用,那我们自然要尝试一下了,下面我就对SQLiteOpenHelper的基本用法进行介绍。

首先,你要知道SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它,就需要创建一个自己的帮助类去继承它。SQLiteOpenHelper中有两个抽象方法:onCreate()onUpgrade()。我们必须在自己的帮助类里重写这两个方法,然后分别在这两个方法中实现创建和升级数据库的逻辑。

SQLiteOpenHelper中还有两个非常重要的实例方法:getReadableDatabase()getWritableDatabase()。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则要创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。不同的是,当数据库不可写入的时候(如磁盘空间已满),getReadableDatabase()方法返回的对象将以只读的方式打开数据库,而getWritableDatabase()方法则将出现异常。

SQLiteOpenHelper中有两个构造方法可供重写,一般使用参数少一点的那个构造方法即可。这个构造方法中接收4个参数:第一个参数是Context,这个没什么好说的,必须有它才能对数据库进行操作;第二个参数是数据库名,创建数据库时使用的就是这里指定的名称;第三个参数允许我们在查询数据的时候返回一个自定义的Cursor,一般传入null即可;第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作。构建出SQLiteOpenHelper的实例之后,再调用它的getReadableDatabase()getWritableDatabase()方法就能够创建数据库了,数据库文件会存放在/data/data/<package name>/databases/目录下。此时,重写的onCreate()方法也会得到执行,所以通常会在这里处理一些创建表的逻辑。

我们建立一个代码示例如下:

Kotlin 复制代码
class MyDatabaseHelper(
    private val context: Context,
    private val databaseName: String,
    val version: Int
) : SQLiteOpenHelper(context, databaseName, null, version) {

    private val createTable = "create table tableName(id integer primary key autoincrement, " +
            "key1 text," +
            "key2 real," +
            "key3 integer)"

    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(createTable)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {

    }
}

调用数据库

Kotlin 复制代码
val myDatabaseHelper =MyDatabaseHelper(this,"databaseName",1)
myDatabaseHelper.writableDatabase

操作数据库

Kotlin 复制代码
val myDatabaseHelper = MyDatabaseHelper(this, "databaseName", 1)
val db = myDatabaseHelper.writableDatabase
val value1 = ContentValues().apply {
    put("key1", "111")
    put("key2", 1.1)
    put("key3", 1)
}
db.insert("tableName", null, value1)

val value2 = ContentValues().apply {
    put("key1", "222")
    put("key2", 2.2)
    put("key3", 2)
}
db.insert("tableName", null, value2)
Kotlin 复制代码
db.delete(tableName, "key2 = ? and key3 = ? ", arrayOf("2.2","2"))
Kotlin 复制代码
val value3 = ContentValues().apply {
            put("key1", "444")
        }
db.update(tableName, value3, "key2 = ?", arrayOf("1.1"))
Kotlin 复制代码
        val course = db.query(tableName, null, null, null, null, null, null)
        if (course.moveToFirst()) {
            do {
                println(course.getString(course3.getColumnIndex("key1")))
                println(course.getString(course.getColumnIndex("key2")))
                println(course.getString(course.getColumnIndex("key3")))
            } while (course.moveToNext())
        }
        course.close()

升级数据库

在MyDatabaseHelper类中,我们还有一个onUpgrade的方法没有使用,这个方法就是用来升级数据库的,当我们需要升级数据库时,改写MyDatabaseHelper的version,让它大于我们直接传入的数,这样就会自动调用onUpgrade,示例代码如下:

Kotlin 复制代码
val myDatabaseHelper = MyDatabaseHelper(this, databaseName, 2)

然后我们在onUpgrade方法中编写升级逻辑,代码如下:

Kotlin 复制代码
class MyDatabaseHelper(
    private val context: Context,
    private val databaseName: String,
    val version: Int
) : SQLiteOpenHelper(context, databaseName, null, version) {

    private val createTable = "create table tableName(id integer primary key autoincrement, " +
            "key1 text," +
            "key2 real," +
            "key3 integer)"

    private val createTable2 = "create table tableName2(id integer primary key autoincrement, " +
            "key1 text," +
            "key2 real," +
            "key3 integer)"

    override fun onCreate(db: SQLiteDatabase?) {
        db?.execSQL(createTable)
        db?.execSQL(createTable2)
    }

    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        if (oldVersion<=1){
            db?.execSQL(createTable2)
        }
    }
}

当原来的版本是1时,我们就创建表2,不然就执行onCreate方法,创建表1表2。如果后续我们需要再表1中增加一个字段 tableName_id,那么我们将传入的version改成3,再在onUpgrade方法中编写如下代码:

Kotlin 复制代码
    override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
        if (oldVersion<=1){
            db?.execSQL(createTable2)
        }
        if (oldVersion<=2){
            db?.execSQL("alter table tableName add column tableName_id integer")
        }
    }

这样我们就能在表1中新增一个tableName_id字段了

相关推荐
阿巴斯甜7 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker7 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95278 小时前
Andorid Google 登录接入文档
android
黄林晴10 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android