我不明白为什么mkdir返回false?

问题描述

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

我不明白为什么dir.mkdir ()返回false,因为我实例化了dir并检查外部存储是否可在isExternalStorageWritable()中写入并在清单文件添加<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />并已创建askPermission()onRequestPermissionsResult()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,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) 

解决方法

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

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

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

可能的发生有多种原因,其中包括以下原因:

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

问题在于,不可能找出那些可能的原因中的哪一个是实际原因。 File.mkdir()不会告诉您,也没有提供查找信息的方法。 java.io.File是一个笨拙的旧界面……您不应该再使用它。 (它已被Java 7取代!)

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

  • Files.createDirectory(Path dir,FileAttribute<?>... attrs)javadoc
  • Files.createDirectories(Path dir,FileAttribute<?>... attrs)javadoc

如果无法创建目录,这两个都将引发异常。另外,如果目录已经存在,createDirectory将引发异常。

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