英文:
I don't understand why mkdir() returns false?
问题
以下是您提供的代码的翻译部分:
public class BitmapFiles {
// ... 其他代码 ...
public void saveBitmap() {
File filePath = Environment.getExternalStorageDirectory();
File dir = new File(filePath.getAbsolutePath() + "/Items");
if (isExternalStorageWritable()) {
Log.d("red", "外部存储可写");//我在日志中收到这个消息
}
if (!dir.exists()) {
try {
boolean direct = dir.mkdir();//返回false
if (dir.exists()) {
Log.d("blue", "目录现在存在");//我在日志中没有收到这个消息
}
if (!direct) {
Log.d("green", "目录未被创建");//我在日志中收到这个消息
}
} catch (SecurityException e) {
e.printStackTrace();
}
} else {
Log.d("yellow", "目录已经存在");
}
file = new File(dir, name + ".jpg");
try {
outputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (outputStream == null) {
Log.d("grey", "输出流为空");//我在日志中收到这个消息
}
bitmap.compress(Bitmap.CompressFormat.JPEG, 0, outputStream);
}
// ... 其他代码 ...
}
public class GroceryItem extends AppCompatActivity {
// ... 其他代码 ...
public boolean isStoragePermissionGranted() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "权限已授予", Toast.LENGTH_SHORT)
.show();
return true;
}
return false;
}
// ... 其他代码 ...
}
请注意,由于您要求只返回翻译后的代码部分,因此我只提供了代码的翻译部分,而没有附加任何解释性文字。如果您需要进一步的解释或帮助,请随时提问。
英文:
I am trying to write my bitmap files to a filepath in a directory I create in androids external storage but when I run my code I recieve a null pointer exception
from bitmap.compress (bitmap.CompressFormat.JPEG, 0, outputStream)
. From debugging I have found that my bitmap
object is not null & that the outputStream
object is null so the null pointer exception
is occuring when I create the outputStream
object & I recieve a java.io.FileNotFoundException
. From debugging I know that the java.io.FileNotFoundException
is occuring because dir.mkdir ()
returns false so no directory is created for my bitmap files.
I don't understand why dir.mkdir ()
returns false because I instantiate dir
& check if the external storage is writable in isExternalStorageWritable()
and add <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
in my manifest file and have created askPermission()
, onRequestPermissionsResult()
& isStoragePermissionGranted ()
that ask the user for permission for the external storage. So I don't understand why dir.mkdir ()
returns false and the directory is not created.
This is the class where the exception occurs:
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;
}
}
This is the class where I ask the user for permission:
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;
}
}
This is the exception I recieve:
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) 
答案1
得分: 1
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
也会抛出异常。
在任何情况下,异常及其消息都应告诉您操作失败的原因。这将帮助您弄清楚实际发生了什么...从而找出如何修复它。
英文:
The NullPointerException
and FileNotFoundException
are caused by incorrect error recover code. Put simply, your code tries too hard to write that bitmap, in situations where it is simply not possible to do so. (If the directory doesn't exist after your attempt to create it, there is no way you could possibly save the bitmap. Persistence is futile!)
The root cause of the cascade of problems is that mkdir()
is (in some circumstances) by creating the the required directory.
> I don't understand why mkdir()
returns false.
This could be happening for a variety of reasons, including some of the following:
- The parent directory for the directory may not exist
- The parent directory's ownership and permissions may be wrong
- The app may not be permitted to write in this file system.
- The device could be read only
- The device could be corrupted or experiencing hardware errors
- The file system could be so full that a directory cannot be created.
The problem is that it is not possible to find out which of those possible causes is the actual cause. File.mkdir()
doesn't tell you, and doesn't provide a way to find out. java.io.File
is a clunky old interface ... and you shouldn't be using it anymore. (It was superseded in Java 7!)
The first step in solving this is to change your application to using the NIO2 Files
and Path
APIs. In particular, you need to use one of:
Files.createDirectory(Path dir, FileAttribute<?>... attrs)
(javadoc)Files.createDirectories(Path dir, FileAttribute<?>... attrs)
(javadoc)
These both will throw an exception if the directory could not be created. In addition, createDirectory
will throw an exception if the directory already exists.
In either case, the exception and its message should tell you why the operation failed. This will help you to figure out what is really going on ... and hence work out how to fix it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论