Android写入/ sdcard /

时间:2018-07-12 17:49:26

标签: android kotlin android-bitmap fileoutputstream

我需要将图像保存到/sdcard/sample/0/b/image.png。我尝试过:

val dir = File("/sdcard/sample/0/b/")
dir.mkdirs()

val image = File(dir, "image.png")
image.createNewFile()

var out: FileOutputStream? = null
try {
    out = FileOutputStream(image)
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
} finally {
    out?.close()
}

我总是收到那个文件不存在。另外,我尝试用Environment.getExternalStorageDirectory()。path替换“ / sdcard”,但结果是相同的。

java.io.IOException: No such file or directory
    at java.io.UnixFileSystem.createFileExclusively0(Native Method)
    at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:281)
    at java.io.File.createNewFile(File.java:1000)

在清单中,为了进行测试,我添加了

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE"/>

3 个答案:

答案 0 :(得分:0)

我应该使用

val permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE)
requestPermissions(permissions, 0x512)

即使我添加了权限来显示sdk-23

<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

答案 1 :(得分:0)

尝试使用:

val dir = File(Environment.getExternalStorageDirectory().absolutePath + "/b/")

如果没有SDCard,则将返回“ / storage / emulated / 0”或类似的值,具体取决于手机型号和android版本。 还请求权限。

答案 2 :(得分:0)

此答案将很长,但是可以解决,并且奖金代码包含所有步骤,该代码显示了如何优雅地管理权限。 OH要谦虚

首先,这段代码是用Kotlin编写的
为了清楚起见,您需要将此文件包含在清单文件文件夹中

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

我们将使用在Model数据类中声明的几个全局变量

companion object { var THE_PATH = "";var gv = 3 }

我们的LAUNCHER活动名为CheckStorageActivity,这是长代码
此活动检查用户是否有SD卡,然后根据检查结果向用户显示内部或外部存储对话框
在这种情况发生之前,尽管用户需要管理授予权限
警告中的重要提示:在真实设备上测试此代码,请参见代码中的注释

class CheckStorageActivity : AppCompatActivity() {

private val STORAGE_PERMISSION_CODE = 1
var STORAGE_LOCATION: Int = 3
var the_path = ""

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_check_storage)
    supportActionBar?.hide()

    val preferences = getSharedPreferences("FirstPreference", Context.MODE_PRIVATE)

    if (!preferences.getBoolean("isFirstTime", false)) {

        val sharedPreferences = getSharedPreferences("SecondPref", Context.MODE_PRIVATE)
        val editorshared = sharedPreferences.edit()
        editorshared.putString("DB_PATH", THE_PATH)
        editorshared.apply()

        val pref = getSharedPreferences("FirstPreference", Context.MODE_PRIVATE)
        val editor = pref.edit()
        editor.putBoolean("isFirstTime", true)
        editor.apply()
    }

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            // this only runs on re START APP 1
            val sharedPreferences = getSharedPreferences("SecondPref", Context.MODE_PRIVATE)
            the_path = sharedPreferences.getString("DB_PATH", "")

            if(the_path != ""){
                pathONLY()
            }
            //showIMAGE()?
        }
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            requestStoragePermission()
        }

}// end onCreate

fun pathALL(){

    val sharedPreferences = getSharedPreferences("SecondPref", Context.MODE_PRIVATE)
    the_path = sharedPreferences.getString("DB_PATH", "")

    val fi = File("storage/")
    val lst = fi.listFiles()
    val top = lst[1].toString()
    val bot = lst[0].toString()

    println("TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT top $top")
    // TOP VALUE ON EMULATOR storage/self
    // THIS MUST BE USED ON emulator to test
    // For real device use storage/emulated for top String variable
    // =============================================================
    println("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB bot $bot")
    // BOT VALUE ON EMULATOR storage/emulated
    // Do not use on Emulator it will NOT work

    if (top.contains("storage/self")) {
        STORAGE_LOCATION = 0
        internalDIALOG()
    }
    if (bot.contains("-")) {
        STORAGE_LOCATION = 1
        externalDIALOG()
    }
}

fun pathONLY(){

    val sharedPreferences = getSharedPreferences("SecondPref", Context.MODE_PRIVATE)
    the_path = sharedPreferences.getString("DB_PATH", "")
    THE_PATH = the_path
    val intent = Intent(this, MainActivity::class.java)
    startActivity(intent)
}

fun writeSharedPrefANDleave(){

    val sharedPreferences = getSharedPreferences("SecondPref", Context.MODE_PRIVATE)
    val editor = sharedPreferences.edit()
    editor.putString("DB_PATH", THE_PATH)
    editor.apply()

    val intent = Intent(this, MainActivity::class.java)
    startActivity(intent)
}

fun internalDIALOG() {

    val builder = AlertDialog.Builder(this)
    builder.setCancelable(false)

    builder.setTitle("SD Card NOT Mounted")
    builder.setMessage("\nClick OK to use INTERNAL Device Storage")
    builder.setNeutralButton("OK") { dialogInterface, i ->
        STORAGE_LOCATION == 0
        setThePath()

        writeSharedPrefANDleave()
    }
    builder.show()
}

fun externalDIALOG() {

    val builder = AlertDialog.Builder(this)
    builder.setCancelable(false)

    builder.setTitle("Select Data Storage Location ")
    builder.setMessage("EXTERNAL Use SD CARD\n\n" + "INTERNAL Device Storage")

    builder.setPositiveButton("EXTERNAL") { dialogInterface, i ->
        STORAGE_LOCATION = 1
        setThePath()

        writeSharedPrefANDleave()
    }
    builder.setNegativeButton("INTERNAL") { dialogInterface, i ->
        STORAGE_LOCATION = 0
        setThePath()

        writeSharedPrefANDleave()
    }
    builder.show()
}

fun setThePath(): String {

    val removable = ContextCompat.getExternalFilesDirs(this, null)[STORAGE_LOCATION]
    if (STORAGE_LOCATION == 1) {
        THE_PATH = removable.toString()
        THE_PATH = THE_PATH + "/Documents/"
    }
    if (STORAGE_LOCATION == 0) {
        THE_PATH = removable.toString()
        THE_PATH = THE_PATH + "/INTERNAL/"
    }
    return THE_PATH.trim()
}

companion object {var MANUALLY_SET = 1}
// Manage Navigation if Permission Manually Set
override fun onResume() {
    super.onResume()
    if(MANUALLY_SET == 2){
        pathALL()
    }
}

private fun requestStoragePermission() {
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {

        AlertDialog.Builder(this)
                .setTitle("To Write to DB Allow Permissions")
                .setMessage("On the Next Screen to Remove the App\n\nCheck Don't Ask Again and Click DENY\n\nOr Click ALLOW to Grant Permission")
                .setPositiveButton("NEXT") { dialog, id ->
                    ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), STORAGE_PERMISSION_CODE)
                }
                .create().show()
    } else {
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), STORAGE_PERMISSION_CODE)
    }
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    if (requestCode == STORAGE_PERMISSION_CODE) {

        if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            if(gv == 3){
                pathALL()
            }
            //showIMAGE()

        } else {
            if (Build.VERSION.SDK_INT >= 23 && !shouldShowRequestPermissionRationale(permissions[0])) {

                val alertDialogBuilder = AlertDialog.Builder(this)
                alertDialogBuilder.setTitle("Set Permissions or UN-Install App")
                alertDialogBuilder
                        .setMessage("Click SETTINGS to Manually Set\n\n"+"OR to UN-Install the Application")
                        .setCancelable(false)
                        .setPositiveButton("SETTINGS") { dialog, id ->
                            MANUALLY_SET = 2
                            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                            val uri = Uri.fromParts("package", packageName, null)
                            intent.data = uri
                            startActivityForResult(intent, 1000)
                        }

                val alertDialog = alertDialogBuilder.create()
                alertDialog.show()

            } else run {
                // User selected Deny Dialog to EXIT App ==> OR <== RETRY to have a second chance to Allow Permissions
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {

                    val alertDialogBuilder = AlertDialog.Builder(this)
                    alertDialogBuilder.setTitle("RETRY")
                    alertDialogBuilder
                            .setMessage("Click RETRY to Set Permissions\n\n"+"Permissions MUST be set to Enter Data")
                            .setCancelable(false)
                            .setPositiveButton("RETRY") { dialog, id ->
                                dialog.cancel()
                                val intent = Intent(this, CheckStorageActivity::class.java)
                                startActivity(intent)
                            }
                    val alertDialog = alertDialogBuilder.create()
                    alertDialog.show()
                }
            }
        }
    }
}

}

现在在DBHelper类中,您可以使用此格式进行所有CRUD和创建数据库

import com.androidstackoverflow.kotlinsqlite.Note.Companion.THE_PATH

class NoteDbManager(context: Context) {

private val dbName = THE_PATH +"JSANotes.db"
private val dbTable = "Notes"