Афоризм
А быть моим врагом – врагу не пожелаю.
Наталья Резник
Последние статьи

 • Активности Android
Многоэкранные Android приложения
 • Fragment dynamic
Динамическая загрузка фрагментов в Android
 • Fragment lifecycle
Жизненный цикл Fragment'ов в Android
 • Fragment example
Пример Fragment'ов в Android
 • Data Binding
Описание и пример Data Binding
 • Пример MVVM
Пример использования MVVM в Android
 • Компонент TreeTable
Описание компонента TreeTable для Swing
 • Пример TreeTable
Пример использования TreeTable
 • Хранилища Android
Внутренние и внешние хранилища данных
 • Пример SQLite
Пример использования SQLite в Android
 • WebSocket
Описание и пример реализации WebSocket
 • Визуальные компоненты
Улучшен компонент выбора даты из календаря
 • Анимация jQuery
Описание и примеры анимации элементов DOM
 • APK-файл Android
Создание apk-файла для android устройств, .dex файлы
 • платформа JaBricks
Платформа OSGi-приложения JaBricks
Поддержка проекта

Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
 • Yandex.Деньги
  410013796724260

 • Webmoney
  R335386147728
  Z369087728698
Вернуться к описанию Хранение данных и файлов в Android

Пример использования хранилища файлов

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

Интерфейс представления

На следующем скриншоте представлен интерфейс примера после старта в Android Studio. В верхней части формы в виде белого прямоугольника располагается компонент ввода текстового значения, после которого размещается компонент в виде закрашенного прямоугольника для отображения текста файла при его извлечении из файла. В самом низу располагаются радио-кнопки выбора хранилища и кнопки выполнения транзакции (Чтение, Сохранение).

Бизнес-логика функционирования примера интуитивно понятна и примитивна. Необходимо ввести текст, выбрать хранилище и нажать кнопку Сохранение. После этого можно прочитать сохраненный текст. В разные файлы хранилищ можно записать различный текст. При сохранении текста в качестве преамбулы в него добавляется путь к файлу и его наименование (myFile); первые три строки текста представленного на скриншоте примера.

Описание кода

Ниже представлен проект/модуль store-file в IDE Android Studio.

В проекте определены следующие объекты :

  • ресурсные файлы :
    • colors.xml — набор цветов;
    • strings.xml — набор строк;
    • border_gray.xml — закрашенный прямоугольник;
    • border_white.xml — незакрашенный прямоугольник;
    • activity_main.xml — определение интерфейса;
  • MainActivity.java — главный модуль активности.

Интерфейс примера на уровне среды разработки (IDE) определяет главный ресурсный файл activity_main.xml. В режиме исполнения примера главный модуль активности MainActivity.java формирует интерфейс и определяет бизнес-логику управления компонентами. Остальные ресурсные файлы играют вспомогательную роль для представления интерфейса компонентов (цвет, фон, текст).

Листинг colors.xml

Ресурсный файл colors.xml создается автоматически средой Android Studio при формировании нового модуля/проекта. В контект файла добавлен цвет gray_light для подкраски фона прямоугольника.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="gray_light">#FFEEEEEE</color>
</resources>

Листинг strings.xml

Ресурсный файл strings.xml, также как и colors.xml, создается автоматически средой Android Studio при формировании нового модуля/проекта. В модуле переопределен заголок (app_name) и добавлены строки определения текста меток и кнопок интерфейса. В теге <string> с атрибутом name="multiple_text" определен двустрочный текст, который при старте записывается в верхний компонент/прямоугольник.

<resources>
    <string name="app_name">Хранилище файлов</string>
    <string name="tv_editor">Редактирование текста</string>
    <string name="tv_viewer">Просмотр файла</string>
    <string name="location">Расположение</string>
    <string name="radio_inner">Внутреннее</string>
    <string name="radio_cd">Внешнее (CD)</string>
    <string name="btn_save">Сохранение</string>
    <string name="btn_read">Чтение</string>
    <string name="multiple_text">"This is a TextView \n
                              With multiple lines</string>
</resources>

border_gray.xml

Ресурсный файл border_gray.xml создан для формирования интерфейса компонента TextView в виде закрашенного прямоугольника. Располагается файл в разделе res/drawable. Главная секция XML-файла имеет тег shape. Внутреннее содержимое файла определяет цвет фона, цвет обрамляющего прямоугольника и радиус скругления углов прямоугольника. Ниже представлен листинг файла border_gray.xml (в свернутом виде).

Листинг border_gray.xml

<?xml version="1.0" encoding="utf-8"?>
<shape 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <!-- View background color -->
    <solid
        android:color="@color/gray_light" >
    </solid>

    <!-- View border color and width -->
    <stroke
        android:width="1dp"
        android:color="@color/black" >
    </stroke>

    <!-- The radius makes the corners rounded -->
    <corners
        android:radius="3dp"   >
    </corners>
</shape>

Для создания ресурсного файла border_gray.xml с помощью IDE Android Studio необходимо выделить в проекте запись res/drawable и в контекстном меню выбрать пункт New/Drawable Resource File. В открывшемся диалоговом окне, как это представлено на следующем скриншоте, необходимо определить File name, наименование корневого элемента Root name и нажать ОК. После того, как файл будет создан, его можно открыть и отредактировать. Ресурсный файл border_white.xml отличается только цветом фона.

activity_main.xml

На следующем скриншоте представлен ресурсный файл activity_main.xml в режиме Design. Данный ресурс определяет интерфейс приложения/модуля в режиме run-time. Особый комментарий здесь не требуется. Можно только отметить, что для редактирования компонента в режиме Design его можно выделить в дереве компонентов Component Tree (слева снизу), и определить свойства в панели атрибутов, не представленной на скриншоте. Также компоненты можно редактировать непосредственно в файле, переключаясь в режим Code.

Ниже (в свернутом виде) представлен листинг activity_main.xml. После переключения редактора ресурсного файла из режима Design в режим Code свойства визуальных компонентов интерфейса можно редактировать непосредственно в файле. IDE Android Studio "помогает" при прямом редактировании свойств компонента представлением всплывающих подсказок.

Листинг activity_main.xml


<androidx.constraintlayout.widget.ConstraintLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity">

    <TextView
     android:id="@+id/tvEditor"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_marginStart="8dp"
     android:layout_marginTop="8dp"
     android:labelFor="@id/etmEditor"
     android:text="@string/tv_editor"
     android:textStyle="bold"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toTopOf="parent" />

    <EditText
     android:id="@+id/etmEditor"
     android:layout_width="380dp"
     android:layout_height="128dp"
     android:layout_marginStart="8dp"
     android:layout_marginTop="8dp"
     android:background="@drawable/border_white"
     android:ems="10"
     android:gravity="start|top"
     android:importantForAutofill="no"
     android:inputType="textMultiLine"
     android:lines="10"
     android:maxLines="10"
     android:padding="4dp"
     android:text="@string/multiple_text"
     android:textAlignment="viewStart"
     android:textSize="14sp"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@+id/tvEditor"
     tools:ignore="DuplicateSpeakableTextCheck" />

    <TextView
     android:id="@+id/textView"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_marginStart="8dp"
     android:layout_marginTop="16dp"
     android:text="@string/tv_viewer"
     android:textStyle="bold"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@+id/etmEditor"/>

    <EditText
     android:id="@+id/etmViewer"
     android:layout_width="380dp"
     android:layout_height="128dp"
     android:layout_marginStart="8dp"
     android:layout_marginTop="8dp"
     android:background="@drawable/border_gray"
     android:cursorVisible="false"
     android:ems="10"
     android:focusable="false"
     android:gravity="start|top"
     android:importantForAutofill="no"
     android:inputType="textMultiLine"
     android:lines="10"
     android:longClickable="false"
     android:maxLines="10"
     android:padding="4dp"
     android:textSize="14sp"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@+id/textView"
     tools:ignore="SpeakableTextPresentCheck" />

    <Button
     android:id="@+id/btnRead"
     android:layout_width="160dp"
     android:layout_height="56dp"
     android:layout_marginStart="8dp"
     android:layout_marginTop="16dp"
     android:onClick="onBtnReadClick"
     android:text="@string/btn_read"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@+id/rbGroup"/>

    <Button
     android:id="@+id/btnSave"
     android:layout_width="160dp"
     android:layout_height="56dp"
     android:layout_marginStart="8dp"
     android:layout_marginTop="16dp"
     android:onClick="onBtnSaveClick"
     android:text="@string/btn_save"
     app:layout_constraintStart_toEndOf="@+id/btnRead"
     app:layout_constraintTop_toBottomOf="@+id/rbGroup"/>

    <RadioGroup
     android:id="@+id/rbGroup"
     android:layout_width="320dp"
     android:layout_height="56dp"
     android:layout_marginStart="16dp"
     android:layout_marginTop="8dp"
     android:background="@drawable/border_white"
     android:orientation="horizontal"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@+id/tvLocation">

       <RadioButton
        android:id="@+id/rbIn"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:text="@string/radio_inner"
        app:layout_constraintStart_toStartOf="parent"/>

       <RadioButton
        android:id="@+id/rbOut"
        android:layout_width="160dp"
        android:layout_height="wrap_content"
        android:text="@string/radio_cd" />
    </RadioGroup>

    <TextView
     android:id="@+id/tvLocation"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_marginStart="16dp"
     android:layout_marginTop="16dp"
     android:text="@string/location"
     app:layout_constraintStart_toStartOf="parent"
     app:layout_constraintTop_toBottomOf="@+id/etmViewer"/>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java

Файл MainActivity.java (представлен ниже в свернутом виде) наследует свойства активности AppCompatActivity, формирует интерфейс примера и определяет бизнес-логику его компонентов.

Активность MainActivity включает несколько методов :

  • onCreate — метод формирования интерфейса, в котором дополнительно определеляются локальные переменные и настройки;
  • readExternalFile — метод чтения файла из внешнего хранилища;
  • readLocalFile — метод чтения локального файла;
  • writeExternalFile — метод сохранения текста в файл внешнего хранилища;
  • writeLocalFile — метод сохранения текста в локальный файл;
  • onBtnReadClick — вызов методов чтения файлов при обработке события нажатия на кнопку «Чтение»;
  • onBtnSaveClick — вызов методов сохранения текста в файл при обработке события нажатия на кнопку «Запись».

Детального описания кода активности не требуется, он прозрачен. Специфичные константы и методы обращения к хранилищам Android подсвечены.

Листинг MainActivity.java

package com.example.store.file;

import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity
{
    private EditText       tvEdit    = null;
    private EditText       tvView    = null;

    private RadioButton    rbIn      = null;

    private  final  String  FILENAME = "myFile";
    private  final  String  LOG_TAG  = "DEVELOPMENT";
    private         String  EXTERNAL_DIR;
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvEdit = findViewById(R.id.etmEditor);
        tvView = findViewById(R.id.etmViewer);
        rbIn   = findViewById(R.id.rbIn     );
        // Внешнее хранилище 
        EXTERNAL_DIR = Environment.DIRECTORY_MUSIC;
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    private void readExternalFile()
    {
        Log.d(LOG_TAG, "ExternalStorageState : " + 
                    Environment.getExternalStorageState());
        File dir= getExternalFilesDir(EXTERNAL_DIR);
        if (dir == null) {
            Log.d(LOG_TAG, "dir = NULL");
            return;
        }
        File file;
        file = new File(dir.getAbsolutePath(), FILENAME);
        Log.d(LOG_TAG, "file : " + file.getAbsolutePath());
        Log.d(LOG_TAG, "file exists : " + file.exists());
        if (file.exists()) {
            try {
                FileReader     fr = new FileReader(file);
                BufferedReader br = new BufferedReader(fr);
                String str;
                StringBuilder text = new StringBuilder();
                // читаем содержимое
                while ((str = br.readLine()) != null) {
                    if (!str.contains(":"))
                        str = "    " + str.trim();
                    text.append(str).append("\n");
                }
                tvView.setText(text.toString());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    void readLocalFile()
    {
        try {
            FileInputStream   fis ;
            InputStreamReader isr ;
            BufferedReader    br  ;
            StringBuilder     text;

            fis  = openFileInput(FILENAME);
            isr  = new InputStreamReader(fis);

            br   = new BufferedReader(isr);
            text = new StringBuilder();
            // читаем содержимое
            String str;
            while ((str = br.readLine()) != null) {
                if (!str.contains(":"))
                    str = "    " + str.trim();
                text.append(str).append("\n");
            }
            tvView.setText(text.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    void writeExternalFile()
    {
        Log.d(LOG_TAG, "ExternalStorageState : " +
                Environment.getExternalStorageState());
        File dir= getExternalFilesDir(EXTERNAL_DIR);
        try {
            File file;
            file= new File(dir.getAbsolutePath(),FILENAME);
            Log.d(LOG_TAG, file exists : "+file.exists());

            String txt="file :\n" +file.getAbsolutePath()
                      + "\ntext :\n" + tvEdit.getText()
                                             .toString();
            FileWriter     fw = new FileWriter(file);
            BufferedWriter bw = new BufferedWriter(fw);
            // пишем данные
            bw.write(txt);
            // закрываем поток
            bw.close();
            Log.d(LOG_TAG, "Файл записан");
            Log.d(LOG_TAG, "file exists : " + file.exists());
            Log.d(LOG_TAG, "file path : " + 
                            file.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    void writeLocalFile()
    {
        File internalStorageDir = getFilesDir();
        File file = new File(internalStorageDir, FILENAME);
        String txt = "file :\n" + file.getAbsolutePath()
               +"\ntext :\n" + tvEdit.getText().toString();
        try {
            FileOutputStream    fos;
            OutputStreamWriter  osw;
            fos = openFileOutput(FILENAME, MODE_PRIVATE);
            osw = new OutputStreamWriter(fos);
            BufferedWriter bw = new BufferedWriter(osw);
            bw.write(txt);
            bw.close();
            Log.d(LOG_TAG, "Файл записан");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    public void onBtnReadClick(View v)
    {
        if (rbIn.isChecked())
            readLocalFile();
        else
            readExternalFile();
    }
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    public void onBtnSaveClick(View v)
    {
        if (rbIn.isChecked())
            writeLocalFile();
        else
            writeExternalFile();
    }
}

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

  Рейтинг@Mail.ru