Android 中存取文件位置有三种,而且每种各有其读取方式。
- apk 中的只读资源文件
 - SD 卡中的文件
 - 数据区的文件(/data)
 
1. 资源文件的读取
有两种资源文件 raw 和 assets,使用以下两种不同的方式读取:
val rawInputStream = context.resources.openRawResource(R.raw.test)
val assetsInputStream = context.assets.open(fileName) 
2. SD 卡数据读写
2.1 获取权限
根据需要在 manifest 中加入以下内容:
<!--写-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--读-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--创建修改-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
2.2 判断 SD 卡状态
Environment.getExternalStorageState()
如果手机装有 SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED。
2.3 获取 SD 卡根目录
Environment.getExternalStorageDirectory()
2.4 读写
val file = File(Environment.getExternalStorageDirectory(), "a.txt")
val inputStream = FileInputStream(file)
val outStream = FileOutputStream(file)
3. 数据区读写
3.1 写操作
val fout = openFileOutput(fileName, Context.MODE_PRIVATE)
3.2 读操作
val fin = openFileInput(fileName)
3.3 写操作中的使用模式
MODE_APPEND:向文件尾写入数据
MODE_PRIVATE:仅该程序可写入数据
MODE_WORLD_READABLE:所有程序均可读该文件数据
MODE_WORLD_WRITABLE:所有程序均可写入数据
4. File 读写数据区示例
4.1 创建文件夹
private fun makeDir() {
  folder = File(filesDir, folderName)
  if (folder.exists()) {
    log("Directory \"${folder.path}\" existed.")
  } else {
    folder.mkdir()
    log("Create directory \"${folder.path}\".")
  }
}
4.2 新建并写文件
private fun createFile() {
  file = File(folder, fileName)
  if (file.exists()) {
    log("File \"${file.path}\" existed.")
  } else {
    try {
      file.createNewFile()
      file.appendText("Hello.\n")
      log("Create \"${file.path}\" with \"Hello.\"")
    } catch (e: Exception) {
      e.printStackTrace()
    }
  }
}
4.3 读文件
private fun readFile() {
  if (file.isFile) {
    try {
      log("Content from \"${file.path}\": ${file.readText(Charset.forName("UTF-8"))}")
    } catch (e: Exception) {
      e.printStackTrace()
    }
  }
}
4.4 复制
private fun copyFile() {
  copyFile = File(folder, copyName)
  if (file.isFile && !copyFile.isFile) {
    file.copyTo(copyFile)
    log("Copy \"${file.path}\" to \"${copyFile.path}\"")
  }
}
4.5 遍历
private fun listFileNames() {
  log("Files includes in ${folder.name}: ")
  log("--------")
  folder.listFiles().forEach {
    log(it.name)
  }
  log("--------")
}
4.6 递归删除文件夹
private fun deleteFolder() {
  folder.deleteRecursively()
}
4.7 变量及其它
private fun log(msg: String) {
  Log.d(javaClass.simpleName, msg)
  outStr += msg
  outStr += "\n\n"
}
private lateinit var folder: File
private lateinit var file: File
private lateinit var copyFile: File
private var outStr = ""
companion object {
  private val folderName = "xandeer"
  private val fileName = "a.txt"
  private val copyName = "a_copy.txt"
}
4.8 运行结果

点击菜单 View -> Tool Windows -> Device File Explorer ,可查看当前虚拟机的文件系统,在 /data/user/0/me.xandeer.examples/files 中即可看到示例中添加的文件夹和文件。
