Читаем и пишем в файл статики

Обновлено: 06.07.2024

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

В языке программирования C указатель на файл имеет тип FILE и его объявление выглядит так:

С другой стороны, функция fopen() открывает файл по указанному в качестве первого аргумента адресу в режиме чтения ("r"), записи ("w") или добавления ("a") и возвращает в программу указатель на него. Поэтому процесс открытия файла и подключения его к программе выглядит примерно так:

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

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

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

Объявление функции fopen() содержится в заголовочном файле stdio.h, поэтому требуется его подключение. Также в stdio.h объявлен тип-структура FILE.

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

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

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

fscanf()

Функция fscanf() аналогична по смыслу функции scanf() , но в отличии от нее осуществляет форматированный ввод из файла, а не стандартного потока ввода. Функция fscanf() принимает параметры: файловый указатель, строку формата, адреса областей памяти для записи данных:

Возвращает количество удачно считанных данных или EOF. Пробелы, символы перехода на новую строку учитываются как разделители данных.

Допустим, у нас есть файл содержащий такое описание объектов:

Тогда, чтобы считать эти данные, мы можем написать такую программу:

В данном случае объявляется структура и массив структур. Каждая строка из файла соответствует одному элементу массива; элемент массива представляет собой структуру, содержащую строковое и два числовых поля. За одну итерацию цикл считывает одну строку. Когда встречается конец файла fscanf() возвращает значение EOF и цикл завершается.

fgets()

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

Такой вызов функции прочитает из файла, связанного с указателем myfile, одну строку текста полностью, если ее длина меньше 50 символов с учетом символа '\n', который функция также сохранит в массиве. Последним (50-ым) элементом массива str будет символ '\0', добавленный fgets() . Если строка окажется длиннее, то функция прочитает 49 символов и в конце запишет '\0'. В таком случае '\n' в считанной строке содержаться не будет.

В этой программе в отличие от предыдущей данные считываются строка за строкой в массив arr. Когда считывается следующая строка, предыдущая теряется. Функция fgets() возвращает NULL в случае, если не может прочитать следующую строку.

getc() или fgetc()

Функция getc() или fgetc() (работает и то и другое) позволяет получить из файла очередной один символ.

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

Запись в текстовый файл

Также как и ввод, вывод в файл может быть различным.

  • Форматированный вывод. Функция fprintf ( файловый_указатель, строка_формата, переменные ) .
  • Посточный вывод. Функция fputs ( строка, файловый_указатель ) .
  • Посимвольный вывод. Функция fputc() или putc( символ, файловый_указатель ) .

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

Запись в каждую строку файла полей одной структуры:

Построчный вывод в файл ( fputs() , в отличие от puts() сама не помещает в конце строки '\n'):

Пример посимвольного вывода:

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

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

При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка "rb" или "wb".

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

Функции fread() и fwrite() принимают в качестве параметров:

  1. адрес области памяти, куда данные записываются или откуда считываются,
  2. размер одного данного какого-либо типа,
  3. количество считываемых данных указанного размера,
  4. файловый указатель.

Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно "заказать" считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.

Пример использования функций fread() и fwrite() :

Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.

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. */

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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.

Оригинальная версия продукта: Visual Studio
Исходный номер КБ: 816149

Аннотация

В разделе Чтение текстовых файлов этой статьи описывается, как использовать класс для чтения StreamReader текстового файла. Разделы Write a text file (пример 1) и разделы Write a text file (пример 2) описывают, как использовать класс для записи StreamWriter текста в файл.

Чтение текстового файла

Следующий код использует класс для открытия, чтения и закрытия StreamReader текстового файла. Вы можете передать путь текстового файла конструктору, чтобы StreamReader открыть его автоматически. Метод читает каждую строку текста и приращение указателя файла к следующей строке по ReadLine мере чтения. Когда метод достигает конца файла, он возвращает ReadLine ссылку null. Дополнительные сведения см. в группе StreamReader Class.

Создайте пример текстового файла в Блокнот. Выполните приведенные ниже действия.

  1. Вклеить текст hello world в Блокнот.
  2. Сохраните файл как Sample.txt.

Начните Microsoft Visual Studio.

В меню File указать на New, а затем выбрать Project.

Добавьте следующий код в начале файла Class1.cs:

Добавьте в метод следующий Main код:

В меню Отлаговка выберите Пуск для компиляции и запуска приложения. Нажмите КНОПКУ ВВОД, чтобы закрыть окно консоли. В окне Консоли отображается содержимое файла Sample.txt:

Написать текстовый файл (пример 1)

Следующий код использует класс для открытия, записи и закрытия StreamWriter текстового файла. Аналогично классу, вы можете передать путь текстового файла конструктору, чтобы открыть StreamReader StreamWriter его автоматически. Метод WriteLine записывает полную строку текста в текстовый файл.

Запустите Visual Studio.

В меню File указать на New, а затем выбрать Project.

Добавьте следующий код в начале файла Class1.cs:

Добавьте в метод следующий Main код:

В меню Отлаговка выберите Пуск для компиляции и запуска приложения. Этот код создает файл, которыйTest.txt на диске C. Open Test.txt в текстовом редакторе, например Блокнот. Test.txt содержит две строки текста:

Написать текстовый файл (пример 2)

Следующий код использует класс для открытия, записи и закрытия StreamWriter текстового файла. В отличие от предыдущего примера, этот код передает конструктору два дополнительных параметра. Первый параметр — путь к файлу и имя файла. Второй параметр true указывает, что файл открыт в режиме приложения. Если вы указываете для второго параметра, содержимое файла перезаписывается при каждом запуске false кода. Третий параметр Unicode указывает, чтобы StreamWriter кодировать файл в формате Unicode. Можно также указать следующие методы коди-кодинга для третьего параметра:

Метод похож на метод, за исключением того, что метод не автоматически встраит комбинацию символов возврата или строки Write WriteLine Write (CR/LF). Это полезно, когда нужно одновременно писать по одному символу.

Запустите Visual Studio.

В меню Файл выберите пункт Создать и затем пункт Проект.

Добавьте следующий код в начале файла Class1.cs:

Добавьте в метод следующий Main код:

В меню Отлаговка выберите Пуск для компиляции и запуска приложения. Этот код создает файл, которыйTest1.txt на диске C. Open Test1.txt в текстовом редакторе, например Блокнот. Test1.txt содержит одну строку текста: 0123456789.

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

Полное перечисление кода для записи текстового файла (версия 1)

Полное перечисление кода для записи текстового файла (версия 2)

Устранение неполадок

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

В этом уроке мы будем использовать методы Files.lines (), Files.ReadString (), Files.ReadAllBytes() и классы FileReader, BufferedReader и Scanner для чтения файла в строку на Java с примерами.

Вступление

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

Вот список всех классов и методов, которые мы рассмотрим:

  • Файлы.строки()
  • Файлы.Строка чтения()
  • Файлы.ReadAllBytes()
  • Устройство для чтения файлов
  • Буферизатор
  • Сканер

Файлы.строки()

Класс Files содержит статические методы для работы с файлами и каталогами. Полезным методом является lines () , который возвращает поток строк: Поток<Строка> . Из этого потока можно получить строки, содержащиеся в файле.

Метод принимает Путь к файлу, который мы хотели бы прочитать, с необязательной кодировкой . Мы будем использовать синтаксис try-with-resources для автоматизации очистки и закрытия:

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

Вместо печати каждой строки для добавления строк можно использовать StringBuilder :

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

Если файл не слишком велик, можно поместить его в строку, хотя, если он размером в сотни мегабайт, это не так мудро.

Файлы.Строка чтения()

Начиная с Java 11, класс Files познакомил нас с методом ReadString () , который принимает Путь к файлу, а также Кодировку .

В отличие от Files.lines() , он возвращает Строку напрямую, а не Поток объект:

Файлы.ReadAllBytes()

Этот метод также принимает Путь к файлу, который мы хотели бы прочитать:

Теперь массив байт содержит всю информацию из input.txt файл. Самый простой способ преобразовать его в строку-поместить их в конструктор с необязательной кодировкой :

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

Сканер

Поскольку мы работаем со строками, мы хотели бы использовать методы, возвращающие строки. Сканер имеет next() и nextLine() именно для этого. Оба метода возвращают объекты типа String . Первый используется для чтения произвольных строк, в то время как второй анализирует и возвращает целые строки.

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

Мы используем цикл while до тех пор, пока sc содержит больше элементов. Если бы мы не проверили с помощью hasNext() , sc выдал бы Исключение NoSuchElementException , если мы попытаемся получить доступ к элементу после последнего.

Идея использования методов hasNext() и next() исходит из интерфейса Итератора , поскольку Сканер реализует его внутренне.

Устройство для чтения файлов

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

Файл FileReader используется для чтения файлов. Он предлагает методы read() и read(char []) , которые возвращают один символ и несколько символов соответственно. Кроме того, он принимает Файл или Строку в конструктор.

Считыватель файлов.чтение(символ[])

Давайте откроем файл с помощью FileReader и прочитаем его содержимое:

Метод read() принимает последовательность символов (в которой мы храним прочитанные символы), начальную и конечную точки того, что мы хотели бы прочитать. В частности, мы решили прочитать не более 256 символов. Если input.txt имеет больше, мы будем читать только 256 символов. Если в нем меньше, возвращаются читаемые символы.

Возвращаемое значение, хранящееся внутри целого числа n , может быть использовано для проверки того, сколько символов метод на самом деле прочитал. В случае, если достигнут конец потока, метод возвращает -1 .

Поскольку метод заполняет символ[] , мы можем преобразовать его в Строку . Аналогичный результат можно получить с помощью String.valueOf(char[]) .

Читатель файлов.чтение()

Метод read() без char[] считывает по одному символу за раз. Мы захотим просмотреть содержимое и прочитать каждый символ самостоятельно:

Здесь мы проверяем, не является ли прочитанный символ -1 , что указывало на то, что для чтения больше не осталось символов. Если нет, мы добавим() его в StringBuilder и, наконец, преобразуем его в Строку .

Примечание: Оба read() и read(char[]) считанные байты, преобразуйте их в символы и возвращайте их по одному . Это неэффективно и должно выполняться с помощью буферизации , когда это возможно.

Буферизатор

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

Давайте создадим экземпляр BufferedReader :

На данный момент у нас есть объект bufferedreader, готовый для чтения содержимого из input.txt . В этом примере мы будем читать файл построчно, хотя BufferedReader поддерживает чтение отдельных символов по отдельности, а также нескольких символов в массив.

Давайте используем этот экземпляр BufferedReader для чтения файла и сохранения его содержимого, строка за строкой, в строку:

Еще раз, мы используем StringBuilder для сбора всех строк. Чтобы разделить каждую строку, мы добавляем нулевой терминатор ( \n ) между ними. Наконец, мы закрываем ручей.

Вывод

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

Читайте также: