Чтение файлов андроид студио

Создаём текстовый редактор

Операции с файлами

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

Android использует стандартные операции ввода/вывода, принятые в Java. Например, Android реализует файловые потоки с помощью классов из пакета java.io, а также имеет собственные классы для работы с файлами внутри приложения.

Чтобы записать данные в файл, необходимо вызвать метод Context.openFileOutput() и передать в качестве параметра имя файла. Метод возвращает стандартный Java-объект FileOutputStream. Вызов метода для данного файла из другого приложения не будет работать, обратиться вы можете только к своим файлам. Например, чтобы создать файл и записать данные, пишем следующий код:

Если имеется статический файл, который надо упаковать с вашим приложением во время компиляции проекта, можно сохранить его в каталоге res/raw/, а затем открыть его при помощи метода Resources.openRawResource(). Он возвращает объект InputStream, который можно использовать для чтения файла. После окончания работы с потоком не забудьте его закрыть, вызвав метод close().

Создадим простейший аналог Блокнота, позволяющий записывать и читать данные из файла.

На экране активности разместим компонент EditText и растянем его:

activity_main.xml

Создадим пункты меню Открыть и Сохранить в ресурсах. Строковые ресурсы добавьте самостоятельно.

res/menu/menu_main.xml

В методах openFile() и saveFile() реализуем операции по открытию и сохранению файла. Для Kotlin код получился намного короче.

Класс MainActivity

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

Сохранение настроек — Флажки

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

Подготовим различные настройки, которые будем хранить в файле строковых ресурсов strings.xml:

res/values/strings.xml

Теперь создадим файл настроек preferences.xml (если забыли, то перечитайте статью Сохранение настроек):

res/xml/preferences.xml

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

Создадим новую активность, которая наследует от класса PreferenceActivity. В классе активности для предпочтений внутри метода обратного вызова onCreate() нужно только вызвать метод addPreferencesFromResource() и загрузить XML-файл preferences.xml, содержащий наши настройки (пока одну):

Класс SettingsActivity

Не забываем добавить объявление активности SettingsActivity в файл манифеста AndroidManifest.xml:

Добавим новый пункт меню Настройки в меню (файл res/menu/main.xml), чтобы открывать подготовленное окно настроек.

В методе onOptionsItemSelected() класса MainActivity добавим новый блок when/switch:

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

Чтение установок предпочтений нужно проводить в методе onResume(), который вызывается системой как во время запуска приложения, так и после закрытия окна настроек и возврата главной активности на передний план:

В методе getBoolean() второй параметр false означает значение по умолчанию для возвращаемого значения предпочтения, если запрос на чтение установленного значения закончится неудачей.

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

Сохранение текстовых настроек

Добавим возможность устанавливать размер шрифта для текста. Откроем снова файл preferences.xml и добавим новый элемент EditTextPreference:

В метод onResume() добавим новый код для чтения установленного значения размера шрифта:

Запустите проект и вызовите окно настроек. Теперь у нас появилась опция установки размера шрифта. Если щёлкнуть на новом пункте, то откроется диалоговое окно с текстовым полем ввода.

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

Сохранение настроек — Списки

Продолжим работу с текстовым редактором и добавим в него список для выбора стиля текста. В списке будет четыре опции: Обычный, Полужирный, Курсив, Полужирный+Курсив.

Подготовим массив строк и сохраним его в файле arrays.xml, который необходимо поместить в каталог res/values/ (хотя можно просто добавить в strings.xml).

res/values/arrays.xml

В файл preferences.xml добавим дополнительный элемент ListPreference, в котором определим атрибуты заголовка окна, привязку к массиву значений и значение по умолчанию:

Для чтения настроек из списка добавляем код в метод onResume() класса MainActivity:

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

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

Источник

Работа с файловой системой

Чтение и сохранение файлов

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

ОС Android построена на основе Linux. Этот факт находит свое отражение в работе с файлами. Так, в путях к файлам в качестве разграничителя в Linux использует слеш «/», а не обратный слеш «\» (как в Windows). А все названия файлов и каталогов являются регистрозависимыми, то есть «data» это не то же самое, что и «Data».

Читайте также:  Переходы между страницами android studio

Приложение Android сохраняет свои данные в каталоге /data/data/ / и, как правило, относительно этого каталога будет идти работа.

Для работы с файлами абстрактный класс android.content.Context определяет ряд методов:

boolean deleteFile (String name) : удаляет определенный файл

String[] fileList () : получает все файлы, которые содержатся в подкаталоге /files в каталоге приложения

File getCacheDir() : получает ссылку на подкаталог cache в каталоге приложения

File getDir(String dirName, int mode) : получает ссылку на подкаталог в каталоге приложения, если такого подкаталога нет, то он создается

File getExternalCacheDir() : получает ссылку на папку /cache внешней файловой системы устройства

File getExternalFilesDir(String type) : получает ссылку на каталог /files внешней файловой системы устройства

File getFileStreamPath(String filename) : возвращает абсолютный путь к файлу в файловой системе

FileInputStream openFileInput(String filename) : открывает файл для чтения

FileOutputStream openFileOutput (String name, int mode) : открывает файл для записи

Все файлы, которые создаются и редактируются в приложении, как правило, хранятся в подкаталоге /files в каталоге приложения.

Для непосредственного чтения и записи файлов применяются также стандартные классы Java из пакета java.io.

Итак, применим функционал чтения-записи файлов в приложении. Пусть у нас будет следующая примитивная разметка layout:

Поле EditText предназначено для ввода текста, а TextView — для вывода ранее сохраненного текста. Для сохранения и восстановления текста добавлены две кнопки.

Теперь в коде Activity пропишем обработчики кнопок с сохранением и чтением файла:

При нажатии на кнопку сохранения будет создаваться поток вывода FileOutputStream fos = openFileOutput(FILE_NAME, MODE_PRIVATE)

В данном случае введенный текст будет сохраняться в файл «content.txt». При этом будет использоваться режим MODE_PRIVATE

Система позволяет создавать файлы с двумя разными режимами:

MODE_PRIVATE : файлы могут быть доступны только владельцу приложения (режим по умолчанию)

MODE_APPEND : данные могут быть добавлены в конец файла

Поэтому в данном случае если файл «content.txt» уже существует, то он будет перезаписан. Если же нам надо было дописать файл, тогда надо было бы использовать режим MODE_APPEND:

Для чтения файла применяется поток ввода FileInputStream :

Подробнее про использование потоков ввода-вывода можно прочитать в руководстве по Java: https://metanit.com/java/tutorial/6.3.php

В итоге после нажатия кнопки сохранения весь текст будет сохранен в файле /data/data/название_пакета/files/content.txt

Где физически находится созданный файл? Чтобы увидеть его на подключенном устройстве перейдем в Android Stud в меню к пункту View -> Tool Windows -> Device File Explorer

После этого откроектся окно Device File Explorer для просмотра файловой системы устройства. И в папке data/data/[название_пакета_приложения]/files мы сможем найти сохраненный файл.

Источник

Чтение файлов андроид студио

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

Объект File подходит для чтения или записи больших объемов данных в порядке от начала до конца, без пропусков. Например, это хорошо подходит для файлов картинок или для различных обменов данными через сеть. Здесь будет показано, как выполнять базовые файловые операции в Вашем приложении. Подразумевается, что Вы знакомы с файловой системой Linux и стандартной системой ввода/вывода файлов в (standard file input/output API) в java.io.

[Выбор между внутренним и внешним хранилищем (Internal Storage, External Storage)]

Все устройства Android имеют две области хранения файлов (file storage area): «internal» и «external» storage. Эти имена появились на первых стадиях развития Android, когда большинство устройств поставлялись со встроенной энергонезависимой памятью FLASH (internal storage) плюс извлекаемый носитель памяти, такой как micro SD card (external storage). Некоторые устройства делили постоянную область хранения (permanent storage space) на разделы «internal» и «external», так что даже без наличия внешнего извлекаемого хранилища (removable storage medium) всегда имеется 2 пространства хранения, и поведение API всегда одинаково — независимо от того, есть в наличии внешнее хранилище или нет. Следующие списки подводят общую черту под фактическими различиями каждого пространства хранения.

Internal storage (внутреннее, неизвлекаемое хранилище): External storage (внешнее, извлекаемое хранилище):
• Оно всегда доступно.
• Файлы, которые сохранены здесь, по умолчанию доступны только Вашего приложения.
• Не требуется запрашивать разрешения на доступ к internal storage для Вашего приложения.
• Когда пользователь деинсталлирует Ваше приложение, то система также удалит все файлы приложения с internal storage.

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

• Оно не всегда доступно, потому что пользователь может монтировать external storage как USB MSD storage (Android работает как флешка, подключенная к компьютеру), и в некоторых случаях может просто извлечь external storage из устройства.
• External storage доступно на чтение для всех, так что файлы, сохраненные туда, могут прочитаны без Вашего контроля над процессом.
• Приложению требуется получить разрешение на доступ к external storage в файле манифеста.
• Когда пользователь деинсталлирует Ваше приложение, система удалит файлы Вашего приложения из external storage только если Вы сохранили их в директории из getExternalFilesDir() .

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

Совет: несмотря на то, что приложения по умолчанию устанавливаются в internal storage, Вы можете указать атрибут android:installLocation в файле манифеста, после чего Ваше приложение может быть установлено и на external storage. Пользователи ценят эту опцию, когда размер APK очень велик, и размер external storage space больше, чем internal storage. Дополнительную информацию см. в документации App Install Location [2].

[Получение разрешения для приложения на доступ к External Storage]

Чтобы иметь возможность записи в external storage, Вы должны запросить в файле манифеста разрешение WRITE_EXTERNAL_STORAGE :

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

Но если Ваше приложение использует разрешение WRITE_EXTERNAL_STORAGE, то это неявно дает ему также разрешение использовать и чтение external storage.

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

[Сохранение файла в Internal Storage]

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

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

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

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

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

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

[Сохранение файла в External Storage]

Поскольку external storage иногда может быть недоступно (когда пользователь смонтировал его как внешний USB-носитель на PC, или когда вытащил карту SD из телефона), то перед доступом к тому Вы должны всегда проверить, что он есть в наличии. Вы можете запросить состояние external storage вызовом getExternalStorageState() . Если возвращенное состояние External Storage равно MEDIA_MOUNTED , то Вы можете читать и записывать на него свои файлы. Например, следующие методы полезны для определения доступности устройства хранения:

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

Публичные файлы (Public files) — это файлы, которые должны быть свободно доступны для других приложений и пользователя. Когда пользователь деинсталлирует Ваше приложение, эти файлы должны остаться доступными для пользователя. Например, такими файлами могут быть фотографии, созданные другими приложениями или другие файлы, загруженные через сеть.

Частные файлы (Private files) — это файлы, полные права на которые принадлежат Вашему приложению, и которые должны быть удалены при деинсталляции Вашего приложения пользователем. Несмотря на то, что эти файлы технически доступны для пользователя и других приложений, поскольку они находятся на внешнем извлекаемом хранилище (external storage), эти файлы не имеют в реальности особого значения для пользователя вне Вашего приложения. Когда пользователь деинсталлирует Ваше приложение, система удалит все файлы в Вашем частном каталоге на внешнем хранилище. Примером таких файлов могут быть дополнительные ресурсы, загруженные Вашим приложением или временные медиафайлы.

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

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

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

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

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

[Опрос количества свободного места]

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

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

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

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

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

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

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

• Все файлы, сохраненные Вашим приложением на internal storage.
• Все файлы, сохраненные Вашим приложением с использованием getExternalFilesDir().

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

[Пример записи файла на sdcard0]

Предположим, что необходимо записать какой-нибудь тестовый файл (с именем myFile.txt) в папку myFolder на внешний носитель, который виден в системе Android как sdcard0. Т. е. полный путь должен выглядеть примерно так:

Базовый путь до External Storage

Проблема тут состоит в том, чтобы узнать часть пути basePath, поскольку на разных системах Android этот путь будет разным, в зависимости от версии и внутреннего аппаратного устройства. В моем телефоне Samsung Galaxy Note этот basePath = /storage/sdcard0 , но это еще не значит, что на Вашем телефона этот путь будет именно таким. Чтобы получить basePath, используйте вызов функции getExternalStorageDirectory :

Проверка доступности носителя данных в External Storage

Вторая проблема состоит в доступности на запись носителя данных. Дело в том, что записать на носитель можно не всегда, например если он смонтирован как флешка USB (когда Ваш телефон подключен к компьютеру в режиме Mass Storage Device, USB MSD). Проверить доступность носителя можно следующей функцией:

Разрешение доступа к носителю данных в файле манифеста

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

Функция, которая сохраняет файл, принимая полный путь до файла filePath и сохраняемый текст FileContent:

Вызов функции SaveFile, который выполняет задачу сохранения файла в External-носителе:

[Пример записи файла на extSdCard]

Получение полного корневого пути до извлекаемой карты SD не так прост, как до External Storage, поскольку в API Android для этого почему-то не предусмотрены специальные простые функции. Приходится получать путь окольными путями, через имена системных папок. Вот код функции, которая получает путь до извлекаемой карты SD:

Вызов функции SaveFile, который выполняет задачу сохранения файла на извлекаемой карте SD:

[Сохранение бинарного файла (массива byte[])]

В предыдущих примерах мы рассматривали класс OutputStreamWriter , который позволяет записать строку String или массив символов char[]. Но как быть, если нужно записать массив байт byte[]? Для этого подойдет класс DataOutputStream . Пример:

Примеры вызовов getAbsolutePath:

Вызов Результат вызова
Environment.getRootDirectory.getAbsolutePath() /system
Environment.getExternalStorageDirectory().getAbsolutePath() /storage/sdcard0
Environment.getExternalStoragePublicDirectory(null).getAbsolutePath() завершится с ошибкой
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS).getAbsolutePath() /storage/sdcard0/Alarms

[Ссылки]

1. Saving Files site:developer.android.com .
2. App Install Location site:developer.android.com .

Комментарии

В новых Android доступ на запись надо оформлять не в Манифесте. Вот что пишут: «Android added new permission model for Android 6.0 (Marshmallow). What Are Runtime Permissions? With Android 6.0 Marshmallow, Google introduced a new permission model that allows users to better understand why an application may be requesting specific permissions. Rather than the user blindly accepting all permissions at install time, the user is now prompted to accept permissions as they become necessary during application use.

microsin: ИМХО, это предупреждение чисто информационное, ничего не поменялось, разве что название. Раньше было все то же самое — перед установкой приложения Android показывает пользователю, какие действия будут разрешены приложению. Если пользователь согласен, то он подтверждает действие и установка продолжится, если нет — приложение не установится.

Источник

Читайте также:  Iphone или android как единственное устройство
Оцените статью