Android SDK 29: Размер недавно сохранённого файла 0 байт после выключения устройства

Вопрос или проблема

У моего устройства версия Android SDK 29. Нет внутренней батареи, питание осуществляется от 12В. Для включения/выключения мы просто используем проводной переключатель, поэтому отключение питания происходит путём жёсткой обрезки электричества во время работы Android.

У нас есть большая проблема, когда мы сохраняем файл во внутреннее хранилище (в папку приложения). Например, мы сохранили файл, и неважно, будет ли отключение питания выполнено через несколько секунд или даже через полчаса, недавно сохранённый файл имеет размер 0 байт.

В настоящее время мы справляемся с этой проблемой, сохраняя фиктивный файл в качестве последнего, потому что мы подумали, что даже если он будет уничтожен, ничего плохого не произойдёт, и точный файл будет в порядке. Дополнительно мы добавили процесс чтения файла в конце функции сохранения. Частота появления проблемы сократилась, но иногда точный файл тоже оказывается пустым после жёсткого отключения питания.

Вот фрагмент функции сохранения:

                    File task_dummy = new File(file_folder, "dummy_task.dmt");
                    String file = generate_task_JSON_file(task);
                   
                    if (file != null){
                        
                        if(task_data.exists())
                            task_data.delete();
                        task_data.createNewFile();
                        if(task_dummy.exists())
                            task_dummy.delete();
                        task_dummy.createNewFile();

                        FileOutputStream fos = new FileOutputStream(task_data.getPath());
                        ObjectOutputStream oos = new ObjectOutputStream(fos);
                        oos.writeObject(file);
                        oos.close();
                        fos.close();
                        oos.flush();
                        fos.flush();

                        fos = new FileOutputStream(task_dummy.getPath());
                        oos = new ObjectOutputStream(fos);
                        oos.writeObject(file);
                        oos.close();
                        fos.close();
                        oos.flush();
                        fos.flush();

                        try{
                            FileInputStream fin = new FileInputStream(task_data);
                            ObjectInputStream ois = new ObjectInputStream(fin);
                            String file_string =   ois.readObject().toString();
                            ois.close();
                            fin.close();
                        } catch (ClassNotFoundException e) {

                        }

                    }

Какой хороший и безопасный метод для правильного сохранения? Большое спасибо. Лукаш

Ответ или решение

Ответ:

Здравствуйте, Лукаше!

Проблема, с которой вы столкнулись, связана с тем, что при жестком отключении питания данные, которые вы сохраняете на внутреннем хранилище Android, могут быть не сохранены или повреждены. Это происходит из-за того, что процесс записи данных "периодически кэшируется" в памяти, и только после определенного времени они записываются на диск. При отключении питания до завершения этой операции данные могут стать недоступными или иметь нулевой размер.

Вот несколько методов, которые могут помочь вам безопасно сохранять файлы и уменьшить риск повреждения данных:

  1. Используйте FileChannel с MappedByteBuffer: Это может помочь вам синхронизировать данные быстрее при записи. Метод force() гарантирует, что изменения будут записаны на диск.

    FileOutputStream fos = new FileOutputStream(task_data);
    FileChannel channel = fos.getChannel();
    MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, file.length());
    buffer.put(file.getBytes());
    channel.force(true); // Принудительная запись в файл
    fos.close();
  2. Принудительное завершение потока: Ваша текущая реализация закрывает потоки, но вызов flush() не требуется сразу после close(), и инициализация ObjectOutputStream также может повлиять на структуру записи. Вы можете вызвать flush() только после записи:

    oos.writeObject(file);
    oos.flush(); // Это удобно в случае объектов, но важно
    oos.close();
  3. Заключение в транзакцию: Перед завершением записи всегда вы можете использовать отдельные файлы и в конце объединять данные. Вы можете сохранить временный файл и переименовать его только после успешного завершения всех операций.

  4. Обработка ошибок и резервное копирование: Убедитесь, что правильно обрабатываете исключения. Если во время записи возникает ошибка, ваше приложение должно это учитывать и не оставлять частично записанные или пустые файлы:

    try {
        // Ваша логика записи
    } catch (IOException e) {
        // Запишите ошибку в лог
    }
  5. Добавление задержек: Поскольку вы используете жесткое отключение, попробуйте добавить задержку (например, Thread.sleep(200)) между сохранением файла и любыми другими действиями. Это даст процессу записи немного больше времени, чтобы завершиться.

  6. Журналирование и синхронизация: Включите более подробное логирование, чтобы отслеживать, когда файлы записываются и закрываются. Это может помочь вам в будущем при отладке и установке причин появления пустых файлов.

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

Надеюсь, эти советы помогут вам решить проблему с сохранением данных! Если у вас будут дополнительные вопросы, пожалуйста, не стесняйтесь обратиться.

С уважением,
[Ваше Имя]

Оцените материал
Добавить комментарий

Капча загружается...