Читаем и пишем в файл human javarush
В этом уроке мы будем читать и записывать файлы на Java с помощью FileReader, FileWriter, BufferedReader, BufferedWriter, FileInputStream, FileOutputStream и т. Д.
Вступление
В этой статье мы погрузимся в Чтение и запись файлов на Java .
При программировании, независимо от того, создаете ли вы мобильное приложение, веб-приложение или просто пишете сценарии, вам часто приходится читать или записывать данные в файл. Эти данные могут быть данными кэша, данными, которые вы получили для набора данных, изображения или практически всем, что вы можете придумать.
В этом уроке мы покажем наиболее распространенные способы чтения и записи файлов на Java.
Java предоставляет несколько API (также известных как Java I/O ) для чтения и записи файлов с момента ее первых выпусков. В последующих выпусках ввод-вывод Java был улучшен, упрощен и расширен для поддержки новых функций.
Прежде чем мы перейдем к некоторым реальным примерам, это поможет понять доступные вам классы, которые будут обрабатывать чтение и запись данных в файлы. В следующих разделах мы дадим краткий обзор классов ввода-вывода Java и объясним, что они делают, затем мы рассмотрим потоки Java NIO и, наконец, покажем некоторые примеры чтения и записи данных в файлы.
Потоки Java NIO
Java NIO -это неблокирующий API ввода-вывода, который был представлен еще в Java 4 и может быть найден в пакете/| java.nio . С точки зрения производительности это большое улучшение API для операций ввода-вывода.
Буферы, селекторы и каналы являются тремя основными компонентами Java NIO, хотя в этой статье мы сосредоточимся исключительно на использовании классов NIO для взаимодействия с файлами, а не обязательно на концепциях, лежащих в основе API.
Поскольку этот учебник посвящен чтению и записи файлов, в этом коротком разделе мы обсудим только связанные классы:
-
: Это иерархическая структура фактического расположения файла и обычно используется для поиска файла, с которым вы хотите взаимодействовать. : Это класс, который предоставляет несколько служебных методов для создания Пути из заданного URI строки. : Это еще один служебный класс, который имеет несколько методов для чтения и записи файлов, не блокируя выполнение в потоках.
Используя эти несколько классов, вы можете легко взаимодействовать с файлами более эффективным способом.
Потоки ввода-вывода
Существует два типа потоков, которые вы можете использовать для взаимодействия с файлами:
Для каждого из вышеперечисленных типов потоков существует несколько вспомогательных классов, поставляемых с Java, которые мы кратко рассмотрим ниже.
Потоки символов
Потоки символов используются для чтения или записи типа данных символов. Давайте рассмотрим наиболее часто используемые классы. Все эти классы определены в разделе java.io посылка.
Вот некоторые классы, которые вы должны знать, которые можно использовать для чтения символьных данных:
-
: Абстрактный класс для чтения потока символов. : Класс, используемый для чтения потока байтов и преобразования в поток символов. : Класс для чтения символов из файла. : Это оболочка над классом Reader , которая поддерживает возможности буферизации. Во многих случаях это наиболее предпочтительный класс для чтения данных, поскольку из файла можно прочитать больше данных за один вызов read () , что уменьшает количество фактических операций ввода-вывода с файловой системой.
И вот некоторые классы, которые вы можете использовать для записи символьных данных в файл:
-
: Это абстрактный класс для записи потоков символов. : Этот класс используется для записи потоков символов, а также для преобразования их в потоки байтов. : Класс для фактической записи символов в файл. : Это оболочка над классом Writer , которая также поддерживает возможности буферизации. Это наиболее предпочтительный класс для записи данных в файл, так как в файл может быть записано больше данных за один вызов write () . И , как и BufferedReader , это уменьшает общее количество операций ввода-вывода с файловой системой.
Потоки байтов
Потоки байтов используются для чтения или записи байтовых данных с файлами. Это отличается от того, как они обрабатывали данные раньше. Здесь вы работаете с необработанными байтами, которые могут быть символами, данными изображений, данными в юникоде (для представления символа требуется 2 байта) и т. Д.
В этом разделе мы рассмотрим наиболее часто используемые классы. Все эти классы определены в разделе java.io посылка.
Вот классы, используемые для чтения байтовых данных:
-
: Абстрактный класс для чтения потоков байтов. : Класс для простого считывания байтов из файла. : Это оболочка над InputStream , которая поддерживает возможности буферизации. Как мы видели в потоках символов, это более эффективный метод, чем FileInputStream .
А вот классы, используемые для записи байтовых данных:
-
: Абстрактный класс для записи байтовых потоков. : Класс для записи необработанных байтов в файл. : Этот класс является оболочкой над OutputStream для поддержки возможностей буферизации. И опять же, как мы видели в потоках символов, это более эффективный метод, чем FileOutputStream благодаря буферизации.
Примеры чтения и записи текстовых файлов
В предыдущих разделах мы обсуждали различные API, предоставляемые Java, и теперь пришло время использовать эти классы API в некотором коде.
Приведенный ниже пример кода обрабатывает чтение и запись текстовых файлов с использованием различных классов, которые мы подробно описали выше. Чтобы упростить вещи и обеспечить лучшее сравнение используемых фактических методов, входные и выходные данные будут оставаться одинаковыми между примерами.
3. Решение - сериализация, ISerializable
- Помнишь, мы сегодня разбирали сохранение объектов в файл и чтение из файла?
- Да, только мы сохраняли в поток вывода, а читали из потока ввода.
- Молодец, Амиго. Приятно слышать, что ты замечаешь такие мелочи. А ты бы смог дописать код, чтобы было сохранение в файл и чтение из файла?
- А что там писать?! Объявил FileInputStream и FileOutputStream и передавай их в методы save & load. Тут уже ничего не перепутаешь - все просто.
- Рада за тебя. Итак, новая тема – сериализация .
Сериализация – это практически то же самое, что мы с тобой только что делали, только гораздо круче и встроено прямо в Java-машину. Java-машина умеет сохранять и загружать свои объекты. Для этого ей даже не требуются методы save & load: все объекты хранятся внутри Java-машины, и она имеет к ним полный доступ.
Мы просто берем объект и сохраняем его в поток/читаем из потока:
//save cat to file
FileOutputStream fileOutput = new FileOutputStream("cat.dat");
ObjectOutputStream outputStream = new ObjectOutputStream ( fileOutput );
outputStream.writeObject ( cat );
fileOutput.close();
outputStream.close();
//load cat from file
FileInputStream fiStream = new FileInputStream("cat.dat");
ObjectInputStream objectStream = new ObjectInputStream ( fiStream );
Object object = objectStream.readObject();
fiStream.close();
objectStream.close();
- Да. Там очень большой и сложный механизм сериализации, который поддерживает сохранение в поток и чтение из потока почти всех типов данных.
- Почти всех, это значит не всех?
- Да, дело в том, что не все объекты по своей сути можно сохранить . Некоторые объекты не хранят все свои данные в себе, а лишь ссылаются на другие объекты и/или источники данных. Например, консоль (System.in), поток ввода (InputStream), или что-нибудь еще.
Поэтому разработчики Java придумали специальный интерфейс-маркер – Serializable . Его называют маркером, т.к. он не содержит никаких данных и методов. Он используется только для того, чтобы «помечать» (маркировать) классы. Если мы считаем, что наш класс хранит в себе все свои данные, тогда мы можем пометить его этим маркером – написать implements Serializable.
Пример «кота» с поддержкой сериализации:
Код |
---|
class Cat implements Serializable public String name; public int age; public int weight; > |
Когда мы пытаемся сериализовать (сохранить) какой-нибудь объект, Java-машина проверяет – поддерживает ли он сериализацию: реализует ли он интерфейс Serializable? Если да, то сохраняет объект, если нет – выкидывает исключение о невозможности сериализации.
Тут нужно понимать, что сериализуемый объект должен состоять тоже только из сериализуемых объектов.
- Ну, этого и следовало ожидать. Нельзя же сохранить целое, не сохранив какие-то его части.
- А как же типы int, String, ArrayList?
- Они все поддерживают сериализацию, на этот счет разработчики Java специально позаботились. Тут проблем быть не должно.
Более того, при сериализации объекта сохраняется его тип. Теперь ты можешь в переменную класса с типом Object сохранить ссылку на объект Cat, и все это отлично сериализуется и десериализуется.
- Десериализация – так называют процесс, обратный сериализации – чтение и восстановление объекта из потока/файла.
Привет всем! Мне после моего поста тут регулярно пишут люди с вопросом, стоит ли подписываться на JavaRush, и что вообще учить по Java. Поэтому ответив уже наверное сотне людей в личке, решил написать тут для всех сразу свое мнение, кому это вдруг интересно. По моим ощущениям - все зависит от целей: если хочешь не особо напрягаться при обучении и через год уметь неплохо решать простейшие задачи на Java, а через два - более-менее нормально разрабатывать, то стоит, а если хочешь максимально эффективно научиться разрабатывать, несмотря на то что придется пахать - определенно не стоит. Потратишь год времени на решение их задач, и все еще не сможешь написать ни одной мало-мальски нормальной программы и не будешь разбираться в необходимых при разработке инструментах. Лучше, опять же имхо, посмотреть, допустим, все видосы YouTube-канала, который я указал выше, а после этого просто прочитать несколько книг (для полноты информации) на это уйдет тот же год или около того, но этого уже будет достаточно, чтобы заниматься разработкой на Java по полной (самому или мидлом в какой-то конторе, неважно). Только самое главное не просто смотреть видео или листать книжки по интересующим тебя главам, а именно разобраться в материале, т.е. прочил главу -> разобрался(погуглил, если надо) -> все законспектировал у себя в тетради или на ноуте(впоследствии будет очень удобно иметь конспект) -> перевел полученные знания в код (в иделе со временем писать проект, который кому-то интересен, хотя бы тебе самому) -> только после этого читаешь \ смотришь дальше. Вот тогда будет быстрый и эффективный прогресс. Это в разы сложнее, чем решать JavaRush, но и в разы эффективнее. JavaRush дает очень удобно и очень растянуто по времени базовое знание, но это 5% того, что придется изучить и понять программисту и тратить на это год жалко.. Вот примерный стек того, что стоит знать серьезному программисту на Java (написал в том порядке, в котором это все надо изучать, а теперь прикиньте сами сколько из этого есть в курсе JavaRush):
2. Java Patterns:
1) OOP Patterns (Main paradigms, SOLID principles, UML)
2) GoF-patterns
3) GRASP-patterns
4) Antipatterns
5) Enterprise Architecture Patterns
6) Enterprise Integration Architecture Patterns
7) Development Design (TestDD, TypeDD, BDD, DDD, FDD, MDD, PDD)
3. Java GUI's (AWT, Swing, JavaFX, SWT, GWT, Vaadin, ZK)
4. Data Bases:
1) SQL
2) JDBC
3) ORM (JPA, Hibernate, HQL, JPQL, JTA, iBatis, Mapstruct)
4) RDBMS (PostgreSQL, MySQL, Oracle, MS SQL Server, H2)
5) Distributed DB (Hadoop, Splunk, Spark)
6) In-memory DB (VoltDB, MemSQL)
7) NoSQL DB (MongoDB, Neo4j, Cassandra, Apache Ignite, Tarantool)
8) DB Migration (Liquibase, Flyway, Flocker, JOOQ)
9) Cache Systems (Memcache, Redisson, Kryo, EhCache)
JavaRush
версия: 1.0.59
Последнее обновление программы в шапке: 25.02.2022
Краткое описание:
Обучение программированию на Java онлайн
Обучение программированию на Java с нуля в формате игры-квеста от разработчиков JavaRush. Курс содержит 1200 практических задач и 600 мини-лекций.
Мечтаете стать разработчиком, но нет времени на оффлайн-курсы? Не проблема. Теперь вы можете уделять своему обучению столько времени, сколько возможно, и учиться где угодно. Даже полчаса достаточно, чтобы прочесть 1-2 лекции и решить несколько задач :)
Наш курс по Java построен в формате игры, которая состоит из 4 квестов. В каждом квесте — 10 уровней с лекциями и задачами. Представьте, что вы играете в обычную игру и “прокачиваете” своего персонажа, а заодно учитесь программировать!
Писать десятки строк кода с телефона — непростая задача. Поэтому мы разработали систему подсказок и автоподстановок, с которой вы сможете программировать быстрее. После того, как вы напишете свое решение, отправляйте его на проверку и моментально получайте результат.
В приложении есть задачи по Java на любой уровень сложности:
- Написание своего кода;
- Исправление готового кода;
- Прикладные мини-проекты и написание игр.
Если возникли трудности в решении задачи, обращайтесь в раздел помощь: там вам помогут студенты и разработчики курса.
Ваш прогресс сохраняется, так что вы сможете вернуться к обучению в любую минуту, чтобы продолжить решение задачи или прочесть лекцию.
2. Задача на сохранение массива объектов в файл
Git Essentials
Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!
Примечание : Чтобы избежать путаницы в пути к файлу, пример кода будет считываться и записываться из файла в домашнем каталоге пользователя. Домашний каталог пользователя можно найти с помощью System.getProperty("user.home"); , который мы используем в наших примерах.
Чтение и запись с помощью программы чтения файлов и пишущей машинки
Давайте начнем с использования классов FileReader и Пишущая машинка :
Оба класса принимают строку, представляющую путь к файлу в их конструкторах. Вы также можете передать Файл объект, а также Файловый дескриптор .
Метод write() записывает допустимую последовательность символов – либо Строку , либо символ[] . Кроме того, он может записать один символ , представленный как int .
Метод read() считывает и возвращает символ за символом, позволяя нам, например, использовать считанные данные в цикле while .
Не забудьте закрыть оба этих класса после использования!
Чтение и запись с помощью BufferedReader и BufferedWriter
Использование BufferedReader и BufferedWriter классов:
Чтение и запись с помощью FileInputStream и FileOutputStream
Использование FileInputStream и FileOutputStream классов:
Чтение и запись с помощью BufferedInputStream и BufferedOutputStream
Использование BufferedInputStream и BufferedOutputStream классов:
Чтение и запись с помощью классов Java.nio
Использование классов java.nio :
Другой способ извлечения содержимого через класс Files , что более важно, если вы не читаете текстовые данные, – это использовать метод ReadAllBytes для чтения данных в массив байтов:
В случае , если вы заинтересованы в использовании потоков с java.nio , вы также можете использовать приведенные ниже методы, предоставляемые классом Files , которые работают так же, как потоки, которые мы рассмотрели ранее в статье:
Вступление
В этой статье мы погрузимся в Чтение и запись файлов на Java .
При программировании, независимо от того, создаете ли вы мобильное приложение, веб-приложение или просто пишете сценарии, вам часто приходится читать или записывать данные в файл. Эти данные могут быть данными кэша, данными, которые вы получили для набора данных, изображения или практически всем, что вы можете придумать.
В этом уроке мы покажем наиболее распространенные способы чтения и записи файлов на Java.
Java предоставляет несколько API (также известных как Java I/O ) для чтения и записи файлов с момента ее первых выпусков. В последующих выпусках ввод-вывод Java был улучшен, упрощен и расширен для поддержки новых функций.
Прежде чем мы перейдем к некоторым реальным примерам, это поможет понять доступные вам классы, которые будут обрабатывать чтение и запись данных в файлы. В следующих разделах мы дадим краткий обзор классов ввода-вывода Java и объясним, что они делают, затем мы рассмотрим потоки Java NIO и, наконец, покажем некоторые примеры чтения и записи данных в файлы.
Вывод
В этой статье мы рассмотрели наиболее распространенные способы чтения и записи данных в файл с использованием как пакета ввода-вывода Java, так и более нового пакета Java NIO. Всякий раз, когда это возможно, мы рекомендуем использовать классы Java NIO для файловых операций из-за его неблокирующего API, и, кроме того, код немного более удобен для обслуживания и чтения.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com . javarush . task . task20 . task2001 ; |
import java . io .*; |
import java . util . ArrayList ; |
import java . util . Arrays ; |
import java . util . List ; |
/* |
Читаем и пишем в файл: Human |
Реализуй логику записи в файл и чтения из файла для класса Human. |
Поле name в классе Human не может быть пустым. |
Метод main реализован только для вас и не участвует в тестировании. |
*/ |
public class Solution |
public static void main ( String [] args ) |
//исправьте outputStream/inputStream в соответствии с путем к вашему реальному файлу |
try |
File your_file_name = new File ( "D:\\1.txt" ); |
OutputStream outputStream = new FileOutputStream ( your_file_name ); |
InputStream inputStream = new FileInputStream ( your_file_name ); |
Human ivanov = new Human ( "Ivanov" , new Asset ( "home" , 999_999.99 ), new Asset ( "car" , 2999.99 )); |
ivanov . save ( outputStream ); |
outputStream . flush (); |
Human somePerson = new Human (); |
somePerson . load ( inputStream ); |
inputStream . close (); |
//check here that ivanov equals to somePerson - проверьте тут, что ivanov и somePerson равны |
if ( somePerson . hashCode () == ivanov . hashCode ()); |
> catch ( IOException e ) |
//e.printStackTrace(); |
System . out . println ( "Oops, something wrong with my file" ); |
> catch ( Exception e ) |
//e.printStackTrace(); |
System . out . println ( "Oops, something wrong with save/load method" ); |
> |
> |
public static class Human |
public String name ; |
public List < Asset >assets = new ArrayList <>(); |
public Human () |
> |
public Human ( String name , Asset . assets ) |
this . name = name ; |
if ( assets != null ) |
this . assets . addAll ( Arrays . asList ( assets )); |
> |
> |
@ Override |
public boolean equals ( Object o ) |
if ( this == o ) return true ; |
if ( o == null || getClass () != o . getClass ()) return false ; |
Human human = ( Human ) o ; |
if ( name != null ? ! name . equals ( human . name ) : human . name != null ) return false ; |
return assets != null ? assets . equals ( human . assets ) : human . assets == null ; |
> |
@ Override |
public int hashCode () |
int result = name != null ? name . hashCode () : 0 ; |
result = 31 * result + ( assets != null ? assets . hashCode () : 0 ); |
return result ; |
> |
public void save ( OutputStream outputStream ) throws Exception |
//implement this method - реализуйте этот метод |
PrintWriter saveWriter = new PrintWriter ( outputStream ); |
saveWriter . println ( this . name ); |
if ( assets != null ) |
for ( Asset asset : assets ) |
saveWriter . println ( asset . getName ()); |
saveWriter . println ( asset . getPrice ()); |
> |
> |
saveWriter . close (); |
> |
public void load ( InputStream inputStream ) throws Exception |
//implement this method - реализуйте этот метод |
BufferedReader loadReader = new BufferedReader ( new InputStreamReader ( inputStream )); |
name = loadReader . readLine (); |
while ( loadReader . ready ()) |
assets . add ( new Asset ( loadReader . readLine (), Double . parseDouble ( loadReader . readLine ()))); |
> |
loadReader . close (); |
> |
> |
> |
/*Требования: |
1. Логика чтения/записи реализованная в методах save/load должна работать корректно в случае, если список assets пустой. |
2. Логика чтения/записи реализованная в методах save/load должна работать корректно в случае, если поле name и список assets не пустые. |
3. Класс Solution.Human не должен поддерживать интерфейс Serializable. |
4. Класс Solution.Human должен быть публичным. |
5. Класс Solution.Human не должен поддерживать интерфейс Externalizable.*/ |
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
- Привет, Амиго! Сегодня мы познакомимся с еще одной интересной темой. А именно: сохранением и загрузкой (восстановлением) объектов . Допустим у нас есть класс Cat:
Код |
---|
class Cat public String name; public int age; public int weight; > |
И мы хотим добавить в него удобный механизм сохранения в файл и загрузки из файла.
Вот как это можно сделать:
public void save (OutputStream outputStream ) throws Exception
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter .println(name);
printWriter .println(age);
printWriter .println(weight);
>
- О! Это же очень просто. Мы просто печатаем значения всех аргументов, по одному в каждой строчке. А при загрузке читаем их в том же порядке. Отличное решение.
- Спасибо, Амиго. А можешь написать, как будут выглядеть методы save и load у такой группы классов:
Код |
---|
class Cat public String name; public int age; public int weight; > class Dog public String name; public int age; > class Human public Cat cat; public Dog dog; > |
У тебя есть объект человек, и он может иметь одну собаку и одного кота.
- У меня есть решение:
public void save (OutputStream outputStream ) throws Exception
PrintWriter printWriter = new PrintWriter( outputStream );
printWriter .println(name);
printWriter .println(age);
printWriter .println(weight);
>
public void save (OutputStream outputStream ) throws Exception
PrintWriter printWriter = new PrintWriter( outputStream );
printWriter .println(name);
printWriter .println(age);
>
public void save (OutputStream outputStream ) throws Exception
cat.save( outputStream );
dog.save( outputStream );
>
- Очень хорошее решение. Но что будет, если у человека нет кота, а есть только собака?
Где проверки на null?
public void save (OutputStream outputStream ) throws Exception
if (cat != null)
cat.save( outputStream );
if (dog != null)
dog.save( outputStream );
>
- Все равно не очень верно. У тебя две ошибки:
1) Если у человека нет ни кота, ни собаки, они все равно будут созданы, при вызове метода load
2) Если мы сохраним только собаку, то ее данные будут прочитаны котом при загрузке.
- А что же делать?
- Мы не можем пропускать запись переменных, иначе это вызовет сбой при чтении. Но нужно сделать так, чтобы переменные, чье значение было null при сохранении и после загрузки, получали null. Вот мой вариант:
public void save (OutputStream outputStream ) throws Exception
PrintWriter writer = new PrintWriter( outputStream );
String isCatPresent = cat != null ? "yes" : "no";
writer.print(isCatPresent);
if (cat!=null)
cat.save( outputStream );
String isDogPresent = dog != null ? "yes" : "no";
writer.print(isDogPresent);
if (dog != null)
dog.save( outputStream );
>
public void load (InputStream inputStream ) throws Exception
BufferedReader reader = new BufferedReader(new InputStreamReader( inputStream ));
String isCatPresent = reader.readLine();
if (isCatPresent.equals("yes"))
<
cat = new Cat();
cat.load( inputStream );
>
- Да, мне нравится такое решение.
- Да, что-то в нем есть.
Разница между вводом-выводом Java и NIO
Основное различие между этими двумя пакетами заключается в том, что методы read() и write() блокируют вызовы области ввода-вывода Java. Под этим мы подразумеваем, что поток, вызывающий один из этих методов, будет заблокирован до тех пор, пока данные не будут прочитаны или записаны в файл.
С другой стороны, в случае NIO методы не являются блокирующими. Это означает, что вызывающие потоки могут выполнять другие задачи (например, чтение/запись данных из другого источника или обновление пользовательского интерфейса), в то время как методы чтение или запись ожидают завершения своей операции. Это может привести к значительному повышению производительности, если вы имеете дело с большим количеством запросов ввода-вывода или большим количеством данных.
Читайте также: