17

The code works for most of the time, but some time it throws exception. Couldn't figure out what could cause it.

What is does is to create a file at

/storage/emulated/0/Download/theFileName.jpg

and write data to it (from sourceFile which does exist), but got "file not exist" exception for the newly created file.

(it does have uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE", and uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" in manifest).

File sourceFile = new File(theSourceFileFullPath);
if (sourceFile.exists()) {
    File downloadDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
    String downloadPath = downloadDirectory.getPath();
    String newFilePath = (downloadPath + "/" + fileName);
    File newFile = new File(newFilePath);
    try {
        FileInputStream in = new FileInputStream(sourceFile);

        // ava.io.FileNotFoundException: 
        //     /storage/emulated/0/Download/theFileName.jpg: open failed: ENOENT (No such file or directory) 
        // exception at this line       
        FileOutputStream out = new FileOutputStream(newFile);
        //......
     } catch (Exception e) {}
}
Mike
  • 4,356
  • 4
  • 28
  • 45
lannyf
  • 6,775
  • 4
  • 49
  • 92
  • 1
    Maybe did not finished its creation and you try to access it. Everytime the app opens it tries to create a file and read from it? – Ispas Claudiu Nov 30 '15 at 14:35
  • Try replace: File newFile = new File(downlaodDirectory, fileName); – mdtuyen Nov 30 '15 at 14:43
  • Lispas, the app has been running. mdtuyen, File newFile = new File(downlaodDirectory, fileName); does not help, and if having both downlaodDirectory and fileName, it is same as new File(downlaodDirectory.getPath()+"/"+ fileName); – lannyf Nov 30 '15 at 15:16
  • A FileInputStream does not create a file. So why is that statement there? What are you doing with 'in' ? It's unclear from your post if the exeption is from the input or output stream. – greenapps Nov 30 '15 at 17:03
  • greenapps, the line of out = new FileOutputStrem(newFile) is to create a FileOutputStream and to use it write data to it later. BTW it does create the file if it doesnot exist. /** * Constructs a new {@code FileOutputStream} that writes to {@code file}. The file will be * truncated if it exists, and created if it doesn't exist. * * @throws FileNotFoundException if file cannot be opened for writing. */ public FileOutputStream(File file) throws FileNotFoundException { this(file, false); } – lannyf Nov 30 '15 at 21:50
  • 1
    Is this error coming on the same device? Or some devices error, and some devices do not? – Knossos Dec 22 '15 at 18:24
  • @lannyf did you get to the bottom of this? I'm seeing something similar. It's been driving me crazy for a while :) – Chris Nevill Mar 22 '19 at 21:52

6 Answers6

9

I can think of the following possible reasons for this behavior:

  1. The new file could not be created simply because there is no free space on SD card. The next time you encounter this issue, try to see if you have at least some available space via file manager or Settings -> Storage. I doubt you can do something about it if this is what happens on your user's device.
  2. The SD card is not available due to some OS glitch or it's physically not attached, thus the file could not be created. Once again - there is nothing you can do about it, other than showing some Toast with error message.
  3. How do you generate the fileName part of your file's path? Sometimes the files can not be created because the filename contains unsupported (by this particular device) characters. E.g. I have HTC Desire X with Android 4.1.2 which can not create files with the code similar to yours if the filename contains colon. Try another way to generate the filename and see if it makes a difference.
  4. Did you make sure that the Downloads directory exists before creating the file inside it? Write something like the following:

    if (!downloadDirectory.exists()) {
        downloadDirectory.mkdirs();
    }
    
  5. The WRITE_EXTERNAL_STORAGE permission is considered dangerous on the Android 6, thus it can be revoked by the user at any time. Make sure user didn't revoke this permission before writing to the file.
  6. Always close the I/O stream when you finished working with it. Add the finally clause to your try-catch block and close both in and out streams in it:

    finally {
        if (in != null) {
            try {
                in.close();
            } catch (Exception e) { }
        }
    
        if (out != null) {
            try {
                out.close();
            } catch (Exception e) { }
        }
    }
    
  7. The last one - and finally I'm out of options. :) I suppose this issue could also arise if you write to the same file from multiple threads. If that's the case, try to synchronize access to your file-writing code.
Community
  • 1
  • 1
aga
  • 25,984
  • 9
  • 77
  • 115
  • thanks aga! the crashes are reported from crashlytics, and the instances show the device seems do not short of memory. it could be a glitch, but there are hundreds reports. file name are fine simple as one word. It does not like the system download dir is not there, and if it were then the same user would have multiple instance reported but it is not the case. User may revoke the write_external_storage, but the instance distribution cross from all different devices. Thank you again for listing the possibles. – lannyf Dec 18 '15 at 21:57
  • @lannyf I forgot about one more opportunity: you did not close the `in` and `out` streams when you've finished working with them. Try this one also. – aga Dec 18 '15 at 22:10
  • Thank you aga. it does have close on the streams but not showing in the code snippet. – lannyf Dec 19 '15 at 15:08
  • @lannyf check also that you don't write to the same file from different threads simultaneously. That's the last option I can think of. :) – aga Dec 19 '15 at 15:24
  • cannt think of if there is multiple thread trying to write the same file here. When it gets here, the output file name is generated to be unique and checked the possible ongoing one to get the unique new name for here. Thanks for point this out! – lannyf Dec 19 '15 at 20:24
2

According to Java docs - Class FileNotFoundException:

public class FileNotFoundException extends IOException

Signals that an attempt to open the file denoted by a specified pathname has failed.

This exception will be thrown by the FileInputStream, FileOutputStream, and RandomAccessFile constructors when a file with the specified pathname does not exist. It will also be thrown by these constructors if the file does exist but for some reason is inaccessible, for example when an attempt is made to open a read-only file for writing.

To resume, there are three cases where a FileNotFoundException may be thrown.

  1. The named file does not exist.
  2. The named file is actually a directory.
  3. The named file cannot be opened for reading for some reason.

got "file not exist" exception for the newly created file.

In your code I don't see two things

  1. Removing file after successful write. I'm not kidding at all. If I had a class like this and that error, I would make a kind of test, which would finish with deleting downlaodDirectory after copying content from source file. In that case it would pass the method or you would get another, but more specific error - like in my words: unable to delete file. Under use it
  2. Closing file after writing data. I don't see also a method to close files. In your code, does seem to be that your File is still open, so you run again an app and you get this unpredicted by you error.

To fix the issue just close both files after processing data using file.close() method.

Hope it help

piotrek1543
  • 18,034
  • 7
  • 69
  • 86
  • thanks piotrek. the stream do get closed, it's just not show in the code snippet. The #1, the name file does not exist and need to created here. #2, it is a file name not a directory. #3 that's what trying to find why and a work around for it. – lannyf Dec 19 '15 at 20:19
1
  1. The issue might happen due to the way you create file:

    String downloadPath = downloadDirectory.getPath();
    String newFilePath = (downloadPath + "/" + fileName);
    File newFile = new File(newFilePath);
    

    The dangerous code is here:

    String newFilePath = (downloadPath + "/" + fileName);
    

    Instead, try to use the following approach:

    File newFile = new File(downloadDirectory, fileName);
    
  2. SD card availability - check the following documentation http://developer.android.com/training/basics/data-storage/files.html#WriteExternalStorage. It might be that media is not mounted (for instance on some old devices it happens when user connects device to computer via usb) So, try to check if media mounted:

    /* Checks if external storage is available for read and write */
    public boolean isExternalStorageWritable() {
         String state = Environment.getExternalStorageState();
         if (Environment.MEDIA_MOUNTED.equals(state)) {
             return true;
         }
         return false;
     }
    

    and notify user if not.

GregoryK
  • 2,741
  • 1
  • 24
  • 22
  • thanks Gregory! if newFilePath = (downloadPath + "/" + fileName); were the problem then it would have much more exception. Besides both version eventually calls into fixSlashes(). aga already mentioned external storage availability, don't think that's the issue with device's 'download' folder, if it were the problem the same user/deivce would have much more exceptions, which is not the case. – lannyf Dec 22 '15 at 23:30
  • @lannyf MEDIA_MOUNTED problem is a bit tricky. It happens in rare cases only. One possible scenario, so you can test it, when user's device has SD card and user connects the device (with old Android) to computer via USB and selects USB connection in order to transfer files. (I had a similar problem in my app which never happened for me as I hadn't SD card.) "isExternalStorageWritable" is recommended by develper.android.com and it really easy to implement, so I would look into it. – GregoryK Dec 23 '15 at 09:41
  • Thanks Gregory! it gets a lot reported instances (for the same exception issue) happening on device do not have SD card. – lannyf Dec 25 '15 at 22:12
0

I hope your code to write data in file is perfect I am just Concentrate in your problem.I think there is two possibility to get File not found Exception.

  1. Some time File Name is not Support Some Special Character While you provide this kind of character to giving file name at that time file is not properly Generated that's why this error was occur So please Make sure your file name is Proper.
  2. second is Your file extension.here your not specified which kind of file you have.

here I have Some Code Snippet I hope this will helping you to Solve problem.

Solution

   File file=new File(Environment.getExternalStorageDirectory()+"/"+ConstansClass.FOLDERNAME);
    if(!file.exists())
    {
        file.mkdir();
    }


    String file=filename.replaceAll("[^a-zA-Z0-9.-]", " ");
    yourDir = new File(file, file+".mp3");
    if(yourDir.exists())
    {
        return yourDir;
    }

Edit

I am Sorry lannf I don't know what exactly happen in your code but i have one code snippet which is just download mp3 file from soundcloude and Store in my local storage.i think it's exactly same as your requirement.so i have post my code below.

 @Override
protected File doInBackground(Void... params) {


    //File sdCardRoot = Environment.getExternalStorageDirectory()+"/Music";

    File file=new File(Environment.getExternalStorageDirectory()+"/"+ConstansClass.FOLDERNAME);
    if(!file.exists())
    {
        file.mkdir();
    }


    String filename=soundCloudeResponse.getTitle();//.replaceAll("[^a-zA-Z0-9.-]", " ");
    yourDir = new File(file, filename+".mp3");
    if(yourDir.exists())
    {
        return yourDir;
    }
    String url=soundCloudeResponse.getStream_url()+"?"+ConstansClass.SOUNDCLOUDE_CLIENT_ID;

    URL u = null;
    try {
        DebugLog.e("Request Url"+ url);
        u = new URL(url);
        URLConnection conn = u.openConnection();
        int contentLength = conn.getContentLength();

        DataInputStream stream = new DataInputStream(u.openStream());

        byte[] buffer = new byte[contentLength];
        stream.readFully(buffer);
        stream.close();

        DataOutputStream fos = new DataOutputStream(new FileOutputStream(yourDir));
        fos.write(buffer);
        fos.flush();
        fos.close();
        DebugLog.d("Download Complete in On Background");


    } catch (MalformedURLException e) {
        sucess=false;
        e.printStackTrace();

    } catch (IOException e) {
        sucess=false;
        e.printStackTrace();

    }
    catch (Exception e)
    {
        sucess=false;
        e.printStackTrace();
        DebugLog.e("Error ::"+e.getMessage());
    }


    return yourDir;
}

I think your are intelligent developer so you can modify this code according to your requirement.

Best Of Luck

Chirag Solanki
  • 928
  • 2
  • 11
  • 22
  • Thanks Chirag! '/storage/emulated/0/Download/theFileName.jpg' is file path of the one of the reported exception. The file name were fine with proper ext. – lannyf Dec 25 '15 at 21:55
0

you didn't posted full exception stack traces but I found exact problem solved by SO.

java.io.FileNotFoundException: /storage/emulated/0/bimagechooser/1429031333305.jpg: open failed: ENOENT (No such file or directory)

Use this library image-chooser-library. & need to re-factor code.

The Guy coomar2841. will surely help you. as he spend hours solving the problem. so save your time.

Took the sources of com.kbeanie.imagechooser and dropped them into your APP, removed the gradle declaration for the library and the APP should work.

please view the GitHub Issue

I hope it'll work for you. :)

Kaleem Ullah
  • 5,548
  • 2
  • 37
  • 43
0

There could be one more possibility:

If one part of your code is writing the file and another one is reading, then it is good to consider that the reader is reading before the writer finishes writing the file.

You can cross check this case by putting your code on debug mode. If it works fine there and gives you FileNotFoundException, then surely this could be the potential reason of this exception.

Now, how to resolve:

You can use retry mechanism something similar to below code block

if(!file..exists()){
Thread.sleep(200);}

in your code and change the sleep value according to your needs.

Hope that helps.!!

Ajay Sodhi
  • 91
  • 1
  • 2