Операции чтения и записи в файл являются стандартным функционалом любых приложений, которые ведут журналирование событий, работу с файлами, вплоть до передачи данных по сети. В данной статье рассмотрим методы записи в файлы информации и чтения из файла записанной строки.
Структура проекта
Эстетических изменений стандартных кнопок или ListView в данном уроке производиться не будет, поскольку мы будем работать с тем, что скрыто от глаз пользователя, а именно работать с файлами.
Вся структура проекта соответственно состоит на этот раз лишь из одного класса: MainActivity
Также в проекте присутствуют следующие файлы ресурсов:
- activity_main.xml
- strings.xml
- styles.xml - в данном файле отсутствуют какие-либо изменения относящиеся к проекту.
Кроме этого внесены изменения в файл AndroidManifest.xml. В файле необходимо добавить следующие две строки. Это разрешения для приложения - производить операции чтения и записи с внешним накопителем (то есть SD Card телефона) В современным смартфонах на базе ОС Android в большинстве случаев запись информации производится во внешний накопитель, хотя обычный пользователь считает этот накопитель внутренним, поскольку он является встроенным, но с точки зрения операционной систем данный накопитель (то есть SD Card) является внешним накопителем. В данной статье не будет рассматриваться вариант работы с истинно внутренним накопителем.
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="ru.evileg.workwithfiles" >
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- ...
- </manifest>
Формирование разметки приложения
activity_main.xml
Разметка основной активити, в которой будет производиться работа нашего приложения. В данной разметке присутствует всего две кнопки (Button) и текстовое поле (TextView), в которое мы будем выводить информацию сохранённую в файле.
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingLeft="@dimen/activity_horizontal_margin"
- android:paddingRight="@dimen/activity_horizontal_margin"
- android:paddingTop="@dimen/activity_vertical_margin"
- android:paddingBottom="@dimen/activity_vertical_margin"
- android:background="#ffffff"
- android:orientation="vertical"
- tools:context=".MainActivity">
- <Button
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/write_file"
- android:id="@+id/buttonWrite"
- android:layout_gravity="center_horizontal" />
- <Button
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/read_file"
- android:id="@+id/buttonRead"
- android:layout_gravity="center_horizontal" />
- <TextView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/textView"
- android:textSize="26sp"
- android:layout_gravity="center_horizontal" />
- </LinearLayout>
strings.xml
Файл ресурсов текста в ОС Android. Подготовка всех строк, которые применяются в Вашем Приложении в данном файле, является не только хорошим тоном, но обязательным условием для разработки качественного Приложения. Поскольку, если вы будете дисциплинировать себя, сохранять всю подобную информацию в данном файле, то впоследствии это окупится, когда вы будете производить перевод Приложения на другие языки. Тем более, что в Android Studio имеется удобный функционал для этого.
- <resources>
- <string name="app_name">Work With Files</string>
- <string name="hello_world">Hello world!</string>
- <string name="action_settings">Settings</string>
- <string name="write_done">Запись выполнена</string>
- <string name="write_file">Записать данные в файл</string>
- <string name="read_file">Считать данные из файла</string>
- </resources>
styles.xml
В данном файле нет изменений относящихся к проекту. Но при создании проекта стандартная тема оформления не рендерится Android Studio. Выдается ошибки при предпросмотре и в режиме дизайна. Чтобы этого избежать, пропишите следующую информацию взамен старой.
- <resources>
- <!-- Base application theme. -->
- <style name="AppTheme" parent="Base.Theme.AppCompat.Light"/>
- </resources>
Основной класс проекта - MainActivity.java
Сегодня в данном классе сконцентрирован весь программный код. В данном классе производится формирование внешнего вида главной активити, а также организуется работа с файлами.
- package ru.evileg.workwithfiles;
- import android.os.Bundle;
- import android.os.Environment;
- import android.support.v7.app.AppCompatActivity;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- import android.widget.Toast;
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- /*
- * Создаем постоянные константы для удобства работы,
- * объявляем TextView, который должен быть доступен в нескольких методах класса
- */
- private static final String fileName = "hello.txt";
- private static final String text = "Hello World";
- private static TextView textView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- /*
- * Объявляем и инциализируем Кнопки (Button),
- * а также инициализируем TextView
- * Также в активити имплементирован метод слушателя событий нажатия,
- * то есть OnClickListener, который привязывается к кнопкам
- */
- textView = (TextView) this.findViewById(R.id.textView);
- Button buttonWrite = (Button) this.findViewById(R.id.buttonWrite);
- Button buttonRead = (Button) this.findViewById(R.id.buttonRead);
- buttonWrite.setOnClickListener(this);
- buttonRead.setOnClickListener(this);
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
- int id = item.getItemId();
- //noinspection SimplifiableIfStatement
- if (id == R.id.action_settings) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
- /*
- * Обработчик нажатий кнопок. Нажатая кнопка определяется по её ID через метод getID()
- */
- @Override
- public void onClick(View v) {
- switch (v.getId()){
- case R.id.buttonWrite:
- writeFile();
- break;
- case R.id.buttonRead:
- readFile();
- break;
- default:
- break;
- }
- }
- private void writeFile() {
- try {
- /*
- * Создается объект файла, при этом путь к файлу находиться методом класcа Environment
- * Обращение идёт, как и было сказано выше к внешнему накопителю
- */
- File myFile = new File(Environment.getExternalStorageDirectory().toString() + "/" + fileName);
- myFile.createNewFile(); // Создается файл, если он не был создан
- FileOutputStream outputStream = new FileOutputStream(myFile); // После чего создаем поток для записи
- outputStream.write(text.getBytes()); // и производим непосредственно запись
- outputStream.close();
- /*
- * Вызов сообщения Toast не относится к теме.
- * Просто для удобства визуального контроля исполнения метода в приложении
- */
- Toast.makeText(this, R.string.write_done, Toast.LENGTH_SHORT).show();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private void readFile() {
- /*
- * Аналогично создается объект файла
- */
- File myFile = new File(Environment.getExternalStorageDirectory().toString() + "/" + fileName);
- try {
- FileInputStream inputStream = new FileInputStream(myFile);
- /*
- * Буфферезируем данные из выходного потока файла
- */
- BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
- /*
- * Класс для создания строк из последовательностей символов
- */
- StringBuilder stringBuilder = new StringBuilder();
- String line;
- try {
- /*
- * Производим построчное считывание данных из файла в конструктор строки,
- * Псоле того, как данные закончились, производим вывод текста в TextView
- */
- while ((line = bufferedReader.readLine()) != null){
- stringBuilder.append(line);
- }
- textView.setText(stringBuilder);
- } catch (IOException e) {
- e.printStackTrace();
- }
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
- }
- }
Итог
Если в процессе изучения материала не возникло никаких проблем и ошибок, то по нажатию кнопки записи в файл произойдет создание нового файла и будет произведена запись строки "Hello World". При нажатии кнопки чтения будет выведена информация сохранённая в текстовом файле. Процесс показан на скриншотах ниже.
По нажатию кнопки производится запись в файл информации
Запись в файл
Чтение из файла производится по нажатию соответствующей кнопки. При этом в TextView выводится текст
Созданный файл hello.txt в файловом менеджере
Как я понял данное приложение сохраняет текст в один единственный файл - hello.txt. Хотел бы узнать как можно реализовать функцию создания новый текстовых файлов и их переименования, т.е после нажатия на кнопку сохранения будет создаваться новый текстовый файл, пользователь будет выбирать куда не телефоне его сохранить и сам же вводит имя файла. А так же как реализовать функцию выбора из каталога файлов, т. е при нажатие на кнопку "считать из файла" открывалась бы папка в которой у пользователя находятся другие текстовые документы и он мог их редактировать последующего редактирования.
эххх... как это было давно и не правда )))) я с тех пор (через пару месяцев после этой статьи +-) на Java и не писал больше.
Вот если меня накроет не по-детски и я всё-таки начну писать сравнительные статьи Android: Java vs Qt , вот тогда что-нибудь интересное и вывалится на эту тему. А так пока... даже не знаю, что Вам ответить.