Сохранение файлов

Android использует файловую систему, похожую на систему на основе дисковых файловых систем на других платформах. Этот урок описывает, как работать с файловой системой Android, чтобы читать и записывать файлы, используя File API.

File объект подходит для чтения или записи больших объемов данных с начала до конца, не пропуская ничего вокруг. Например, это хорошо подходит для файлов изображений или для обмена чем-нибудь по сети.

Этот урок показывает, как выполнять основные задачи связанные с файлами в вашем приложении. Урок предполагает, что вы знакомы с основами файловой системы Linux и стандартным API файлового ввода/вывода в java.io.

[wpanchor id=”1″]

 

Выберите внутреннее или внешнее хранилище


Все Android устройства имеют две области хранения файлов: “внутреннее” и “внешнее” хранилище. Эти названия пришли из первых дней Android, когда предлагалось, что большинство устройств предоставляют встроенную постоянную неизменную память (внутреннее хранилище), а также съемный носитель, такое как микро SD карта(внешнее хранилище). Некоторые устройства делят места постоянного хранения на “внутренние” и “внешние” разделы, т.е. даже без съемного носителя, всегда есть два хранилища, и поведение API для внешнего хранилища такое же, не зависимо от того, является ли оно съемным или нет. Следующие списки обобщают факты о каждом хранилище.

Внутреннее хранилище:

  • Всегда доступно.
  • Файлы, сохраненные здесь, по умолчанию, доступны лишь вашему приложению.
  • Когда пользователь удаляет ваше приложение, система удаляет все файлы вашего приложения из внутренней памяти.

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

Внешнее хранилище:

  • Не всегда доступно, так как пользователь может смонтировать внешний накопитель в качестве USB хранилища, и в некоторых случаях вынуть его из устройства.
  • Чтение разрешено всем, поэтому файлы, сохраненные здесь, можно прочитать без вашего контроля.
  • Когда пользователь удаляет ваше приложение, система удаляет файлы вашего приложения отсюда, только если вы сохраните их в каталоге изgetExternalFilesDir().

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

Полезный совет: Хотя приложения устанавливаются во внутреннее хранилище по умолчанию, можно указать android:installLocation атрибут в манифесте, чтобы ваше приложение могло быть установлено на внешний накопитель. Пользователи ценят эту опцию, когда размер APK очень большой, и у них есть внешнее пространство для хранения, превышающее внутреннюю память. Для получения дополнительной информации, см. Путь установки приложения.

[wpanchor id=”2″]

Получите разрешения для внешних накопителей


Для записи на внешний накопитель, вы должны запросить WRITE_EXTERNAL_STORAGE разрешение в вашем файле манифеста:

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

 

Внимание: В настоящее время, все приложения имеют возможность читать с внешних накопителей без специального разрешения. Тем не менее, это изменится в будущем релизе. Если ваше приложение должно прочитать внешний накопитель (но не писать в него), то вам нужно будет объявить READ_EXTERNAL_STORAGE разрешение. Чтобы убедиться, что ваше приложение продолжало работать, как и ожидалось, вы должны объявить это разрешение сейчас, прежде чем изменения вступят в силу.

<manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    ...
</manifest>

 

Однако, если ваше приложение использует WRITE_EXTERNAL_STORAGE разрешение, то также неявно имеет разрешение на чтение внешнего хранилища.

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

[wpanchor id=”3″]

 

Сохраните файл во внутреннем хранилище


При сохранении файла во внутреннее хранилище, вы можете запросить соответствующий каталог, в виде объекта File , вызвав один из двух методов:

getFilesDir()
Возвращает File представляющий собой внутренний каталог вашего приложения.
getCacheDir()
Возвращает File представляющий собой внутренний каталог для временных файлов кэша вашего приложения. Будьте уверены, удалять файлы по одному больше не нужено, и реализуйте разумный предел размера объема памяти, который вы будете использовать в какой-либо момент времени, например, 1 Мб. Если в системе возникает нехватка места, она может удалить ваши файлы кэша без предупреждения.

Чтобы создать новый файл в одном из этих каталогов, вы можете использовать File()конструктор, передав File предоставленный одним из выше указанных методов, который указывает на ваш внутренний каталог. Например:

File file = new File(context.getFilesDir(), filename);

 

В качестве альтернативы, вы можете вызвать openFileOutput() для получения FileOutputStream , который пишет в файл в вашем внутреннем каталоге. Например, вот как записать текст в файл:

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  outputStream.write(string.getBytes());
  outputStream.close();
} catch (Exception e) {
  e.printStackTrace();
}

 

Или, если вам нужно кэшировать некоторые файлы, то следует использовать createTempFile(). Например, следующий метод извлекает имя файла из URL и создает файл с таким же именем во внутренней каталоге кэша вашего приложения:

public File getTempFile(Context context, String url) {
    File file;
    try {
        String fileName = Uri.parse(url).getLastPathSegment();
        file = File.createTempFile(fileName, null, context.getCacheDir());
    catch (IOException e) {
        // Error while creating file
    }
    return file;
}

 

Примечание: Каталог внутреннего хранилища вашего приложения использует имя пакета вашего приложения, располагаясь в специальном месте файловой системы Android. Технически, другое приложение может читать ваши внутренние файлы, если вы установите для файла режим доступа на чтение. Тем не менее, другие приложения также должны знать ваше имя пакета и имена файлов. Другие приложения не могут просматривать ваши внутренние каталоги, и не имеют доступа для чтения или записи, если явно не установить разрешения для чтения или записи. Так что, пока вы используете MODE_PRIVATE для ваших файлов во внутренней памяти, они не являются доступными для других приложений.

[wpanchor id=”4″]

Сохраните файл на внешнем накопителе


Поскольку внешнее хранилище может быть недоступно — например, когда пользователь монтируется хранилище к ПК, или вынул SD карту, которая обеспечивает внешнее хранилище — вы всегда должны убедиться, что раздел доступен перед доступом к нему. Вы можете запросить состояния внешнего хранилища, вызвав getExternalStorageState(). Если возвращенное состояние равно 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;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

 

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

Общедоступные файлы
Файлы, которые должны быть в свободном доступе для других приложений и для пользователя. Когда пользователь удаляет ваше приложение, эти файлы должны оставаться доступными для пользователя.Например, фотографии, сделанные с помощью приложения, или другие загруженные файлы.
Личные файлы
Файлы, которые по праву принадлежат вашему приложению, и их следует удалить, когда пользователь удаляет ваше приложение. Хотя эти файлы являются технически доступными пользователю, и другим приложениям, т.к. они находятся на внешнем накопителе, это файлы, которые реально не представляют собой ценности для пользователя вне вашего приложения. Когда пользователь удаляет ваше приложение, система удаляет все файлы с внешнего приватного каталога вашего приложения.Например, дополнительные ресурсы загруженные вашим приложения или временные медиа-файлы.

Если вы хотите сохранить общедоступные файлы на внешнем устройстве хранения, используйтеgetExternalStoragePublicDirectory() метод для получения File представляющего соответствующий каталог на внешнем накопителе. Метод принимает аргумент, указывающий тип файла, который вы хотите сохранить, чтобы они могли быть логически организованы с другими общедоступными файлами, такими как DIRECTORY_MUSIC или DIRECTORY_PICTURES. Например:

public File getAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory. 
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

 

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

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

public File getAlbumStorageDir(Context context, String albumName) {
    // Get the directory for the app's private pictures directory. 
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

 

Если ни одно из предопределенных имен подкаталогов не удовлетворяет вашим файлам, вы можете вместо этого вызвать getExternalFilesDir() и передать null. При это возвращается корневой каталог для приватных каталогов вашего приложения на внешнем накопителе.

Помните, что getExternalFilesDir() создает каталог внутри каталога, который удаляется, когда пользователь удаляет ваше приложение. Если сохраненные файлы должны оставаться доступными после того как пользователь удаляет ваше приложение — например, когда ваше приложение представляет собой камеру, и пользователь захочет сохранить фотографии — то следует использовать getExternalStoragePublicDirectory().

Независимо от того, используете ли вы getExternalStoragePublicDirectory() для файлов, которые являются общими или getExternalFilesDir() для файлов, которые являются приватными для вашего приложения, важно, что вы используете имена каталогов, предоставляемые константами API, такими как DIRECTORY_PICTURES. Эти имена каталогов гарантируют, что файлы будут интерпретироваться системой должным образом. Например, файлы, сохраненные вDIRECTORY_RINGTONES классифицируются по системе медиа сканера как мелодии звонка вместо музыки.

[wpanchor id=”5″]

 

Запросите свободное пространство


Если вы знаете заранее, сколько данных вы будете сохранять, вы можете выяснить, есть ли в наличие достаточно места, не вызывая IOException с помощью вызова getFreeSpace() илиgetTotalSpace(). Эти методы предоставляют информацию о текущем доступном пространстве и общем пространстве раздела, соответственно. Эта информация также полезна, чтобы избежать заполнения раздела накопителя выше определенного порога.

Тем не менее, система не гарантирует, что вы можете записать столько байт, сколько обозначеноgetFreeSpace(). Если возвращаемое число на несколько МБ больше, чем размер данных, которые вы хотите сохранить, или если файловая система заполнена меньше чем на 90%, то, наверное, можно продолжить. В противном случае, вероятно, не стоит записывать в хранилище.

Примечание: Вы не обязаны проверять количество свободного места, прежде чем вы сохраняете файл. Вместо этого, вы можете попробовать записать файл, и поймать IOExceptionесли оно произойдет. Возможно, вам придется сделать так, если вы не знаете точно, сколько места нужно. Например, если вы измените кодировку файла перед сохранением путем преобразования PNG изображения в JPEG, вы не будете знать размер файла заранее.

[wpanchor id=”6″]

Удаление файла


Вы всегда должны удалить файлы, которые вам больше не нужны. Самый простой способ удалить файл это вызвать delete().

myFile.delete();

 

Если файл сохранен во внутреннем хранилище, вы также можете попросить Context найти и удалить файл, вызвав deleteFile():

myContext.deleteFile(fileName);

 

Примечание: Когда пользователь удаляет ваше приложение, Android система удаляет следующее:

  • Все файлы, сохраненные во внутреннем хранилище
  • Все файлы, сохраненные на внешнем накопителе, используя getExternalFilesDir().

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

Коментарі: 1
  1. Азамат

    Добрый день!

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

    Мне нужно реализовать программу где приложение должно создать файл на основе внешнего файла.
    Например, взять данные находящиеся в файле “android/sdcard/file.txt” и по данным полученным из этого файла заполнить другой, создаваемый самим приложением файл “android/sdcard/myFile.txt”.

    Можете подсказать каким образом можно прочесть внешний файл и как начать поиск переменных с нужной мне строки? Например, мне нужно по введенному пользователем параметру найти из file.txt данные, в скобках пример файла
    (“Это file.txt
    Данные для работы:
    13:22:45:54
    454:12:78:1
    95:23:33:85”), в данном случае, если пользователь введет число 13, то в myFile.txt должно записаться строка 13:22:45:54. Проблемы в моем случае, поиск надо начинать с 3-ей строки и искать по первому атрибуту каждой последующей строки(13,454,95). Количество разделителей в строке четко указано.

    Надеюсь от вас получить если и не детальный ответ, то хотя бы способы реализации данного приложения(Ссылки, методы реализации и т.д.).
    Заранее спасибо!

Додати коментар