Почему когда-то он выбрасывает FileNotFoundException

Код работает большую часть времени, но некоторое время он выдает исключение. Не удалось выяснить, что может вызвать это.

Что происходит, это создать файл в

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

и записывать в него данные (из исходных файлов, которые существуют), но получили исключение "файл не существует" для вновь созданного файла.

(он имеет uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE", and uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE "в манифесте).

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) {}
}

Ответы

Ответ 1

Я могу думать о следующих возможных причинах такого поведения:

  • Новый файл не может быть создан просто потому, что на SD-карте нет свободного места. В следующий раз, когда вы столкнетесь с этой проблемой, попробуйте посмотреть, есть ли у вас хотя бы какое-то доступное пространство через диспетчер файлов или Настройки → Хранение. Я сомневаюсь, что вы можете что-то сделать, если это произойдет на вашем пользовательском устройстве.
  • SD-карта недоступна из-за сбоя операционной системы или физически не подключена, поэтому файл не может быть создан. Еще раз - вы ничего не можете с этим поделать, кроме как показать Toast сообщение об ошибке.
  • Как вы создаете часть fileName вашего пути к файлу? Иногда файлы не могут быть созданы, потому что имя файла содержит неподдерживаемые (этим конкретным устройством) символы. Например. У меня HTC Desire X с Android 4.1.2, который не может создавать файлы с кодом, похожим на ваш, если имя файла содержит двоеточие. Попробуйте другой способ сгенерировать имя файла и посмотреть, не изменилось ли оно.
  • Вы убедились, что каталог Downloads существует до создания файла внутри него? Напишите что-то вроде следующего:

    if (!downloadDirectory.exists()) {
        downloadDirectory.mkdirs();
    }
    
  • Разрешение WRITE_EXTERNAL_STORAGE считается опасным на Android 6, поэтому он может быть отозван пользователем в любое время. Удостоверьтесь, что пользователь не отозвал это разрешение перед записью в файл.
  • Всегда закрывайте поток ввода-вывода, когда вы закончите работать с ним. Добавьте предложение finally в блок try-catch и закройте в нем теги in и out:

    finally {
        if (in != null) {
            try {
                in.close();
            } catch (Exception e) { }
        }
    
        if (out != null) {
            try {
                out.close();
            } catch (Exception e) { }
        }
    }
    
  • Последний - и, наконец, у меня нет вариантов.:) Я полагаю, что эта проблема может возникнуть, если вы пишете в тот же файл из нескольких потоков. В этом случае попробуйте синхронизировать доступ к вашему файловому коде.

Ответ 2

В соответствии с Java docs - Класс FileNotFoundException:

public class FileNotFoundException extends IOException

Сигналы о том, что попытка открыть файл, обозначенный указанным именем пути, не удалось.

Это исключение будет выбрано FileInputStream, FileOutputStream и RandomAccessFile, когда файл с указанный pathname не существует. Он также будет брошен этими конструкторы, если файл существует, но по какой-либо причине недоступно, например, когда делается попытка открыть только для чтения файл для записи.

Чтобы возобновить работу, есть три случая, когда может быть выбрано значение FileNotFoundException.

  • Именованный файл не существует.
  • Именованный файл на самом деле является каталогом.
  • Именованный файл не может быть открыт для чтения по какой-либо причине.

получилось исключение "файл не существует" для вновь созданного файла.

В вашем коде я не вижу двух вещей

  • Удаление файла после успешной записи. Я вообще не шучу. Если бы у меня был класс, похожий на эту и ту ошибку, я бы сделал своего рода тест, который завершился бы с удалением downlaodDirectory после копирования содержимого из исходного файла. В этом случае он передаст этот метод или вы получите другую, но более конкретную ошибку - например, по-моему: невозможно удалить файл. При использовании
  • Закрытие файла после записи данных. Я также не вижу способ закрыть файлы. В вашем коде кажется, что ваш файл по-прежнему открыт, поэтому вы запускаете снова приложение, и вы получаете эту непредсказуемую ошибку.

Чтобы исправить проблему, просто закройте оба файла после обработки данных с помощью метода file.close().

Надеюсь, что это поможет

Ответ 3

  • Проблема может возникнуть из-за способа создания файла:

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

    Здесь находится опасный код:

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

    Вместо этого попробуйте использовать следующий подход:

    File newFile = new File(downloadDirectory, fileName);
    
  • Доступность SD-карты - проверьте следующую документацию http://developer.android.com/training/basics/data-storage/files.html#WriteExternalStorage. Возможно, носители не установлены (например, на некоторых старых устройствах это происходит, когда пользователь подключает устройство к компьютеру через usb) Итак, попробуйте проверьте, установлен ли носитель:

    /* 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;
     }
    

    и уведомить пользователя, если нет.

Ответ 4

Я надеюсь, что ваш код для записи данных в файл идеален. Я просто сконцентрирован в вашей проблеме. Я думаю, что есть две возможности получить файл не найден Исключением.

  • Некоторое время Имя файла не поддерживается. Некоторый особый символ. Пока вы предоставляете такого рода символы, чтобы указать имя файла в тот момент, файл не был правильно Создан, почему произошла эта ошибка. Поэтому, пожалуйста, убедитесь, что ваше имя файла правильно.
  • second - это расширение вашего файла. Если вы не указали, какой файл у вас есть.

здесь У меня есть фрагмент кода. Надеюсь, это поможет решить проблему.

Решение

   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

Я извиняюсь lannf Я не знаю, что именно происходит в вашем коде, но у меня есть один фрагмент кода, который просто загружает mp3 файл из soundcloude и Store в моем локальном хранилище. Я думаю, что он точно такой же, как и ваш require.so я разместите мой код ниже.

 @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;
}

Я думаю, что вы умный разработчик, поэтому вы можете изменить этот код в соответствии с вашими требованиями.

Лучшее от удачи

Ответ 5

вы не опубликовали все стеки стека исключений, но я нашел точную проблему, разрешенную SO.

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

Используйте эту библиотеку image-chooser-library. и необходимо перефакторировать код.

The Guy coomar2841. безусловно, поможет вам. поскольку он часами решает проблему. поэтому экономьте свое время.

Захватили источники com.kbeanie.imagechooser и сбросили их в APP, удалили объявление gradle для библиотеки, и APP должен работать.

просмотрите проблему GitHub

Надеюсь, это сработает для вас.:)

Ответ 6

Там может быть еще одна возможность:

Если одна часть вашего кода пишет файл, а другая читает, тогда будет полезно учесть, что читатель читает до того, как автор заканчивает писать файл.

Вы можете перепроверить этот случай, переведя код в режим отладки. Если там все работает нормально и выдает исключение FileNotFoundException, то, несомненно, это может быть потенциальной причиной этого исключения.

Теперь, как решить:

Вы можете использовать механизм повтора, похожий на приведенный ниже блок кода.

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

в вашем коде и измените значение сна в соответствии с вашими потребностями.

Надеюсь, это поможет.!!