Android Kotlin语言下的文件存储
目录
将数据存储到文件中
创建文件和保存数据
Context
类中提供了一个openFileOutput()
方法,可以用于将数据存储到指定的文件中。这个方法接收两个参数:第一个参数是文件名,在文件创建的时候使用,注意这里指定的文件名不可以包含路径,因为所有的文件都默认存储到/data/data/<package name>/files/目录下;第二个参数是文件的操作模式,主要有MODE_PRIVATE
和MODE_APPEND
两种模式可选,默认是MODE_PRIVATE
,表示当指定相同文件名的时候,所写入的内容将会覆盖原文件中的内容,而MODE_APPEND
则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件。其实文件的操作模式本来还有另外两种:MODE_WORLD_READABLE
和MODE_WORLD_WRITEABLE
。这两种模式表示允许其他应用程序对我们程序中的文件进行读写操作,不过由于这两种模式过于危险,很容易引起应用的安全漏洞,已在Android 4.2版本中被废弃。
openFileOutput()
方法返回的是一个FileOutputStream
对象,得到这个对象之后就可以使用Java流的方式将数据写入文件中了。以下是一段简单的代码示例,展示了如何将一段文本内容保存到文件中:
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
对象,得到这个对象之后,再通过流的方式就可以将数据读取出来了。
以下是一段简单的代码示例,展示了如何从文件中读取文本数据:
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_READABLE
和MODE_WORLD_WRITEABLE
这两种模式是在Android 4.2版本中被废弃的,MODE_MULTI_PROCESS
模式是在Android 6.0版本中被废弃的。 -
Activity
类中的getPreferences()
方法这个方法和Context中的
getSharedPreferences()
方法很相似,不过它只接收一个操作模式参数,因为使用这个方法时会自动将当前Activity
的类名作为SharedPreferences的文件名。得到了
SharedPreferences
对象之后,就可以开始向SharedPreferences文件中存储数据了,主要可以分为3步实现。(1) 调用
SharedPreferences
对象的edit()
方法获取一个SharedPreferences.Editor
对象。(2) 向
SharedPreferences.Editor
对象中添加数据,比如添加一个布尔型数据就使用putBoolean()
方法,添加一个字符串则使用putString()
方法,以此类推。(3) 调用
apply()
方法将添加的数据提交,从而完成数据存储操作。
?代码示例如下
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
方法都接收两个参数:第一个参数是键,传入存储数据时使用的键就可以得到相应的值了;第二个参数是默认值,即表示当传入的键找不到对应的值时会以什么样的默认值进行返回。
代码示例如下
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()
方法也会得到执行,所以通常会在这里处理一些创建表的逻辑。
我们建立一个代码示例如下:
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) {
}
}
调用数据库
val myDatabaseHelper =MyDatabaseHelper(this,"databaseName",1)
myDatabaseHelper.writableDatabase
操作数据库
增
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)
删
db.delete(tableName, "key2 = ? and key3 = ? ", arrayOf("2.2","2"))
改
val value3 = ContentValues().apply {
put("key1", "444")
}
db.update(tableName, value3, "key2 = ?", arrayOf("1.1"))
查
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,示例代码如下:
val myDatabaseHelper = MyDatabaseHelper(this, databaseName, 2)
然后我们在onUpgrade方法中编写升级逻辑,代码如下:
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方法中编写如下代码:
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字段了
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!