【问题标题】:I don't understand why mkdir() returns false?我不明白为什么 mkdir() 返回 false?
【发布时间】:2020-09-23 11:36:40
【问题描述】:

我正在尝试将我的位图文件写入我在 androids 外部存储中创建的目录中的文件路径,但是当我运行我的代码时,我从bitmap.compress (bitmap.CompressFormat.JPEG, 0, outputStream) 收到了一个null pointer exception。通过调试,我发现我的bitmap 对象不为空,并且outputStream 对象为空,因此当我创建outputStream 对象并收到java.io.FileNotFoundException 时,null pointer exception 正在发生。从调试中我知道java.io.FileNotFoundException 正在发生,因为dir.mkdir () 返回false,所以没有为我的位图文件创建目录。

我不明白为什么 dir.mkdir () 返回 false,因为我实例化了 dir 并检查外部存储是否可写入 isExternalStorageWritable() 并在我的清单文件中添加 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 并创建了 askPermission()、@987654335 @& isStoragePermissionGranted () 请求用户对外部存储的许可。所以我不明白为什么dir.mkdir ()返回false并且没有创建目录。

这是发生异常的类:

public class BitmapFiles {

public String imagePath;
public String name;
private Bitmap bitmap;
private int resourceId;
private Context context;
private OutputStream outputStream;
private File file;

public BitmapFiles (Context context, int resourceId, String name) {
    this.resourceId = resourceId;
    this.name = name;
    this.context = context;

    convertToBitmap();
    saveBitmap();
    setImagePath();
}

public void convertToBitmap () {
    bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId);

}

public void saveBitmap () {
    File filePath = Environment.getExternalStorageDirectory ();
    File dir = new File (filePath.getAbsolutePath() + "/Items");

    if (isExternalStorageWritable()) {
        Log.d ("red", "external storage is writable");//I recieve this in the log cat
    }

    if (!dir.exists ()) {
        try {
            boolean direct = dir.mkdir();//Returns false

            if (dir.exists()) {
                Log.d ("blue", "directory exists now");//I don't recieve this in the log cat
            }

            if (!direct) {
                Log.d ("green", "the directory was not created");//I recieve this in the log cat
            }

        } catch (SecurityException e) {
            e.printStackTrace();
        }

    } else {
        Log.d ("yellow", "the directory already exists");
    }

    file = new File (dir, name + ".jpg");

    try {
        outputStream = new FileOutputStream(file);
    } catch (FileNotFoundException e) {
        e.printStackTrace ();
    }

    if (outputStream == null) {
        Log.d ("grey", "outputstream is null");//I recieve this in log cat
    }

    bitmap.compress (Bitmap.CompressFormat.JPEG, 0, outputStream);

}

public boolean isExternalStorageWritable () {
    String state = Environment.getExternalStorageState();

    if (Environment.MEDIA_MOUNTED.equals (state)) {
        return true;
    }

    return false;
}

}

这是我请求用户许可的类:

public class GroceryItem extends AppCompatActivity {

private static final int STORAGE_PERMISSION_CODE = 101;

protected void onCreate (Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_grocery_item);

    askForPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, STORAGE_PERMISSION_CODE);

}

public void askForPermission (String permission, int requestCode) {
    if (isStoragePermissionGranted()) {
        ActivityCompat.requestPermissions(this, new String [] {permission}, requestCode);
    } else {
        Toast.makeText (this, "Permission already granted", Toast.LENGTH_SHORT)
                .show();

    }
}

public void onRequestPermissionsResult (int requestCode, String [] permissions, int [] grantResults) {
    super.onRequestPermissionsResult (requestCode, permissions, grantResults);

    if (requestCode == STORAGE_PERMISSION_CODE) {
        if (grantResults.length > 0 && grantResults [0] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "Storage Permission Granted", Toast.LENGTH_SHORT)
                    .show();
        } else {
            Toast.makeText(this, "Storage Permission Denied", Toast.LENGTH_SHORT)
                    .show();
        }
    }


}

public boolean isStoragePermissionGranted () {

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        Toast.makeText(this, "permission granted", Toast.LENGTH_SHORT)
                .show();
        return true;
    }

    return false;
}

}

这是我收到的例外情况:

2020-09-23 10:18:20.829 32212-32263/com.myapp.groceryapp W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Items/faan.jpg: open failed: ENOENT (No such file or directory)
2020-09-23 10:18:20.829 32212-32263/com.myapp.groceryapp W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:496)
2020-09-23 10:18:20.829 32212-32263/com.myapp.groceryapp W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:235)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:186)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at com.myapp.groceryapp.BitmapFiles.saveBitmap(BitmapFiles.java:82)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at com.myapp.groceryapp.BitmapFiles.<init>(BitmapFiles.java:30)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at com.myapp.groceryapp.MyDatabaseHelper.createBitmapFiles(MyDatabaseHelper.java:42)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at com.myapp.groceryapp.MyDatabaseHelper.upgradeDatabase(MyDatabaseHelper.java:37)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at com.myapp.groceryapp.MyDatabaseHelper.onCreate(MyDatabaseHelper.java:33)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:412)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:341)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at com.myapp.groceryapp.GroceryItem.accessDataBase(GroceryItem.java:44)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at com.myapp.groceryapp.GroceryItem$StartDatabase.doInBackground(GroceryItem.java:101)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at com.myapp.groceryapp.GroceryItem$StartDatabase.doInBackground(GroceryItem.java:93)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at android.os.AsyncTask$3.call(AsyncTask.java:378)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at java.lang.Thread.run(Thread.java:919)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at libcore.io.Linux.open(Native Method)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7581)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:482)
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp W/System.err:  ... 18 more
2020-09-23 10:18:20.830 32212-32263/com.myapp.groceryapp D/outty: outputstream is null
2020-09-23 10:18:20.836 32212-32263/com.myapp.groceryapp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.myapp.groceryapp, PID: 32212
java.lang.RuntimeException: An error occurred while executing doInBackground()
    at android.os.AsyncTask$4.done(AsyncTask.java:399)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
    at java.util.concurrent.FutureTask.run(FutureTask.java:271)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:919)
 Caused by: java.lang.NullPointerException
    at android.graphics.Bitmap.compress(Bitmap.java:1407)
    at com.myapp.groceryapp.BitmapFiles.saveBitmap(BitmapFiles.java:95)
    at com.myapp.groceryapp.BitmapFiles.<init>(BitmapFiles.java:30)
    at com.myapp.groceryapp.MyDatabaseHelper.createBitmapFiles(MyDatabaseHelper.java:42)
    at com.myapp.groceryapp.MyDatabaseHelper.upgradeDatabase(MyDatabaseHelper.java:37)
    at com.myapp.groceryapp.MyDatabaseHelper.onCreate(MyDatabaseHelper.java:33)
    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:412)
    at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:341)
    at com.myapp.groceryapp.GroceryItem.accessDataBase(GroceryItem.java:44)
    at com.myapp.groceryapp.GroceryItem$StartDatabase.doInBackground(GroceryItem.java:101)
    at com.myapp.groceryapp.GroceryItem$StartDatabase.doInBackground(GroceryItem.java:93)
    at android.os.AsyncTask$3.call(AsyncTask.java:378)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
    at java.lang.Thread.run(Thread.java:919) 

【问题讨论】:

  • 那是因为您的设备运行的是 Android 10。

标签: java android nullpointerexception filenotfoundexception android-external-storage


【解决方案1】:

NullPointerExceptionFileNotFoundException 是由错误恢复代码错误引起的。简而言之,在根本不可能这样做的情况下,您的代码太努力地编写该位图。 (如果您尝试创建后目录不存在,则无法保存位图。持久性是徒劳的!)

一连串问题的根本原因是mkdir()(在某些情况下)是通过创建所需的目录来实现的。

我不明白为什么 mkdir() 返回 false。

发生这种情况可能有多种原因,包括以下一些:

  • 目录的父目录可能不存在
  • 父目录的所有权和权限可能有误
  • 可能不允许该应用在此文件系统中写入。
  • 设备可以是只读的
  • 设备可能已损坏或遇到硬件错误
  • 文件系统可能已满,无法创建目录。

问题在于无法找出这些可能原因中的哪一个是实际原因。 File.mkdir() 没有告诉你,也没有提供找出答案的方法。 java.io.File 是一个笨重的旧界面......你不应该再使用它了。 (它在 Java 7 中被取代!)

解决此问题的第一步是将您的应用程序更改为使用 NIO2 FilesPath API。特别是,您需要使用以下之一:

  • Files.createDirectory(Path dir, FileAttribute&lt;?&gt;... attrs) (javadoc)
  • Files.createDirectories(Path dir, FileAttribute&lt;?&gt;... attrs) (javadoc)

如果无法创建目录,这两个都会抛出异常。另外createDirectory如果目录已经存在会抛出异常。

在任何一种情况下,异常及其消息都应该告诉您操作失败的原因。这将帮助您弄清楚到底发生了什么……从而找出解决方法。

【讨论】:

    猜你喜欢
    • 2023-02-05
    • 1970-01-01
    • 2021-11-18
    • 1970-01-01
    • 2015-09-12
    • 2011-09-14
    • 2021-10-20
    • 2022-11-20
    • 1970-01-01
    相关资源
    最近更新 更多