Ошибка java нет ввода вывода

What are IO Exceptions (java.io.IOException) and what causes them?

What methods/tools can be used to determine the cause so that you stop the exception from causing premature termination? What does this mean, and what can I do to fix this exception?

asked Sep 6, 2018 at 1:03

Victor's user avatar

3

Java IOExceptions are Input/Output exceptions (I/O), and they occur whenever an input or output operation is failed or interpreted. For example, if you are trying to read in a file that does not exist, Java would throw an I/O exception.

When writing code that might throw an I/O exception, try writing the code in a try-catch block. You can read more about them here: https://docs.oracle.com/javase/tutorial/essential/exceptions/catch.html

Your catch block should look something like this:

try {
    //do something
}catch(FileNotFoundException ex){
    System.err.print("ERROR: File containing _______ information not found:n");
    ex.printStackTrace();
    System.exit(1);
}

answered Sep 6, 2018 at 1:14

Code Daddy's user avatar

Here you go https://docs.oracle.com/javase/7/docs/api/java/io/IOException.html

IOException is thrown when an error occurred during an input-output operation. That can be reading/writing to a file, a stream (of any type), a network connection, connection with a queue, a database etc, pretty much anything that has to do with data transfer from your software to an external medium.

In order to fix it, you would want to see the stack trace of your exception or at least the message, to see exactly where the exception is thrown and why.

try {
    methodThrowingIOException();
} catch (IOException e) {
    System.out.println(e.getMessage()); //if you're using a logger, you can use that instead to print.
    //e.printStackTrace(); //or print the full stack.
}

The error message that will be printed will likely show you what the issue is. If you add the error message here, I’ll be able to give you more info on how to fix that specific IOException. Without that, no one can really give you a complete answer.

answered Sep 6, 2018 at 1:16

Stef's user avatar

StefStef

2,5832 gold badges18 silver badges28 bronze badges

It is a very generic exception that a lot IO operation can cause. A best way is to read the Stack Trace. To continue the execution you can use the try-catch block to bypass the exception, but as you mention you should investigate into the cause.

To print the stack trace:

try {
    // IO operation that could cause an exception
} catch (Exception ex) {
    ex.printStackTrace();
}

answered Sep 6, 2018 at 1:08

mckuok's user avatar

mckuokmckuok

7446 silver badges11 bronze badges

IOException is usually a case in which the user inputs improper data into the program. This could be data types that the program can’t handle or the name of a file that doesn’t exist. When this happens, an exception (IOException) occurs telling the compiler that invalid input or invalid output has occurred.

Like others have said, you can use a try-catch statement to stop a premature termination.

try {
 // Body of code
} catch (IOException e) {
 e.printStackTrace();
}

answered Sep 6, 2018 at 1:18

kPs's user avatar

9. Потоки ввода/вывода

Методические указания

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

Байтовые потоки обеспечивают чтение и запись двоичных данных. Реализованы подклассами классов InputStream (байтовые потоки ввода) и OutputStream (байтовые потоки вывода).

Символьные потоки предназначены для чтения и записи текстовых данных в кодировке Unicode. Реализованы подклассами классов Reader (символьные потоки ввода) и Writer (символьные потоки вывода).

Проверка существования и доступности файла

Объекты класса File представляют файлы и директории. Объекты типа Path представляют пути к файлам и директориям. Класс Files обеспечивает статические методы управления файлами и директориями. Класс Paths предоставляет статические методы конвертирования путей, заданных строками String или ссылками на ресурсы URI в объекты типа Path.

package ru.isu.math.files;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;

public class MyApp {
    public static void main(String[] args) {
        File file = new File("data/source.txt");
        Path path = file.toPath();

        // Проверить существует ли заданный файл
        boolean isExisting = Files.exists(path);

        if (isExisting) {
            System.out.println("Заданный файл существует");

            // Проверить доступен ли заданный файл для чтения
            boolean isReadable = Files.isReadable(path);

            if (isReadable)
                System.out.println("Заданный файл доступен для чтения");
            else
                System.out.println("Заданный файл не доступен для чтения");

        } else {
            System.out.println("Заданный файл не существует");
        }
    }
}

Другой способ проверить существование и доступность файла

public static void main(String[] args) {
    File file = new File("data/source.txt");
    if (file.exists()) {
        System.out.println("Заданный файл существует");

        if (file.canRead())
            System.out.println("Заданный файл доступен для чтения");
        else
            System.out.println("Заданный файл не доступен для чтения");

    } else {
        System.out.println("Заданный файл не существует");
    }
}

Обработка исключительных ситуаций

Исключение — это ошибка, возникающая в процессе выполнения программы. Обрабатываемые исключения являются объектами подклассов класса Exception.

try {
    // Здесь может произойти исключительная ситуация
} catch (Exception e) {
    // Здесь можно обработать возникшее исключение 
} finally {
    // Здесь размещаются инструкции, которые будут выполнены в конце в любом случае 
}

При вводе выводе могут возникать следующие исключительные ситуации:

  • IOException — ошибка ввода-вывода.
  • FileNotFoundException — файл не найден.
  • ClassNotFoundException — класс не найден.

Закрытие ресурсов и try c ресурсами

Файловые потоки ввода-вывода следует закрывать с помощью метода close(). Вызов этого метода следует размещать в блоке finally, при этом потребуется обработчик исключительной ситуации IOException. Вместо использования метода close(), автозакрываемые потоки ввода-вывода можно создавать, как аргумент инструкции try c ресурсами.

Чтение файла

Чтение текста из файла с помощью символьного потока ввода с использованием try c ресурсами.

static void read() {
    File file = new File("data/source.txt");
    Path path = file.toPath();
    
    if (Files.exists(path) && Files.isReadable(path)) {
        try (BufferedReader reader = Files.newBufferedReader(path)) {
            String line;
            while ((line = reader.readLine()) != null)
                System.out.println(line);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Чтение текста из файла с помощью символьного потока ввода без использования try c ресурсами.

static void read() {
    File file = new File("data/source.txt");
    Path path = file.toPath();

    if (Files.exists(path) && Files.isReadable(path)) {
        BufferedReader reader = null;
        try {
            reader = Files.newBufferedReader(path);
            String line;
            while ((line = reader.readLine()) != null)
                System.out.println(line);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) 
                    reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Создание и запись файла

Запись текста в файл с помощью байтового потока вывода.

static void write() {
    // Данные для записи в файл
    String s = "Hello World!";
    byte data[] = s.getBytes();

    File file = new File("data/target.txt");
    Path path = file.toPath();
    try (OutputStream out = new BufferedOutputStream(
            Files.newOutputStream(path, CREATE, WRITE))) {
        out.write(data, 0, data.length);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Запись текста в файл с помощью символьного потока вывода.

static void write() {
    String path = "data/target.txt";
    String lines[] = {"Line 1", "Line 2", "Line 3"};

    try (FileWriter writer = new FileWriter(path)) {
        for (String line: lines)
            writer.write(line + System.lineSeparator());
    } catch (IOException e) {
        System.err.println(e);
    }
}

Сериализация и десериализация объектов

Сериализация — запись состояния объектов в последовательность байтов.
Десериализация — чтение состояния объектов из последовательности байтов.

Как правило при сериализации объекты записываются в файл, а при десериализации считываются из файла. Для того чтобы объекты класса могли быть сериализованы, класс должен реализовывать маркерный интерфейс Serializable. Для сериализации используется объектный поток ввода — ObjectOutputStream. Для десериализации используется объектный поток ввода вывода — ObjectInputStream.

import java.io.Serializable;

public class Person implements Serializable {
    private String firstName;
    private String lastName;
    private int age;

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "firstName = '" + firstName + ''' +
                ", lastName = '" + lastName + ''' +
                ", birthDate = " + age +
                '}';
    }
}

Сериализация:

static void serialize() {
    Person max = new Person("Max", "Planck", 21);
    Person isaac = new Person("Isaac", "Newton", 40);

    Person persons[] = {max, isaac};

    try (FileOutputStream fos = new FileOutputStream("data/objects")) {
        ObjectOutputStream out = new ObjectOutputStream(fos);
  
        for (Person person: persons)
            out.writeObject(person);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Десериализация:

static void deserialize() {
    String path = "data/objects";
    try (FileInputStream fis = new FileInputStream(path)) {
        ObjectInputStream in = new ObjectInputStream(fis);

        while (true) {
            try {
                Person person = (Person) in.readObject();
                System.out.println(person);
            } catch (EOFException e) {
                break;
            }
        }
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

Задание

Часть I

Найти заданную подстроку в выбранном текстовом файле.

Часть II

Извлечь все слова из заданного текстового файла и записать их в виде упорядоченного лексикографически списка (каждое слово с новой строки) в другой текстовый файл.

Часть III

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

Вопросы

  1. Байтовые потоки ввода-вывода
  2. Символьные потоки ввода-вывода
  3. Сериализация и десериализация
  4. Файлы, директории, пути
  5. Обработка исключительных ситуаций
  6. try с ресурсами

Ресурсы

  1. Г. Шилдт. Java Руководство для начинающих. Главы 9-10.

Доброго времени суток, мой виртуальный друг!
В прошлый раз мы рассмотрели байтовые потоки.
Но, к сожалению, люди пока не научились читать информацию в виде байтов, а до сих пор, по неизвестной причине, предпочитают информацию в текстовом виде. Странные они…
Поэтому, байты байтами, но работать приходится чаще всего именно с текстом.
К счастью, Java и тут нас не бросит, из коробки предоставляя такие средства работы с текстом, как символьные потоки. Рассмотрим же их поближе.

Символьные потоки ввода

Для работы с символьными потоками ввода существует класс java.io.Reader. Его методы:

/**
 * Метод читает символы и сохраняет их в символьном буфере target.
 *
 * @param target буфер для хранения символов
 * @return число сохраненных в буфере символов или -1, если символы в источнике закончились
 *
 * @throws IOException если произошла ошибка ввода-вывода
 * @throws NullPointerException если target равен null
 * @throws java.nio.ReadOnlyBufferException если target предназначен только для чтения
 */
public int read(CharBuffer target) throws IOException;
/**
 * Метод читает из потока код одного символа.
 *
 * @return     возвращает код одного символа в виде целого числа или -1,
 *             если символов больше нет во входном потоке
 *
 * @exception  IOException при возникновении ошибки ввода-вывода
 */
public int read() throws IOException;
/**
 * Метод читает символы и сохраняет их в массив.
 *
 * @param       cbuf массив, в котором будут сохранены символы
 *
 * @return      число прочитанных символов или -1, 
 *              если символов больше нет во входном потоке
 *
 * @exception   IOException при возникновении ошибки ввода-вывода
 */
public int read(char cbuf[]) throws IOException;
/**
 * Читает символы и сохраняет их в определенную область массива.
 *
 * @param      cbuf  массив, в котором будут сохранены символы
 * @param      off   позиция относительно начала массива, 
 *             в которую будут сохраняться прочитанные символы
 * @param      len   максимальное число символов, которые будут прочитаны
 *
 * @return     число прочитанных символов или -1, 
 *             если символов больше нет во входном потоке
 *
 * @exception  IOException  при возникновении ошибки ввода-вывода
 */
public int read(char cbuf[], int off, int len) throws IOException;
/**
 * Метод пропускает символы в потоке.
 *
 * @param  n  число символов, которое нужно пропустить
 *
 * @return    число реально пропущенных символов
 *
 * @exception  IllegalArgumentException  если n - отрицательное число
 * @exception  IOException  при возникновении ошибки ввода-вывода
 */
public long skip(long n) throws IOException;
/**
 * Готов ли поток к чтению данных.
 *
 * @return true если поток готов к чтению
 *
 * @exception  IOException при возникновении ошибки ввода-вывода
 */
public boolean ready() throws IOException;
/**
 * Метод для определения, поддерживает ли данный поток механизм меток. 
 *
 * @return true, если метки поддерживаются и false - если нет
 */
public boolean markSupported();
/**
 * Метод ставит метку на текущей позиции в потоке, 
 * чтобы иметь возможность потом к ней вернуться. 
 * Не все потоки поддерживают механизм меток.
 *
 * @param  readAheadLimit  максимальное количество символов,  
 *                         прочитанных после установки метки, 
 *                         чтобы метка оставалась актуальной.
 *                         Если будет прочитано большее количество символов - 
 *                         метка становится неактуальной
 *                         и метод reset завершится с ошибкой.
 *
 * @exception  IOException если механизм меток не поддерживается или 
 *                         в случае любой другой ошибки ввода-вывода
 */
public void mark(int readAheadLimit) throws IOException;
/**
 * Перемещает чтение потока в позицию, ранее помеченную меткой.
 *
 * @exception  IOException  Если метка не была установлена или
 *                          если метка стала неактуальной или,
 *                          если поток не поддерживает метод reset() или
 *                          при возникновении ошибки ввода-вывода
 */
public void reset() throws IOException;
/**
 * Закрывает поток.
 *
 * @exception  IOException при возникновении ошибки ввода-вывода
 */
public void close() throws IOException;

Как и в случае байтовых потоков, класс Reader — абстрактный класс, поэтому для создания конкретных потоков используются его подклассы. Наиболее популярные из них:


/**
 * Класс для чтения текста из файла.
 */
java.io.FileReader;
/**
 * Класс, превращающий входной поток байтов во входной поток символов.
 */
java.io.InputStreamReader;
/**
 * Класс, который добавляет возможность буферизации и чтения строками.
java.io.BufferedReader;

Символьные потоки вывода

Теперь познакомимся с символьными потоками вывода. Базовым классом для всех потоков вывода в Java является класс java.io.Writer. Его методы:

/**
 * Метод записывает в поток один символ.
 *
 * @param  c целочисленное представление символа
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(int c) throws IOException;
/**
 * Записывает массив символов в поток.
 *
 * @param  cbuf массив символов
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(char cbuf[]) throws IOException;
/**
 * Записывает область массива символов в поток.
 *
 * @param  cbuf массив символов
 * @param  off начало области массива, которую надо записать в поток
 * @param  len количество символов, которые надо записать в поток
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(char cbuf[], int off, int len) throws IOException;
/**
 * Записывает строку в поток.
 *
 * @param  str строка
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(String str) throws IOException;
/**
 * Записывает часть строки в поток
 *
 * @param  str строка
 * @param  off индекс первого символа подстроки, которую надо записать
 * @param  len число символов, которые надо записать
 *
 * @throws  IndexOutOfBoundsException если off < 0 или 
                                      len < 0 или off + len < 0 или 
                                      off + len > str.length()
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(String str, int off, int len) throws IOException;
/**
 * Дописывает символьную последовательность в поток.
 *
 * @param  csq символьная последовательность
 *
 * @return  текущий объект Writer
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public Writer append(CharSequence csq) throws IOException;
/**
 * Дописывает в поток часть символьной последовательности.
 *
 * @param  csq символьная последовательность, часть которой нужно дописать в поток
 *
 * @param  start индекс первого символа, который нужно записать в поток
 * @param  end индекс последнего символа, который нужно записать в поток
 *
 * @return  текущий объект Writer
 *
 * @throws  IndexOutOfBoundsException если start - отрицательное число или 
 *                                    end отрицательное число или 
 *                                    start > end или 
 *                                    end > csq.length()
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public Writer append(CharSequence csq, int start, int end) throws IOException;
/**
 * Дописывает в поток один символ.
 *
 * @param  c символ, который нужно дописать в поток
 *
 * @return  текущий объект Writer
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 *
 */
public Writer append(char c) throws IOException;
/**
 * Метод записывает всю информацию из буфера в приемник.
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void flush() throws IOException;
/**
 * Закрывает поток, предварительно записав в приемник всю информацию из буфера.
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void close() throws IOException;

Чаще всего используются следующие подклассы класса Writer:


/**
 * Класс, для записи текста в файл.
 */
java.io.FileWriter;
/**
 * Класс, который добавляет буферизацию при записи информации в поток.
 */
java.io.BufferedWriter;
/**
 * Класс, который предоставляет множество методов для удобной записи различной информации в поток.
 */
java.io.PrintWriter;

Особая роль PrintStream

В пакете java.io есть удивительный класс PrintStream, который является наследником OutputStream, но, при этом, имеет множество методов записи текста в поток. Если сравнить класс PrintWriter и PrintStream, можно заметить, что методы для записи чисел, символов и т.п. — просто совпадают. 

Зачем же наследовать от класса OutputStream, отвечающего за байтовый вывод, класс, который отвечает за символьный вывод?

Ответ на самом деле довольно прост. Класс PrintStream был добавлен в Java в версии 1.0, а класс Writer — в версии 1.1. То есть на момент добавления PrintStream базовых классов, отвечающих за символьный ввод и вывод просто не существовало. 

Но существует и более интересная причина такой долгой жизни класса PrintStream и она связана с так называемыми стандартными потоками.

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

Стандартные потоки — это потоки данных, которые всегда открываются при запуске процесса в операционной системе. Таких потоков обычно три:

  1. Стандартный поток ввода — stdin — предназначен для чтения команд пользователя. По умолчанию связан с устройством ввода текстовой информации — клавиатурой;
  2. Стандартный поток вывода — stdout — предназначен для отображения текстовой информации пользователю. По умолчанию связан с устройством вывода текстовой информации — монитором;
  3. Стандартный поток вывода ошибок — stderr — предназначен для вывода ошибок и диагностической информации. Обычно связан с тем же устройством, что и stdout, но, в отличии от stdout, вывод в stderr не буферизируется.

Java по умолчанию всегда автоматически инициализирует и открывает стандартные потоки:

  1. Стандартный поток ввода — System.in — объект класса InputStream;
  2. Стандартный поток вывода — System.out — объект класса PrintStream;
  3. Стандартный поток вывода ошибок — System.err — объект класса PrintStream;

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

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

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

Утилитный класс Scanner

Для того, чтобы сделать чтение текста удобнее в Java 1.5 в пакет java.util был добавлен класс Scanner. Он имеет множество удобных методов для чтения не только текста, но и чисел, логических констант и многого другого.

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

import java.util.Scanner;

public class IntSum {
    public static void main(String[] args) {
        //Используем Scanner для чтения информации введенной пользователем через консоль
        //В данном случае закрывать scanner не нужно, так как он
        //связан со стандартным потоком ввода System.in, которым управляет сама Java
        Scanner scanner = new Scanner(System.in);
        System.out.println("Введите целое число: ");
        //Читаем первое число. Если пользователь введет не число - возникнет ошибка
        int value = scanner.nextInt();

        System.out.println("Введите еще одно целое число: ");
        //Читаем второе число. Если пользователь введет не число - возникнет ошибка
        int value2 = scanner.nextInt();

        int result = value + value2;
        //Выводим результат в консоль, используя метод printf, 
        //который умеет распознавать шаблоны (%d, %s и т.п.) и заменять их числами, строками и т.п.
        System.out.printf("Сумма чисел %d и %d равна %d", value, value2, result);
    }
}

Теперь, когда мы основательно изучили теорию — рассмотрим несколько примеров.

Пример 1 — из консоли в файл

Пусть мы хотим всю информацию, введенную пользователем в консоль — сохранять в файл. 

Главное, о чем нужно помнить при работе с текстом — это кодировка символов. В этой программе — мы читаем и пишем в кодировке UTF-8:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Scanner;

public class LogMe {
    public static void main(String[] args) throws IOException {
        //Файл, куда будем писать все введенное с клавиатуры
        File file = new File("D:/log.txt");

        //Используем Scanner для чтения того, что введет пользователь
        //В данном случае закрывать scanner не нужно, так как он
        //связан со стандартным потоком ввода System.in, которым управляет сама Java
        Scanner scanner = new Scanner(System.in, "UTF-8");
        //Используем PrintWriter для того, чтобы писать в файл
        try(PrintWriter writer = new PrintWriter(
                new OutputStreamWriter(
                        new FileOutputStream(file), "UTF-8"))) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if(line != null) {
                    //Если пользователь ввел exit - завершаем программу
                    if("exit".equals(line)) {
                        return;
                    }

                    //Пишем в файл то, что ввел пользователь
                    writer.println(line);
                }
            }
        }
    }
}

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

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Scanner;

public class LogMe {
    public static void main(String[] args) throws IOException {
        //Файл, куда будем писать все введенное с клавиатуры
        File file = new File("D:/log.txt");

        //Используем Scanner для чтения того, что введет пользователь.
        //В данном случае закрывать scanner не нужно, так как он
        //связан со стандартным потоком ввода System.in, которым управляет сама Java
        Scanner scanner = new Scanner(System.in, "UTF-8");
        //Используем PrintWriter для того, чтобы писать в файл
        try(PrintWriter writer = new PrintWriter(
                new OutputStreamWriter(
                        //Второй параметр true - значит не перезаписываем содержимое файла, 
                        //а дописываем в него
                        new FileOutputStream(file, true), "UTF-8"))) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if(line != null) {
                    //Если пользователь ввел exit - завершаем программу
                    if("exit".equals(line)) {
                        return;
                    }

                    //Пишем в файл то, что ввел пользователь
                    writer.println(line);
                }
            }
        }
    }
}

Пример 2 — из файла в консоль

Рассмотрим обратную задачу — прочитаем содержимое файла и выведем его в консоль:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class FileToConsole {
    public static void main(String[] args) throws FileNotFoundException {
        //Файл, содержимое которого мы будем читать
        File file = new File("D:/1.txt");

        //Используем Scanner, чтобы построчно читать содержимое файла в кодировке UTF-8
        //В данном случае - обязательно закрыть за собой поток, так как мы сами его и открыли
        try(Scanner scanner = new Scanner(file, "UTF-8")) {
            //Читаем файл построчно до тех пор, пока есть строки
            while (scanner.hasNextLine()) {
                //Читаем очередную строку из файла
                String line = scanner.nextLine();
                if(line != null) {
                    //Распечатываем строку из файла
                    System.out.println(line);
                }
            }
        }
    }
}

Вместо заключения

Думаете это все? О, нет, конечно не все! Нас впереди ждет еще одна очень увлекательная тема — непотоковая работа с данными. 

Символьные потоки ввода

Для работы с символьными потоками ввода существует класс java.io.Reader. Его методы:

/**
 * Метод читает символы и сохраняет их в символьном буфере target.
 *
 * @param target буфер для хранения символов
 * @return число сохраненных в буфере символов или -1, если символы в источнике закончились
 *
 * @throws IOException если произошла ошибка ввода-вывода
 * @throws NullPointerException если target равен null
 * @throws java.nio.ReadOnlyBufferException если target предназначен только для чтения
 */
public int read(CharBuffer target) throws IOException;
/**
 * Метод читает из потока код одного символа.
 *
 * @return     возвращает код одного символа в виде целого числа или -1,
 *             если символов больше нет во входном потоке
 *
 * @exception  IOException при возникновении ошибки ввода-вывода
 */
public int read() throws IOException;
/**
 * Метод читает символы и сохраняет их в массив.
 *
 * @param       cbuf массив, в котором будут сохранены символы
 *
 * @return      число прочитанных символов или -1, 
 *              если символов больше нет во входном потоке
 *
 * @exception   IOException при возникновении ошибки ввода-вывода
 */
public int read(char cbuf[]) throws IOException;
/**
 * Читает символы и сохраняет их в определенную область массива.
 *
 * @param      cbuf  массив, в котором будут сохранены символы
 * @param      off   позиция относительно начала массива, 
 *             в которую будут сохраняться прочитанные символы
 * @param      len   максимальное число символов, которые будут прочитаны
 *
 * @return     число прочитанных символов или -1, 
 *             если символов больше нет во входном потоке
 *
 * @exception  IOException  при возникновении ошибки ввода-вывода
 */
public int read(char cbuf[], int off, int len) throws IOException;
/**
 * Метод пропускает символы в потоке.
 *
 * @param  n  число символов, которое нужно пропустить
 *
 * @return    число реально пропущенных символов
 *
 * @exception  IllegalArgumentException  если n - отрицательное число
 * @exception  IOException  при возникновении ошибки ввода-вывода
 */
public long skip(long n) throws IOException;
/**
 * Готов ли поток к чтению данных.
 *
 * @return true если поток готов к чтению
 *
 * @exception  IOException при возникновении ошибки ввода-вывода
 */
public boolean ready() throws IOException;
/**
 * Метод для определения, поддерживает ли данный поток механизм меток. 
 *
 * @return true, если метки поддерживаются и false - если нет
 */
public boolean markSupported();
/**
 * Метод ставит метку на текущей позиции в потоке, 
 * чтобы иметь возможность потом к ней вернуться. 
 * Не все потоки поддерживают механизм меток.
 *
 * @param  readAheadLimit  максимальное количество символов,  
 *                         прочитанных после установки метки, 
 *                         чтобы метка оставалась актуальной.
 *                         Если будет прочитано большее количество символов - 
 *                         метка становится неактуальной
 *                         и метод reset завершится с ошибкой.
 *
 * @exception  IOException если механизм меток не поддерживается или 
 *                         в случае любой другой ошибки ввода-вывода
 */
public void mark(int readAheadLimit) throws IOException;
/**
 * Перемещает чтение потока в позицию, ранее помеченную меткой.
 *
 * @exception  IOException  Если метка не была установлена или
 *                          если метка стала неактуальной или,
 *                          если поток не поддерживает метод reset() или
 *                          при возникновении ошибки ввода-вывода
 */
public void reset() throws IOException;
/**
 * Закрывает поток.
 *
 * @exception  IOException при возникновении ошибки ввода-вывода
 */
public void close() throws IOException;

Как и в случае байтовых потоков, класс Reader — абстрактный класс, поэтому для создания конкретных потоков используются его подклассы. Наиболее популярные из них:


/**
 * Класс для чтения текста из файла.
 */
java.io.FileReader;
/**
 * Класс, превращающий входной поток байтов во входной поток символов.
 */
java.io.InputStreamReader;
/**
 * Класс, который добавляет возможность буферизации и чтения строками.
java.io.BufferedReader;

Символьные потоки вывода

Теперь познакомимся с символьными потоками вывода. Базовым классом для всех потоков вывода в Java является класс java.io.Writer. Его методы:

/**
 * Метод записывает в поток один символ.
 *
 * @param  c целочисленное представление символа
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(int c) throws IOException;
/**
 * Записывает массив символов в поток.
 *
 * @param  cbuf массив символов
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(char cbuf[]) throws IOException;
/**
 * Записывает область массива символов в поток.
 *
 * @param  cbuf массив символов
 * @param  off начало области массива, которую надо записать в поток
 * @param  len количество символов, которые надо записать в поток
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(char cbuf[], int off, int len) throws IOException;
/**
 * Записывает строку в поток.
 *
 * @param  str строка
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(String str) throws IOException;
/**
 * Записывает часть строки в поток
 *
 * @param  str строка
 * @param  off индекс первого символа подстроки, которую надо записать
 * @param  len число символов, которые надо записать
 *
 * @throws  IndexOutOfBoundsException если off < 0 или 
                                      len < 0 или off + len < 0 или 
                                      off + len > str.length()
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void write(String str, int off, int len) throws IOException;
/**
 * Дописывает символьную последовательность в поток.
 *
 * @param  csq символьная последовательность
 *
 * @return  текущий объект Writer
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public Writer append(CharSequence csq) throws IOException;
/**
 * Дописывает в поток часть символьной последовательности.
 *
 * @param  csq символьная последовательность, часть которой нужно дописать в поток
 *
 * @param  start индекс первого символа, который нужно записать в поток
 * @param  end индекс последнего символа, который нужно записать в поток
 *
 * @return  текущий объект Writer
 *
 * @throws  IndexOutOfBoundsException если start - отрицательное число или 
 *                                    end отрицательное число или 
 *                                    start > end или 
 *                                    end > csq.length()
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public Writer append(CharSequence csq, int start, int end) throws IOException;
/**
 * Дописывает в поток один символ.
 *
 * @param  c символ, который нужно дописать в поток
 *
 * @return  текущий объект Writer
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 *
 */
public Writer append(char c) throws IOException;
/**
 * Метод записывает всю информацию из буфера в приемник.
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void flush() throws IOException;
/**
 * Закрывает поток, предварительно записав в приемник всю информацию из буфера.
 *
 * @throws  IOException при возникновении ошибки ввода-вывода
 */
public void close() throws IOException;

Чаще всего используются следующие подклассы класса Writer:


/**
 * Класс, для записи текста в файл.
 */
java.io.FileWriter;
/**
 * Класс, который добавляет буферизацию при записи информации в поток.
 */
java.io.BufferedWriter;
/**
 * Класс, который предоставляет множество методов для удобной записи различной информации в поток.
 */
java.io.PrintWriter;

Особая роль PrintStream

В пакете java.io есть удивительный класс PrintStream, который является наследником OutputStream, но, при этом, имеет множество методов записи текста в поток. Если сравнить класс PrintWriter и PrintStream, можно заметить, что методы для записи чисел, символов и т.п. — просто совпадают. 

Зачем же наследовать от класса OutputStream, отвечающего за байтовый вывод, класс, который отвечает за символьный вывод?

Ответ на самом деле довольно прост. Класс PrintStream был добавлен в Java в версии 1.0, а класс Writer — в версии 1.1. То есть на момент добавления PrintStream базовых классов, отвечающих за символьный ввод и вывод просто не существовало. 

Но существует и более интересная причина такой долгой жизни класса PrintStream и она связана с так называемыми стандартными потоками.

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

Стандартные потоки — это потоки данных, которые всегда открываются при запуске процесса в операционной системе. Таких потоков обычно три:

  1. Стандартный поток ввода — stdin — предназначен для чтения команд пользователя. По умолчанию связан с устройством ввода текстовой информации — клавиатурой;
  2. Стандартный поток вывода — stdout — предназначен для отображения текстовой информации пользователю. По умолчанию связан с устройством вывода текстовой информации — монитором;
  3. Стандартный поток вывода ошибок — stderr — предназначен для вывода ошибок и диагностической информации. Обычно связан с тем же устройством, что и stdout, но, в отличии от stdout, вывод в stderr не буферизируется.

Java по умолчанию всегда автоматически инициализирует и открывает стандартные потоки:

  1. Стандартный поток ввода — System.in — объект класса InputStream;
  2. Стандартный поток вывода — System.out — объект класса PrintStream;
  3. Стандартный поток вывода ошибок — System.err — объект класса PrintStream;

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

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

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

Утилитный класс Scanner

Для того, чтобы сделать чтение текста удобнее в Java 1.5 в пакет java.util был добавлен класс Scanner. Он имеет множество удобных методов для чтения не только текста, но и чисел, логических констант и многого другого.

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

import java.util.Scanner;

public class IntSum {
    public static void main(String[] args) {
        //Используем Scanner для чтения информации введенной пользователем через консоль
        //В данном случае закрывать scanner не нужно, так как он
        //связан со стандартным потоком ввода System.in, которым управляет сама Java
        Scanner scanner = new Scanner(System.in);
        System.out.println("Введите целое число: ");
        //Читаем первое число. Если пользователь введет не число - возникнет ошибка
        int value = scanner.nextInt();

        System.out.println("Введите еще одно целое число: ");
        //Читаем второе число. Если пользователь введет не число - возникнет ошибка
        int value2 = scanner.nextInt();

        int result = value + value2;
        //Выводим результат в консоль, используя метод printf, 
        //который умеет распознавать шаблоны (%d, %s и т.п.) и заменять их числами, строками и т.п.
        System.out.printf("Сумма чисел %d и %d равна %d", value, value2, result);
    }
}

Теперь, когда мы основательно изучили теорию — рассмотрим несколько примеров.

Пример 1 — из консоли в файл

Пусть мы хотим всю информацию, введенную пользователем в консоль — сохранять в файл. 

Главное, о чем нужно помнить при работе с текстом — это кодировка символов. В этой программе — мы читаем и пишем в кодировке UTF-8:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Scanner;

public class LogMe {
    public static void main(String[] args) throws IOException {
        //Файл, куда будем писать все введенное с клавиатуры
        File file = new File("D:/log.txt");

        //Используем Scanner для чтения того, что введет пользователь
        //В данном случае закрывать scanner не нужно, так как он
        //связан со стандартным потоком ввода System.in, которым управляет сама Java
        Scanner scanner = new Scanner(System.in, "UTF-8");
        //Используем PrintWriter для того, чтобы писать в файл
        try(PrintWriter writer = new PrintWriter(
                new OutputStreamWriter(
                        new FileOutputStream(file), "UTF-8"))) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if(line != null) {
                    //Если пользователь ввел exit - завершаем программу
                    if("exit".equals(line)) {
                        return;
                    }

                    //Пишем в файл то, что ввел пользователь
                    writer.println(line);
                }
            }
        }
    }
}

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

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Scanner;

public class LogMe {
    public static void main(String[] args) throws IOException {
        //Файл, куда будем писать все введенное с клавиатуры
        File file = new File("D:/log.txt");

        //Используем Scanner для чтения того, что введет пользователь.
        //В данном случае закрывать scanner не нужно, так как он
        //связан со стандартным потоком ввода System.in, которым управляет сама Java
        Scanner scanner = new Scanner(System.in, "UTF-8");
        //Используем PrintWriter для того, чтобы писать в файл
        try(PrintWriter writer = new PrintWriter(
                new OutputStreamWriter(
                        //Второй параметр true - значит не перезаписываем содержимое файла, 
                        //а дописываем в него
                        new FileOutputStream(file, true), "UTF-8"))) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                if(line != null) {
                    //Если пользователь ввел exit - завершаем программу
                    if("exit".equals(line)) {
                        return;
                    }

                    //Пишем в файл то, что ввел пользователь
                    writer.println(line);
                }
            }
        }
    }
}

Пример 2 — из файла в консоль

Рассмотрим обратную задачу — прочитаем содержимое файла и выведем его в консоль:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class FileToConsole {
    public static void main(String[] args) throws FileNotFoundException {
        //Файл, содержимое которого мы будем читать
        File file = new File("D:/1.txt");

        //Используем Scanner, чтобы построчно читать содержимое файла в кодировке UTF-8
        //В данном случае - обязательно закрыть за собой поток, так как мы сами его и открыли
        try(Scanner scanner = new Scanner(file, "UTF-8")) {
            //Читаем файл построчно до тех пор, пока есть строки
            while (scanner.hasNextLine()) {
                //Читаем очередную строку из файла
                String line = scanner.nextLine();
                if(line != null) {
                    //Распечатываем строку из файла
                    System.out.println(line);
                }
            }
        }
    }
}

Вместо заключения

Думаете это все? О, нет, конечно не все! Нас впереди ждет еще одна очень увлекательная тема — непотоковая работа с данными. 

проблема с сотовым телефоном Samsung SGH-U600

Сотовый телефон Samsung SGH-U600

При попытке установить Opera mini выбивает сообщение:»Ошибка Java.Исключение ввода-вывода»..Как это можно устранить?

Люди с такой же проблемой (11)

не могу установить игру пишет ошибка джава исключение ввода вывода чо делать- тороплюсь поэтому с ошибками и без знаков препинания  бысуне  14 декабря 2017 

На GT-C3011 пытаюсь установить игру <<Мой щенок>>. Открываю файл нажимаю [Установить] и выскакивает ошибка java исключение ввода-вывода. Что делать?  Afanasev  21 января 2013 

у меня тоже самое… ни игры, ни проги не устанавливаются  алёнкая  26 декабря 2010 

Знаете, как решить эту проблему?
Поделитесь своим знанием!

Ваш способ решения:

Наиболее похожие проблемы из этого раздела

Не могу установить официальную оперу мини на нокию 311. Захожу на сайт m.opera.com нажимаю скачать, оно выбивает »Загрузка» и ничего дальше. Я уже …

Как поставить более свежую оперу мини на телефон самсунг GT-C3300i. А то скачал 6.5 оперу а он мне пишет ошибка Java. Очень срочно надо!

загружаю оперу мини в там пишут ошибка сети проверьте подключение сети проверяла
у меня телеФон samsung GT-3300 кстати на ж
этот телеФон есть …

Пропал Вацап. При попытке установить Вацап снова выдается сообщение «память полная». Что можно сделать?

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

Welemir1, код просто так никому не даю, меня нету ни в каких гитхабах и т.п. модных сайтах, поэтому считайте, что я новичок-середнячок в программировании. Так спокойнее будет и для меня и для вас. )

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

Добавлено через 2 минуты
Welemir1, я видел много проектов, в которых по 60-100кб кода, а потом сам пробовал делать и получалось, что элегантный код весит не более 5кб. Вот такая магия происходит, если уметь упрощать код и делать его читаемым. Это очень трудно, но поверьте, игра стоит свечь.

Понравилась статья? Поделить с друзьями:
  • Ошибка java net connectexception connection timed out no further
  • Ошибка java net connectexception connection refused connect
  • Ошибка java lang runtimeexception java lang nullpointerexception
  • Ошибка java lang nullpointerexception в программе
  • Ошибка java lang illegalargumentexception как исправить