Каталог расширений

Популярные теги

3gp       avi       fb2       jpg       mp3       pdf      

Как вывести из файла в java


Как открыть и прочитать текстовый файл в Java

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

Под текстовым файлом мы имеем в виду файл с текстом - все просто! Вы можете создать текстовый файл в таких программах, как Блокнот на компьютере с Windows, TextEdit на Mac, Gedit в среде Linux/Gnome.

Первое, что мы сделаем, это откроем текстовый файл и прочитаем его содержимое.

Как прочитать текстовый файл

Для этой цели начните новый проект. Назовите пакет openandread, а класс ReadFile. Добавьте оператор импорта чуть ниже названия пакета и перед именем класса:

import java.io.IOException;
 

Ваше окно с кодом будет выглядеть так:

package openandread;
 import java.io.IOException;
 
 public class ReadFile {
 
 public static void main(String[] args) throws IOException {
 
 } 
 }
 

Чтобы Java-программа работала корректно с нашими текстовыми файлами, добавьте следующее к методу main (текст на синем фоне):

public static void main(String[] args) throws IOException {
 
 }
 

Мы говорим Java, что метод main вызовет ошибку IOException, и что ее необходимо устранить. Позже мы добавим блок try ... catch, чтобы отобразить соответствующее сообщение об ошибке для пользователя.

Чтобы открыть текстовый файл, давайте создадим новый класс. Итак выберите File > New File в меню NetBeans вверху. Создайте новый файл Java Class и дайте ему имя FileData. Когда ваш новый класс будет создан, добавьте следующие три оператора импорта:

import java.io.IOException;
 import java.io.FileReader;
 import java.io.BufferedReader;

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

(Все три импорта подчеркнуты желтым цветом, потому что мы еще ничего с ними не сделали. Это функция NetBeans.)

Для того, чтобы прочитать текстовый файл Java, мы создадим новый объект из этого класса. Добавьте следующий конструктор в свой код вместе с приватным полем String с именем path_to_file :

public class FileData {
 
 private String path_to_file;
 
 public FileData (String path) {
 path_to_file = path;
 }
 
 }
 

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

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

Не переживайте из-за красного подчеркивания: оно исчезнет, ​​как только мы добавим код. NetBeans добавляет подчеркивание, потому что у нас нет оператора return.

Обратите внимание, что метод настроен на возврат массива String:

public String[]
 

Массив будет содержать все строки из текстового файла.

Также обратите внимание, что мы добавили в конец заголовка метода throws IOException. Каждый метод, который работает над чтением текстовых файлов в Java, нуждается в подобном методе. Throw в переводе с английского означает «выбросить». Java выбросит ошибки, которые мы сможем увидеть в нашем методе main.

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

Вы можете читать целые строки текста, а не отдельные символы. Для этого нужно передать то, что находится в FileReader классу BufferedReader. BufferedReader имеет удобный метод, называемый ReadLine. Как следует из названия, он используется для чтения целых строк, а не отдельных символов. А вот BufferedReader сохраняет символы в памяти (в буфере), чтобы ими было легче манипулировать.

Давайте установим FileReader и BufferedReader:

public String[] OpenAndRead() throws IOException {
 
 FileReader x = new FileReader(path_to_file);
 BufferedReader varRead = new BufferedReader(x);
 
 }
 

Здесь мы создаем два новых объекта: первый - это объект FileReader, который мы назвали x; второй - это объект BufferedReader с именем varRead.

FileReader открывает и считывает файл, исходя из пути к нему. Эту информацию мы сохраняем в переменной path_to_file. А дальше мы можем использовать ее.

В BufferedReader передается объект FileReader (в круглых скобках). Все символы файла затем сохранятся в памяти в ожидании манипуляции. Они сохранятся в переменной varRead.

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

int num = 3;
 String[] lines = new String[num];
 

Сейчас мы установили количество строк в текстовом файле равным 3. Очевидно, что текстовые файлы могут содержать любое количество строк, и мы обычно не знаем, сколько их. Поэтому вскоре мы это изменим. Мы напишем отдельный метод, который получает количество строк в текстовом файле.

Дальше мы устанавливаем массив строк. Количество позиций в массиве (его размер) устанавливается равным количеству строк. Мы поместили эту переменную в квадратные скобки.

Чтобы поместить все строки текста из файла в каждую позицию в массиве, нам нужен цикл. Цикл получит каждую строку текста и поместит их в массив. Добавьте следующее в код:




int i;
 for (i = 0; i < num; i++) {
 lines[i] = varRead.readLine();
 }
 

Ваше окно с кодом должно выглядеть так:

public String[] OpenAndRead() throws IOException {
 
 FileReader x = new FileReader(path_to_file);
 BufferedReader varRead = new BufferedReader(x);
 
 int num = 3;
 String[] lines = new String[num];
 
 int i;
 for (i = 0; i < num; i++) {
 lines[i] = varRead.readLine();
 }
 
 }
 

Цикл for идет от 0 до меньше, чем количества строк. (Помните, позиции массива начинаются с 0. Три строки будут сохранены в позициях 0, 1 и 2.)

Здесь мы обращаемся к строкам текста и сохраняем их в массив:

lines[i] = varRead.readLine();
 

После знака равенства мы имеем это:

varRead.readLine();
 

Объект varRead, который мы установили, читает все символы из текстового файла, которые находятся в памяти (в буфере). Мы можем использовать метод readLine, чтобы прочитать полную строку текстового файла из буфера. После того, как строка прочитана, мы сохраняем ее в позиции массива:

lines[i]
 

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

Осталось добавить в метод следующее:

varRead.close();
 return lines;
 

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

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

public String[] OpenAndRead() throws IOException {
 
 FileReader x = new FileReader(path_to_file);
 BufferedReader varRead = new BufferedReader(x);
 
 int num = 3;
 String[] lines = new String[num];
 
 int i;
 for (i = 0; i < num; i++) {
 lines[i] = varRead.readLine();
 }
 
 varRead.close();
 return lines;
 }
 

Однако все еще существует проблема количества строк. Мы указали жесткое 3. Нам нужно прочитать весь текстовый файл и посчитать, сколько в нем строк. Поэтому добавьте следующий метод в класс FileData:

int numStrings() throws IOException {
 
 FileReader text = new FileReader(path_to_file);
 BufferedReader y = new BufferedReader(text);
 
 String one;
 int num = 0;
 
 while ((one = y.readLine()) != null) {
 num++;
 }
 y.close();
 
 return num;
 }
 

Новый метод называется numStrings и настроен на возврат целочисленного значения. Это количество строк в текстовом файле. Обратите внимание, что этот метод в заголовке также имеет IOException.

В этом коде устанавливается другой FileReader и другой BufferedReader. Чтобы поставить в цикл наш текст, мы написали:

while ((one = y.readLine()) != null) {
 num++;
 }
 

Цикл while выглядит немного грязно. Но он просто говорит «прочитайте каждую строку текста и остановитесь, когда не будет достигнуто нулевое значение». (Если Java прочитала весь текстовый файл, и больше не осталось строк, вернется значение null.) В фигурных скобках мы увеличиваем счетчик с именем num.

В конце кода мы очищаем буфер памяти с именем y и возвращаем количество строк.

Чтобы вызвать этот новый метод в действие, измените методе OpenAndRead это:

int num = 3; 

На это:

int num = numStrings();
 

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

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

Вернитесь к классу ReadFile, классу с методом main. Установите строковую переменную для хранения имени текстового файла:

package openandread;
 import java.io.IOException;
 
 public class ReadFile {
 
 public static void main(String[] args) throws IOException {
 
 String new_path = "D:/test.txt";
 
 } 
 }
 

На этом этапе вам нужно создать текстовый файл где-нибудь на компьютере. Мы создали его в блокноте на компьютере с Windows:

Имя текстового файла - test.txt. Создайте аналогичный у себя. Обратите внимание, куда вы его сохраняете, чтоб указать правильный путь к нему:

String new_path = "D:/test.txt";
 

Если бы мы создали папку с именем MyFiles для хранения этого файла, путь был бы «D: /MyFiles/test.txt». Измените путь к файлу, если это необходимо.

Следующее, что нужно сделать, - это создать новый объект из нашего класса FileData. Затем мы сможем вызвать метод, который откроет и прочитает наш текстовый файл в Java. Мы сделаем это в блоке try ... catch.

Добавьте следующий код под переменной String:

try {
 FileData new_file = new ReadFile(new_path);
 String[] aryStrings = new_file.OpenAndRead();
 
 }
 catch (IOException a) {
 System.out.println(a.getMessage());
 }
 

Не забудьте все фигурные скобки для блока try ... catch. Вам нужна одна пара для части try и другая - для части catch. Для пробной части у нас есть это:

FileData new_file = new ReadFile(new_path);
 String[] aryStrings = new_file.OpenAndRead();
 

Первая строка устанавливает новый объект FileData с именем new_file. В круглых скобках FileData мы добавили переменную new_path. Этого достаточно, чтобы передать конструктору путь к файлу, который ему нужен.

Вторая строка кода устанавливает массив String с именем aryStrings. После знака равенства мы вызвали метод OpenAndRead нашего класса FileData. Если он успешно открывает текстовый файл, то массив текстовых строк будет передан новому массиву aryStrings.

Однако, если что-то пойдет не так, появится ошибка, которую мы поместили в части catch блока try ... catch:

catch (IOException a) {
 System.out.println(a.getMessage());
 }
 

После слова catch в круглых скобках у нас есть это:

IOException a
 

Для этого исключения мы устанавливаем переменную с именем a, которая имеет тип IOException. У объекта IOException есть собственные методы, которые вы можете использовать. Одним из таких методов является getMessage. Это даст пользователю некоторую информацию о том, что пошло не так.

Прежде чем мы увидим пример сообщения об ошибке, давайте пройдемся по всем строкам текстового файла, распечатав каждую. Добавьте следующий код цикла в try блока try ... catch:

int i;
 for (i = 0; i < aryStrings.length; i++) {
 System.out.println(aryStrings[i]);
 }
 

Ваше окно с кодом должно теперь выглядеть так:

package openandread;
 import java.io.IOException;
 
 public class ReadFile {
 
 public static void main(String[] args) throws IOException {
 
 String new_path = "D:/test.txt";
 
 try {
 ReadFile new_file = new FileData(new_path);
 String[] aryStrings = new_file.OpenAndRead();
 
 int i;
 for (i = 0; i < aryStrings.length; i++) {
 System.out.println(aryStrings[i]);
 }
 }
 catch (IOException a) {
 System.out.println(a.getMessage());
 } 
 } 
 }
 

Когда программа будет запущена, в окне «Вывод» будет напечатано следующее:

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

Чтобы проверить часть кода, проверяющую ошибки, измените имя вашего текстового файла на тот, который, как вы знаете, не был создан. Затем запустите этот код. В окне «Вывод» ниже вы можете видеть, что наш текстовый файл был изменен на test2, и его не удалось найти:

При желании вы можете добавить собственное сообщение об ошибке в блок catch:

catch (IOException e) {
 System.out.println("Извини, друг, не могу это сделать!");
 } 
 

Как прочитать текстовый файл с русскими буквами в Java

Если вас интересует, как прочитать текстовый файл на русском языке, то:

  1. Нужно добавить еще несколько import:
    import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.FileInputStream;
 
  2. В методе numStrings замените строку:
    FileReader text = new FileReader(path_to_file);
 

    На эту:

    Reader text = new InputStreamReader(new FileInputStream(path_to_file), "Cp1251");
 
  3. В методе OpenAndRead замените строку:
    FileReader x = new FileReader(path_to_file);
 

    На эту:

    Reader x = new InputStreamReader(new FileInputStream(path_to_file), "Cp1251");
 

Cp1251 – это кодировка, в которой выполнен текстовый файл. Мы конвертируем символы кириллицы с помощью InputStreamReader и FileInputStream.

Окно «Вывод» будет следующим:

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

Система ввода и вывода. Работа с файлами.

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

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

Еще одно предисловие перед теорией: эта статья может показаться несколько сложнее, чем те, которые мы учили раньше. Для организации потоков ввода и вывода нужно будет «сооружать» не малые конструкции. Сказать по правде, я и сам иногда забываю, что за чем следует. Поэтому, не нужно паниковать, если Вы запутались в объеме материала. Все придет со временем, когда Вы будете активно программировать.

Когда говорят о потоках ввода или вывода, обычно подразумевают файл или передачу по сети, иногда консоль. В Java неважно с каким видом ввода/вывода Вы работаете. Для всех средств нужно создать поток (stream) и уже работать с ним. Ввод представлен в классе InputStream, вывод — в OutputStream. Они обеспечивают общий интерфейс для всех подклассов. Все подклассы, которые от них наследуются реализуют ввод/вывод для разных форм данных. Stream инкапсулирует процессы низкого уровня. Алгоритм работы с потоковой передачей следующий:

  1. Создается поток
  2. Поток открыт
  3. Выполняет любое необходимое действие.
  4. Поток закрыт.

Вот все 4 действия, которые нужно совершить, чтобы считать или записать данные. На практике все станет еще проще. Прежде чем мы начнем программировать нужно, чтобы Вы посмотрели на схему классов, которые наследуются от InputStream и OutputStream. Запоминать их необязательно, нужно просто понимать иерархию.

Название классов говорят, какой из них за что отвечает.

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

Еще очень интересный класс RandomAccessFile. Он позволяет одновременно и читать и писать в файл. Для файла используется класс File, в конструктор которого можно прописать путь к файлу:

  1. package com.java_master;

  2.  

  3. import java.io.File;

  4. import java.io.FileNotFoundException;

  5. import java.io.IOException;

  6. import java.io.RandomAccessFile;

  7.  

  8. public class ReadAndWriteFileExample {

  9.    

  10.     public static void readFile() throws IOException{//некоторые методы выбрасывают исключения
  11.         //скоро мы доберемся до исключений

  12.         File file = new File("test.txt");//указываем полный путь к файлу.
  13.         //в конструктор передаем файл и строку "r" которая указывает, что файл можно только читать

  14.         StringBuilder sb = new StringBuilder();//нам нужно будет конкатенировать много строк

  15.         //String может значительно потребить ресурсы

  16.         int b = randomAccessFile.read();//читаем поток байтов

  17.         while(b != -1){//-1 будет означать конец файла. Если не писать этой строки, то прочитается только первая строка файла

  18.             sb = sb.append((char)b);//добавляем к нашей строке поток байтов, который мы прикастили к char. Если не кастить

  19.             //то выведет цифры, байтов

  20.             b = randomAccessFile.read();//читаем файл и записываем в поток

  21.         }

  22.         randomAccessFile.close();//не забываем закрывать поток

  23.         System.out.println(sb);//вывод в консоль
  24.  

  25.     }

  26.    

  27.         File file = new File("test.txt");//файл находится в нашем проекте
  28.         randomAccessFile.write(data.getBytes());//так как мы не можем работать с символами напрямую, нужно перевести строку в байты

  29.         randomAccessFile.close();//закрываем поток

  30.     }

  31.  

  32.         ReadAndWriteFileExample.writeFile("Some my data");

  33.         ReadAndWriteFileExample.readFile();

  34.  

  35.     }

  36.  

  37. }

 

Наш файл test.txt до запуска программы:

test.txt после запуска программы:

Как видите, запись перезаписала первую строку. В классе RandomAccessFile есть метод который позволяет читать и записывать в файл с определенной точки: randomAccessFile.seek(количество символов начиная с начала). Используя этот метод, можно писать файл и не перезаписывать предыдущие записи.

Хотя вышеперечисленные классы позволяют работать с потоком, Вы не можете напрямую прочитать или записать текст.В примере выше нам приходилось кастить байты к char и переводить строку в байты. Для того, чтобы увидеть символы без ухищрений в читаемом для человека формате нужно использовать классы Reader и Writer. Эти классы похожие на BufferedInputStream и BufferedOutputStream только позволяют работать с символами в формате юникод. Вот их иерархия:

Вот пример чтения и записи файла используя BufferedReader и BufferedWriter:

  1. package com.java_master;

  2.  

  3. import java.io.BufferedReader;

  4. import java.io.BufferedWriter;

  5. import java.io.FileInputStream;

  6. import java.io.FileOutputStream;

  7. import java.io.IOException;

  8. import java.io.InputStreamReader;

  9. import java.io.OutputStreamWriter;

  10. import java.io.PrintWriter;

  11. import java.io.StringReader;

  12.  

  13. public class ReadWriteFileUsingBuffered {

  14.  

  15.     public static void readFile() throws IOException{
  16.             StringBuilder sb = new StringBuilder();

  17.             String line = br.readLine();
  18.             while (line != null) {

  19.                 sb.append(line);

  20.                 line = br.readLine();

  21.             }

  22.  

Java | Потоки ввода-вывода

Потоки ввода-вывода

Последнее обновление: 25.04.2018

Отличительной чертой многих языков программирования является работа с файлами и потоками. В Java основной функционал работы с потоками сосредоточен в классах из пакета java.io.

Ключевым понятием здесь является понятие потока. Хотя понятие "поток" в программировании довольно перегружено и может обозначать множество различных концепций. В данном случае применительно к работе с файлами и вводом-выводом мы будем говорить о потоке (stream), как об абстракции, которая используется для чтения или записи информации (файлов, сокетов, текста консоли и т.д.).

Поток связан с реальным физическим устройством с помощью системы ввода-вывода Java. У нас может быть определен поток, который связан с файлом и через который мы можем вести чтение или запись файла. Это также может быть поток, связанный с сетевым сокетом, с помощью которого можно получить или отправить данные в сети. Все эти задачи: чтение и запись различных файлов, обмен информацией по сети, ввод-ввывод в консоли мы будем решать в Java с помощью потоков.

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

В основе всех классов, управляющих потоками байтов, находятся два абстрактных класса: InputStream (представляющий потоки ввода) и OutputStream (представляющий потоки вывода)

Но поскольку работать с байтами не очень удобно, то для работы с потоками символов были добавлены абстрактные классы Reader (для чтения потоков символов) и Writer (для записи потоков символов).

Все остальные классы, работающие с потоками, являются наследниками этих абстрактных классов. Основные классы потоков:

Потоки байтов

Класс InputStream

Класс InputStream является базовым для всех классов, управляющих байтовыми потоками ввода. Рассмотрим его основные методы:

  • int available(): возвращает количество байтов, доступных для чтения в потоке

  • void close(): закрывает поток

  • int read(): возвращает целочисленное представление следующего байта в потоке. Когда в потоке не останется доступных для чтения байтов, данный метод возвратит число -1

  • int read(byte[] buffer): считывает байты из потока в массив buffer. После чтения возвращает число считанных байтов. Если ни одного байта не было считано, то возвращается число -1

  • int read(byte[] buffer, int offset, int length): считывает некоторое количество байтов, равное length, из потока в массив buffer. При этом считанные байты помещаются в массиве, начиная со смещения offset, то есть с элемента buffer[offset]. Метод возвращает число успешно прочитанных байтов.

  • long skip(long number): пропускает в потоке при чтении некоторое количество байт, которое равно number

Класс OutputStream

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

  • void close(): закрывает поток

  • void flush(): очищает буфер вывода, записывая все его содержимое

  • void write(int b): записывает в выходной поток один байт, который представлен целочисленным параметром b

  • void write(byte[] buffer): записывает в выходной поток массив байтов buffer.

  • void write(byte[] buffer, int offset, int length): записывает в выходной поток некоторое число байтов, равное length, из массива buffer, начиная со смещения offset, то есть с элемента buffer[offset].

Абстрактные классы Reader и Writer

Абстрактный класс Reader предоставляет функционал для чтения текстовой информации. Рассмотрим его основные методы:

  • absract void close(): закрывает поток ввода

  • int read(): возвращает целочисленное представление следующего символа в потоке. Если таких символов нет, и достигнут конец файла, то возвращается число -1

  • int read(char[] buffer): считывает в массив buffer из потока символы, количество которых равно длине массива buffer. Возвращает количество успешно считанных символов. При достижении конца файла возвращает -1

  • int read(CharBuffer buffer): считывает в объект CharBuffer из потока символы. Возвращает количество успешно считанных символов. При достижении конца файла возвращает -1

  • absract int read(char[] buffer, int offset, int count): считывает в массив buffer, начиная со смещения offset, из потока символы, количество которых равно count

  • long skip(long count): пропускает количество символов, равное count. Возвращает число успешно пропущенных символов

Класс Writer определяет функционал для всех символьных потоков вывода. Его основные методы:

  • Writer append(char c): добавляет в конец выходного потока символ c. Возвращает объект Writer

  • Writer append(CharSequence chars): добавляет в конец выходного потока набор символов chars. Возвращает объект Writer

  • abstract void close(): закрывает поток

  • abstract void flush(): очищает буферы потока

  • void write(int c): записывает в поток один символ, который имеет целочисленное представление

  • void write(char[] buffer): записывает в поток массив символов

  • absract void write(char[] buffer, int off, int len) : записывает в поток только несколько символов из массива buffer. Причем количество символов равно len, а отбор символов из массива начинается с индекса off

  • void write(String str): записывает в поток строку

  • void write(String str, int off, int len): записывает в поток из строки некоторое количество символов, которое равно len, причем отбор символов из строки начинается с индекса off

Функционал, описанный классами Reader и Writer, наследуется непосредственно классами символьных потоков, в частности классами FileReader и FileWriter соответственно, предназначенными для работы с текстовыми файлами.

Теперь рассмотрим конкретные классы потоков.

Чтение и запись файлов. Курс "Программирование на Java"

В Java есть четыре основных абстрактных класса, реализующих потоки ввода-вывода: InputStream, OutputStream, Reader, Writer. Первые два работают с байтами, вторые – с символами.

Для работы с файлами от этих абстрактных классов созданы соответственно классы FileInputStream, FileOutputStream, FileReader, FileWriter. Они являются адаптерами для объектов класса File к "интерфейсам" InputStream, OutputStream, Reader, Writer, т. е. к их методам.

Скажем несколько слов об адаптере как паттерне, или шаблоне, проектирования. Класс-адаптер A наследуется от интерфейса B, к которому приспосабливается объект другого класса – C. Класс-адаптер A имеет поле типа класса объекта C.

Например, объект File адаптируется к потоку ввода InputStream, т. е. все, что мы хотим получить из File, в конечном итоге мы будем получать из InputStream. Фактически мы работаем с InputStream, через адаптер FileInputStream, который с одной стороны наследуется от InputStream, а с другой – имеет поле, которому присваивается объект File.

Адаптер выполняет работу по получению данных из файла и адаптации их к тому виду, который можно передать в методы InputStream. Класс-адаптер, в данном примере – FileInputStream, переопределяет методы InputStream, добавляя в них свой код.

В основной ветке сначала создается объект, для которого требуется адаптер. Затем создается переменная класса, к которому выполняется адаптация. Этой переменной присваивается объект класса-адаптера, в конструктор которого передается адаптируемый объект.

File file = new File("/home/user/pic.jpg"); InputStream fIn = new FileInputStream(file);

Часто переменную определяют самим классом-адаптером:

FileInputStream fIn = new FileInputStream(file);

В конструктор можно передать строку-адрес. Объект File будет создан внутри адаптера. Пример побайтового копирования файла:

import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;   public class InputOutputStream { public static void main(String[] args) throws IOException {   FileInputStream fileIn = new FileInputStream("src/file/pets.png"); FileOutputStream fileOut = new FileOutputStream("src/file/pets2.png");   while (fileIn.available() > 0) { int oneByte = fileIn.read(); fileOut.write(oneByte); } fileIn.close(); fileOut.close(); } }

Если используются относительные адреса, они должны начинаться от корня проекта.

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

Метод available() объекта класса FileInputStream возвращает количество непрочитанных байтов. Метод read() читает один байт и расширяет его до типа int. Кроме этого, есть другой метод read(), читающий массив байт в переменную-аргумент и возвращающий количество реально прочитанных байт. Метод write() также позволяет записывать блоками.

byte[] blockBytes = new byte[100];   while (fileIn.available() > 0) { int qtyBytes = fileIn.read(blockBytes); fileOut.write(blockBytes, 0, qtyBytes); }

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

У объектов FileOutputStream имеется метод flush(), который принудительно записывает находящиеся в буфере байты на диск. При вызове close() это происходит автоматически.

С помощью класса PrintStream также можно создать поток вывода в файл. PrintStream является наследником FilterOutputStream, который в свою очередь наследник OutputStream как и FileOutputStream.

import java.io.FileNotFoundException; import java.io.PrintStream;   public class PrintStreamTest { public static void main(String[] args) throws FileNotFoundException {   PrintStream fileOut = new PrintStream("src/file/text.txt"); fileOut.println(10.5); fileOut.printf("%s - %d - %f", "hi", 10, 1.1); fileOut.close(); } }

Функция printf() предназначена для форматированного вывода.

Заметим, переменная System.out является объектом типа PrintStream.

В работе с вводом-выводом также используется другой паттерн проектирования – обертка (wrapper), он же декоратор (decorator). Декоратор расширяет функциональность объекта, а не приспосабливает объект к какому-либо стороннему интерфейсу.

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

В основной ветке создается объект оборачиваемого класса, который передается в конструктор обертки. Внутри класса-обертки есть поле типа декорируемого класса. Этому полю присваивается переданный объект.

BufferedInputStream – класс-обертка для InputStream (наследует через FilterInputStream). В отличие от InputStream класс BufferedInputStream позволяет предварительно читать в буфер порции байт, что уменьшает количество обращений к файлу. Существует также BufferedOutputStream.

import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException;   public class BufferStream { public static void main(String[] args) throws IOException {   FileInputStream fileIn = new FileInputStream("src/file/text.txt"); BufferedInputStream bufIn = new BufferedInputStream(fileIn, 100);   int i; while((i = bufIn.read())!= -1){ System.out.print((char)i); } } }

Конструктор класса BufferedInputStream принимает объект InputStream или его наследника.

Хотя данные считываются блоками, метод read() извлекает их по одному. Однако в данном случае он будет извлекать их из буфера.

С помощью классов FileReader и FileWriter выполняется ввод-вывод в текстовые файлы.

FileReader reader = new FileReader("src/file/text.txt"); FileWriter writer = new FileWriter("src/file/text2.txt");   while (reader.ready()) { int c = reader.read(); writer.write(c); }   reader.close(); writer.close();

Метод ready() возвращает истину, если остались непрочитанные символы.

Читать и писать можно блоками. Также методу write() можно передать строку:

FileReader reader = new FileReader("src/file/text.txt"); FileWriter writer = new FileWriter("src/file/text3.txt");   char[] buff = new char[10];   while (reader.ready()) { int qtySymbols = reader.read(buff); writer.write(buff, 0, qtySymbols); }   writer.write("Halo");   reader.close(); writer.close();

Рассматривая ввод данных с клавиатуры, мы уже использовали класс BufferedReader, который наследуется от Reader и позволяет читать отдельные строки методом readLine(). Его также можно использовать для построчного чтения файлов:

import java.io.*;   public class BufferedReaderTest { public static void main(String[] args) throws IOException {   Reader reader = new FileReader("src/file/text.txt"); BufferedReader buffReader = new BufferedReader(reader);   while (buffReader.ready()) { System.out.println(buffReader.readLine()); }   reader.close(); buffReader.close(); } }

Существует и BufferedWriter.

Java. Система ввода/вывода

Статья проплачена кошками - всемирно известными производителями котят.

Если статья вам понравилась, то можете поддержать проект.

Класс File
Поток
Класс OutputStream
Исключения ввода/вывода

Java имеет в своём составе множество классов, связанных с вводом/выводом данных. Рассмотрим некоторые из них.

Класс File

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

Подробнее о классе java.io.File

Поток

При работе с данными ввода/вывода вам будет часто попадаться термин Поток (Stream). Поток - это абстрактное значение источника или приёмника данных, которые способны обрабатывать информацию. Вы в реальности не видите, как действительно идёт обработка данных в устройствах ввода/вывода, так как это сложно и вам это не нужно. Это как с телевизором - вы не знаете, как сигнал из кабеля превращается в картинку на экране, но вполне можете переключаться между каналами через пульт.

Есть два типа потоков: байтовые и символьные. В некоторых ситуациях символьные потоки более эффективны, чем байтовые.

За ввод и вывод отвечают разные классы Java. Классы, производные от базовых классов InputStream или Reader, имеют методы с именами read() для чтения отдельных байтов или массива байтов (отвечают за ввод данных). Классы, производные от классов OutputStream или Write, имеют методы с именами write() для записи одиночных байтов или массива байтов (отвечают за вывод данных).

Подробнее о классе InputStream

Класс OutputStream

Класс OutputStream - это абстрактный класс, определяющий потоковый байтовый вывод.

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

BufferedOutputStream
Буферизированный выходной поток
ByteArrayOutputStream
Создает буфер в памяти. Все данные, посылаемые в этот поток, размещаются в созданном буфере
DataOutputStream
Выходной поток, включающий методы для записи стандартных типов данных Java
FileOutputStream
Отправка данных в файл на диске. Реализация класса OutputStream
ObjectOutputStream
Выходной поток для объектов
PipedOutputStream
Реализует понятие выходного канала.
FilterOutputStream
Абстрактный класс, предоставляющий интерфейс для классов-надстроек, которые добавляют к существующим потокам полезные свойства.

Методы класса:

  • int close() - закрывает выходной поток. Следующие попытки записи передадут исключение IOException
  • void flush() - финализирует выходное состояние, очищая все буферы вывода
  • abstract void write (int oneByte) - записывает единственный байт в выходной поток
  • void write (byte[] buffer) - записывает полный массив байтов в выходной поток
  • void write (byte[] buffer, int offset, int count) - записывает диапазон из count байт из массива, начиная с смещения offset

BufferedOutputStream

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

ByteArrayOutputStream

Класс ByteArrayOutputStream использует байтовый массив в выходном потоке. Метод close() можно не вызывать.

DataOutputStream

Класс DataOutputStream позволяет писать элементарные данные в поток через интерфейс DataOutput, который определяет методы, преобразующие элементарные значения в форму последовательности байтов. Такие потоки облегчают сохранение в файле двоичных данных.

Класс DataOutputStream расширяет класс FilterOutputStream, который в свою очередь, расширяет класс OutputStream.

Методы интерфейса DataOutput:

  • writeDouble(double value)
  • writeBoolean(boolean value)
  • writeInt(int value)

FileOutputStream

Класс FileOutputStream создаёт объект класса OutputStream, который можно использовать для записи байтов в файл. Создание нового объекта не зависит от того, существует ли заданный файл, так как он создаёт его перед открытием. В случае попытки открытия файла, доступного только для чтения, будет передано исключение.

Классы символьных потоков

Символьные потоки имеют два основных абстрактных класса Reader и Writer, управляющие потоками символов Unicode.

Reader

Методы класса Reader:

  • abstract void close() - закрывает входной поток. Последующие попытки чтения передадут исключение IOException
  • void mark(int readLimit) - помещает метку в текущую позицию во входном потоке
  • boolean markSupported() - возвращает true, если поток поддерживает методы mark() и reset()
  • int read() - возвращает целочисленное представление следующего доступного символа вызывающего входного потока. При достижении конца файла возвращает значение -1. Есть и другие перегруженные версии метода
  • boolean ready() - возвращает значение true, если следующий запрос не будет ожидать.
  • void reset() - сбрасывает указатель ввода в ранее установленную позицию метки
  • logn skip(long charCount) - пропускает указанное число символов ввода, возвращая количество действительно пропущенных символов
BufferedReader
Буферизированный входной символьный поток
CharArrayReader
Входной поток, который читает из символьного массива
FileReader
Входной поток, читающий файл
FilterReader
Фильтрующий читатель
InputStreamReader
Входной поток, транслирующий байты в символы
LineNumberReader
Входной поток, подсчитывающий строки
PipedReader
Входной канал
PushbackReader
Входной поток, позволяющий возвращать символы обратно в поток
Reader
Абстрактный класс, описывающий символьный ввод
StringReader
Входной поток, читающий из строки

Класс BufferedReader

Класс BufferedReader увеличивает производительность за счёт буферизации ввода.

Класс CharArrayReader

Класс CharArrayReader использует символьный массив в качестве источника.

Класс FileReader

Класс FileReader, производный от класса Reader, можно использовать для чтения содержимого файла. В конструкторе класса нужно указать либо путь к файлу, либо объект типа File.

Writer

Класс Writer - абстрактный класс, определяющий символьный потоковый вывод. В случае ошибок все методы класса передают исключение IOException.

Методы класса:

  • Writer append(char c) - добавляет символ в конец вызывающего выходного потока. Возвращает ссылку на вызывающий поток
  • Writer append(CharSequence csq) - добавляет символы в конец вызывающего выходного потока. Возвращает ссылку на вызывающий поток
  • Writer append(CharSequence csq, int start, int end) - добавляет диапазон символов в конец вызывающего выходного потока. Возвращает ссылку на вызывающий поток
  • abstract void close() - закрывает вызывающий поток
  • abstract void flush() - финализирует выходное состояние так, что все буферы очищаются
  • void write(int oneChar) - записывает единственный символ в вызывающий выходной поток. Есть и другие перегруженные версии метода
BufferedWriter
Буферизированный выходной символьный поток
CharArrayWriter
Выходной поток, который пишет в символьный массив
FileWriter
Выходной поток, пишущий в файл
FilterWriter
Фильтрующий писатель
OutputStreamWriter
Выходной поток, транслирующий байты в символы
PipedWriter
Выходной канал
PrintWriter
Выходной поток, включающий методы print() и println()
StringWriter
Выходной поток, пишущий в строку
Writer
Абстрактный класс, описывающий символьный вывод

Класс BufferedWriter

Класс BufferedWriter - это класс, производный от класса Writer,который буферизует вывод. С его помощью можно повысить производительность за счёт снижения количества операций физической записи в выходное устройство.

Класс CharArrayWriter

Класс CharArrayWriter использует массив для выходного потока.

Класс FileWriter

Класс FileWriter создаёт объект класса, производного от класса Writer, который вы можете применять для записи файла. Есть конструкторы, которые позволяют добавить вывод в конец файла. Создание объекта не зависит от наличия файла, он будет создан в случае необходимости. Если файл существует и он доступен только для чтения, то передаётся исключение IOException.

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

Существует множество классов и методов для чтения и записи файлов. Наиболее распространённые из них - классы FileInputStream и FileOutputStream, которые создают байтовые потоки, связанные с файлами. Чтобы открыть файл, нужно создать объект одного из этих файлов, указав имя файла в качестве аргумента конструктора.

 FileInputStream(String filename) throws FileNotFoundException FileOutputStream(String filename) throws FileNotFoundException 

В filename нужно указать имя файла, который вы хотите открыть. Если при создании входного потока файл не существует, передаётся исключение FileNotFoundException. Аналогично для выходных потоков, если файл не может быть открыт или создан, также передаётся исключение. Сам класс исключения происходит от класса IOException. Когда выходной файл открыт, любой ранее существовавший файл с тем же именем уничтожается.

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

В JDK 7 метод close() определяется интерфейсом AutoCloseable и можно явно не закрывать файл, а использовать новый оператор try-с-ресурсами, что для Android пока не слишком актуально.

Чтобы читать файл, нужно вызвать метод read(). Когда вызывается этот метод, он читает единственный байт из файла и возвращает его как целое число. Когда будет достигнут конец файла, то метод вернёт значение -1. Примеры использования методов есть в различных статьях на сайте.

Иногда используют вариант, когда метод close() помещается в блок finally. При таком подходе все методы, которые получают доступ к файлу, содержатся в пределах блока try, а блок finally используется для закрытия файла. Таким образом, независимо от того, как закончится блок try, файл будет закрыт.

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

Для записи в файл используется метод write().

 void write(int value) throws IOException 

Метод пишет в файл байт, переданный параметром value. Хотя параметр объявлена как целочисленный, в файл записываются только младшие восемь бит. При ошибке записи передаётся исключение.

В JDK 7 есть способ автоматического управления ресурсами:

 try (спецификация_ресурса) { // использование ресурса } 

Когда в Android будет полноценная поддержка JDK 7, то дополним материал.

Буферизированное чтение из файла - BufferedReader

Чтобы открыть файл для посимвольного чтения, используется класс FileInputReader; имя файла задаётся в виде строки (String) или объекта File. Ускорить процесс чтения помогает буферизация ввода, для этого полученная ссылка передаётся в конструктор класса BufferedReader. Так как в интерфейсе класса имеется метод readLine(), все необходимое для чтения имеется в вашем распоряжении. При достижении конца файла метод readLine() возвращает ссылку null.

Вывод в файл - FileWriter

Объект FileWriter записывает данные в файл. При вводе/выводе практически всегда применяется буферизация, поэтому используется BufferedWriter.

Когда данные входного потока исчерпываются, метод readLine() возвращает null. Для потока явно вызывается метод close(); если не вызвать его для всех выходных файловых потоков, в буферах могут остаться данные, и файл получится неполным.

Сохранение и восстановление данных - PrintWriter

PrintWriter форматирует данные так, чтобы их мог прочитать человек. Однако для вывода информации, предназначенной для другого потока, следует использовать классы DataOutputStream для записи данных и DataInputStream для чтения данных.

Единственным надежным способом записать в поток DataOutputStream строку так, чтобы ее можно было потом правильно считать потоком DataInputStream, является кодирование UTF-8, реализуемое методами readUTF() и writeUTF(). Эти методы позволяют смешивать строки и другие типы данных, записываемые потоком DataOutputStream, так как вы знаете, что строки будут правильно сохранены в Юникоде и их будет просто воспроизвести потоком DataInputStream.

Метод writeDouble() записывает число double в поток, а соответствующий ему метод readDouble() затем восстанавливает его (для других типов также существуют подобные методы).

RandomAccessFile - Чтение/запись файлов с произвольным доступом

Работа с классом RandomAccessFile напоминает использование совмещенных в одном классе потоков DataInputStream и DataOutputStream (они реализуют те же интерфейсы DataInput и DataOutput). Кроме того, метод seek() позволяет переместиться к определенной позиции и изменить хранящееся там значение.

При использовании RandomAccessFile необходимо знать структуру файла. Класс RandomAccessFile содержит методы для чтения и записи примитивов и строк UTF-8.

RandomAccessFile может открываться в режиме чтения ("r") или чтения/записи ("rw"). Также есть режим "rws", когда файл открывается для операций чтения-записи и каждое изменение данных файла немедленно записывается на физическое устройство.

Исключения ввода/вывода

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

Дополнительное чтение

Используем AsyncTask для загрузки текстового файла из сети - используются BufferedReader, InputStreamReader, InputStream.

Реклама

csv - чтение из входного файла и запись в выходной файл в Java

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
.

вывод Java в файл - qaru.

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
  4. Талант Нанимайте технических специалистов и создавайте свой бренд работодателя
  5. Реклама Обратитесь к разработчикам и технологам со всего мира
  6. О компании
.

Как вывести двоичные данные в файл на Java?

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
  4. Талант Нанимайте технических специалистов и создавайте свой бренд работодателя
.

Как читать данные из файла, помещать их в переменную и выводить в другой файл. Java

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
.

logging - Как записать весь вывод системы в файл на JAVA?

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
.

io - Как вы направите вывод одного файла на ввод другого в Java?

Переполнение стека
  1. Около
  2. Продукты
  3. Для команд
  1. Переполнение стека Общественные вопросы и ответы
  2. Переполнение стека для команд Где разработчики и технологи делятся частными знаниями с коллегами
  3. Вакансии Программирование и связанные с ним технические возможности карьерного роста
.

Смотрите также