Руководство по Java Core. Файлы и работа с ними.

При разработке программного обеспечения мы сталкиваемся с приложениями, в которых необходимо передавать или принимать файлы. Практически все классы, необходимые для этой задачи находтся в паке java.io.  В работе с файлами испольщуется такое понятие, как поток (stream), который принимает входной файл и перемещает его в место назначения.

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


Потоки (Streams)

Мы можем сказать ,что поток – это последовательность данных. Существует два вида потоков:

  • Входящий поток
    В Java для чтения файлов используется InputStream .
  • Исходящий поток
    В Java используется OutputStream для записи данных в файл.

Схематично это можно изобразить так:

streams

В Java крайне хорошо поддерживается работа с файлами. Рассмотрим различные примеры работы с файлами.


Байты

Чаще всего, для работы с байтами используются FileInputStream и FileOutputStream. Давайте рассмотрим как это работает на примере простого приложения.

Пример:

Создайте в корневой папке проекта папку resources. В это йпапке создайте два файла: inputFile.txt и outputFile.txt.

Файл inputFile.txt:


This is simple file with some text designed to demonstrate copying of files.

Оставьте файл outputFile.txt пустым.

Класс ByteStreamDemo


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;

        try {
            inputStream = new FileInputStream("resources/inputFile.txt");
            outputStream = new FileOutputStream("resources/outputFile.txt");

            int element;
            while ((element = inputStream.read()) != -1) {
                outputStream.write(element);
            }

            System.out.println("Copying information completed.");
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (inputStream != null) {
                outputStream.close();
            }
        }
    }
}

В результате работы программы мы получим следуюющий результат:


/*Some system messages*/
Copying information completed.

После запуска приложения смотрим файл outputFile.txt


This is simple file with some text designed to demonstrate copying of files.

Копирование успешно выполнено.


Символы

Байтовые потоки в Java используются для ввода и вывода 8-битных элементов. Символьные потоки используюстся для работы с 16-битной кодировкой Unicode.

Для работы с символами, чаще всего используют FileReader и FileWriter. FileReader читает одновременно по 2 байта, а FileWriter, в своб очередь, записывает по 2 байта за раз.

Для понимания того, как жто работает на практике рассмотирм пример простого приложения.

Пример:

Создайте в корневой папке проекта папку resources. В это йпапке создайте два файла: inputFile.txt и outputFile.txt.

Файл inputFile.txt:


This is simple file with some text designed to demonstrate copying of files.

Оставьте файл outputFile.txt пустым.

Класс CharacterStreamDemo


package net.proselyte.javacore.javaio;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CharacterStreamDemo {
    public static void main(String[] args) throws IOException {
        FileReader fileReader = null;
        FileWriter fileWriter = null;

        try {
            fileReader = new FileReader("resources/inputFile.txt");
            fileWriter = new FileWriter("resources/outputFile.txt");

            int element;

            while ((element = fileReader.read()) != -1) {
                fileWriter.write(element);
            }

            System.out.println("Data copying successfully completed.");
        } finally {
            if (fileReader != null) {
                fileReader.close();
            }
            if (fileWriter != null) {
                fileWriter.close();
            }
        }
    }
}

В результате работы программы мы получим следуюющий результат:


/*Some system messages*/
Data copying successfully completed.

После запуска приложения смотрим файл outputFile.txt


This is simple file with some text designed to demonstrate copying of files.

Копирование успешно выполнено.


Стандартные потоки

Как и во многих других языках программирования, в Java обеспечивается ввод информации в программу во время её выполнения. Для этих целей в Java существует три стандартных потока:

  • Стандратный ввод
    Используется для ввода пользователем информаци (обычно – клавиатура) и представлен элементом System.in.
  • Стандартный вывод
    Используется для вывода данных пользователю (обычно – экран монитора) и представлен элементом System.out.
  • Стандартная ошибка
    Используется для вывода ошибок произошедших при работе программы (обычно – на экран монитора) и представлен элементом System.err.

Для понимания того, как это работает на практике, рассмотрим пример простого приложения.

Пример:

Класс StandardStreamDemo


import java.io.IOException;
import java.io.InputStreamReader;

public class StandardStreamDemo {
    public static void main(String[] args) throws IOException {
        InputStreamReader inputStreamReader = null;

        try {
            inputStreamReader = new InputStreamReader(System.in);
            System.out.println("Enter characters (press Q to quit):");

            char character;
            do {
                character = (char) inputStreamReader.read();

                System.out.print(character);
            } while (character != 'Q');

        } finally {
            if (inputStreamReader != null) {
                inputStreamReader.close();
            }
        }
    }
}


Запускаем программу и начинаем вводить символы. Если нам необходимо выйти – вводим символ ‘Q’.

В результате работы рпограммы мы получим, примерно, следующий результат:


/*Some system messages*/
Enter characters (press Q to quit):
This is simple text for testing this program.
This is simple text for testing this program.
Q
Q


Чтение и запись файлов

Теперь рассмотрим чтение и запись файлов более подробно.

Рассмотренные ранее InputStream и OutputSream используются для чтения и записи данных из файлов записи их в файлы.

Давайте посмотрим а иерархию этих двух классов:

javaio
Далее мы рассмотрим FileInputStream и FileOutputStream.


FileInputStream

Этот элемент используется для чтения данных из файлов.

FileInputStream имеет следующие методы:

  • public void close() throws IOException
    Этот метод закрывает поток и освобождает любый ресурсы системы, которые связаны с этим файлом. В случае ошибки “бросает” IOException.
  •  public void finalize() throws IOException
    Этот метод “чистит” соединение с файлом.  И проверяет, что метод close() был вызван. В случае ошибки “бросает” IOException.
  • public int read(int r) throws IOException
    Этот метод читает определённые байты данных из входящего файла .Возвращает int. Если весь файл прочитан – будет возвращено занчение -1. В случае ошибки “бросает” IOException.
  • public int read(byte[] r) throws IOException
    Этот метод читает количество байтов, равное длине массива (r.length). Если весь файл прочитан – будет возвращено занчение -1. В случае ошибки “бросает” IOException.
  • public int available() throws IOException
    Этот метода возвращает количество байтов, которое может быть прочитано из заданного входного файла. Возвращает int.

Рассмотрим два ключевых входных потока:


 

FileOutputStream

Этот поток используется для создания файлов и записи в них данных. Если файл, в который мы хотим записать данные ещё не существует, то FileOutputStream создаст его автоматически.

Исходящий поток имеет следующие методы:

  • public void close() throws IOException
    Этот метод закрывает исходящий поток и освобождает все ресурсы системы, который связаны с ним. В случае ошибки “бросает” IOException.
  • protected void finalize() throws IOException
    Этот метод “чистит” соединение с файлом. Проверяет был ли вызван метод close(). В случае ошибки “бросает” IOException.
  • public void write(int w) throws IOException
    Этот метод записывает опредлённые байты в указанный файл. В случае ошибки “бросает” IOException.
  • public void write(byte[] w) throws IOException
    Этот метод записывает количество байтов, равное длине заданного массива (w.length)  в указанный файл. В случае ошибки “бросает” IOException.

Рассмотрим два ключевых исходящих потока:


Для понимания того, как это работает на практике, рассмотрим пример простого приложения.

Пример:


import java.io.*;

public class FileStreamDemo {
    public static void main(String[] args) throws IOException {
        byte[] bytesForWriting = {'b', 'y', 't', 'e', 's',};
        OutputStream outputStream = new FileOutputStream("resources/inputFile.txt");

        for (byte b : bytesForWriting) {
            outputStream.write(b);
        }
        outputStream.close();

        InputStream inputStream = new FileInputStream("resources/inputFile.txt");
        int size = inputStream.available();

        for (int i = 0; i < size; i++) {
            System.out.print((char) inputStream.read());
        }
        inputStream.close();
    }
}

В результате работы программы мы получим, следующий результат:


/*Some system messages*/
bytes


Навигация файлов и I/O

Рассмотрим другие ключевые классы, которые мы модем использовать при работе с файлами и I/O:


Директории в Java

Директория (грубо говоря – папка) – это экземпляр класса File, который содержит список других файлов.

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

  • mkdir()
    Этот метод создаёт директорию и возвращает логическое значение true, если создание прошло успешно, и false – если нет. Ошибка может быть вызвана либо тем, что данная директория уже существует, либо тем, что вводнй путь директории ещё не создан.
  • mkdirs()
    Этот метод метод создаёт и саму директорию и путь (родительские папки) к этой директории.

Для понимания того, как это работает на практике, рассмотрим пример простого приложения.

Пример:


import java.io.File;

public class DirectoriesDemo {
    public static void main(String[] args) {
        String dirName = "/home/proselyte/Programming/Projects/Proselyte/JavaCore/resources/testDir";
        File directory = new File(dirName);
        directory.mkdirs();
    }
}

В результате работы программы будет создана директория (папка) с названием testDir по указанному пути. Вы олжны вставить свой желаемый путь создаваемой директории.

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

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

Пример:


import java.io.File;
import java.io.IOException;

public class ListDirsDemo {
    public static void main(String[] args) throws IOException{
        File file;
        String[] directories;

        file = new File("/home/proselyte/Programming/Projects/Proselyte/JavaCore");

        directories = file.list();

        for(String directory: directories){
            System.out.println(directory);
        }
    }
}


В результате работы программы мы получим, примерно, следующий результат:


/*Some system messages*/
out
src
JavaCore.iml
.idea
resources

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

 

В следующем уроке мы изучим такую важную составляющую языка программирования Java, как исключения (Exceptions).