问题描述
我试图将位图文件写入在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)
解决方法
NullPointerException
和FileNotFoundException
是由错误的错误恢复代码引起的。简而言之,在根本无法编写位图的情况下,您的代码会太努力地编写该位图。 (如果尝试创建目录后目录不存在,则无法保存位图。持久性是徒劳的!)
一系列问题的根本原因是mkdir()
在某些情况下是通过创建所需的目录来实现的。
我不明白为什么
mkdir()
返回false。
此可能的发生有多种原因,其中包括以下原因:
- 该目录的父目录可能不存在
- 父目录的所有权和权限可能是错误的
- 可能不允许该应用在此文件系统中写入。
- 设备可能是只读的
- 设备可能已损坏或出现硬件错误
- 文件系统可能已满,无法创建目录。
问题在于,不可能找出那些可能的原因中的哪一个是实际原因。 File.mkdir()
不会告诉您,也没有提供查找信息的方法。 java.io.File
是一个笨拙的旧界面……您不应该再使用它。 (它已被Java 7取代!)
解决此问题的第一步是将您的应用程序更改为使用NIO2 Files
和Path
API。特别是,您需要使用以下之一:
-
Files.createDirectory(Path dir,FileAttribute<?>... attrs)
(javadoc) -
Files.createDirectories(Path dir,FileAttribute<?>... attrs)
(javadoc)
如果无法创建目录,这两个都将引发异常。另外,如果目录已经存在,createDirectory
将引发异常。
在任何一种情况下,异常及其消息应告诉您操作失败的原因。这将帮助您弄清楚到底发生了什么...从而找出解决方法。