Ошибка при взаимодействии с файлом c

It is quite common that errors may occur while reading data from a file in C++ or writing data to a file. For example, an error may arise due to the following:

  • When trying to read a file beyond indicator.
  • When trying to read a file that does not exist.
  • When trying to use a file that has not been opened.
  • When trying to use a file in an inappropriate mode i.e., writing data to a file that has been opened for reading.
  • When writing to a file that is write-protected i.e., trying to write to a read-only file.

Failure to check for errors then the program may behave abnormally therefore an unchecked error may result in premature termination for the program or incorrect output.

Below are some Error handling functions during file operations in C/C++:

ferror():

In C/C++, the library function ferror() is used to check for the error in the stream. Its prototype is written as:

 int ferror (FILE *stream);

The ferror() function checks for any error in the stream. It returns a value zero if no error has occurred and a non-zero value if there is an error. The error indication will last until the file is closed unless it is cleared by the clearerr() function. 

Below is the program to implement the use of ferror():

C

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    char feedback[100];

    int i;

    fp = fopen("GeeksForGeeks.TXT", "w");

    if (fp == NULL) {

        printf("n The file could "

               "not be opened");

        exit(1);

    }

    printf("n Provide feedback on "

           "this article: ");

    fgets(feedback, 100, stdin);

    for (i = 0; i < feedback[i]; i++)

        fputc(feedback[i], fp);

    if (ferror(fp)) {

        printf("n Error writing in file");

        exit(1);

    }

    fclose(fp);

}

C++

#include <bits/stdc++.h>

int main()

{

    FILE* fp;

    char feedback[100];

    int i;

    fp = fopen("GeeksForGeeks.TXT", "w");

    if (fp == NULL) {

        printf("n The file could "

               "not be opened");

        exit(1);

    }

    printf("n Provide feedback on "

           "this article: ");

    fgets(feedback, 100, stdin);

    for (i = 0; i < feedback[i]; i++)

        fputc(feedback[i], fp);

    if (ferror(fp)) {

        printf("n Error writing in file");

        exit(1);

    }

    fclose(fp);

}

Output:

Explanation: After executing this code “Provide feedback on this article:“ will be displayed on the screen and after giving some feedback “Process exited after some seconds with return value 0″ will be displayed on the screen.

clearerr():

The function clearerr() is used to clear the end-of-file and error indicators for the stream. Its prototype can be given as:

void clearerr(FILE *stream);

The clearerr() clears the error for the stream pointed by the stream. The function is used because error indicators are not automatically cleared. Once the error indicator for a specific stream is set, operations on the stream continue to return an error value until clearerr(), fseek(), fsetpos(), or rewind() is called.

Below is the program to implement the use of clearerr():

C

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    char feedback[100];

    char c;

    fp = fopen("file.txt", "w");

    c = fgetc(fp);

    if (ferror(fp)) {

        printf("Error in reading from"

               " file : file.txtn");

    }

    clearerr(fp);

    if (ferror(fp)) {

        printf("Error in reading from "

               "file : file.txtn");

    }

    fclose(fp);

}

C++

#include <bits/stdc++.h>

int main()

{

    FILE* fp;

    char feedback[100];

    char c;

    fp = fopen("file.txt", "w");

    c = fgetc(fp);

    if (ferror(fp)) {

        printf("Error in reading from"

               " file : file.txtn");

    }

    clearerr(fp);

    if (ferror(fp)) {

        printf("Error in reading from "

               "file : file.txtn");

    }

    fclose(fp);

}

Output:

The function perror() stands for print error. In case of an error, the programmer can determine the type of error that has occurred using the perror() function. When perror() is called, then it displays a message describing the most recent error that occurred during a library function call or system call. Its prototype can be given as:

void perror (char*msg);

  • The perror() takes one argument which points to an optional user-defined message the message is printed first followed by a colon and the implementation-defined message that describes the most recent error.
  • If a call to perror() is made when no error has actually occurred then ‘No error’ will be displayed.
  • The most important thing to remember is that a call to perror() and nothing is done to deal with the error condition, then it is entirely up to the program to take action. For example, the program may prompt the user to do something such as terminate the program.
  • Usually, the program’s activities will be determined by checking the value of errno and the nature of the error.
  • In order to use the external constant errno, you must include the header file ERRNO.H

Below is the program given below illustrates the use of perror(). Here, assume that the file “file.txt” does not exist.

C

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    rename("file.txt", "newfile.txt");

    fp = fopen("file.txt", "r");

    if (fp == NULL) {

        perror("Error: ");

        return (-1);

    }

    fclose(fp);

    return (0);

}

C++

#include <bits/stdc++.h>

#include <errno.h>

int main()

{

    FILE* fp;

    rename("file.txt", "newfile.txt");

    fp = fopen("file.txt", "r");

    if (fp == NULL) {

        perror("Error: ");

        return (-1);

    }

    fclose(fp);

    return (0);

}

Output:

Last Updated :
10 Jan, 2022

Like Article

Save Article

It is quite common that errors may occur while reading data from a file in C++ or writing data to a file. For example, an error may arise due to the following:

  • When trying to read a file beyond indicator.
  • When trying to read a file that does not exist.
  • When trying to use a file that has not been opened.
  • When trying to use a file in an inappropriate mode i.e., writing data to a file that has been opened for reading.
  • When writing to a file that is write-protected i.e., trying to write to a read-only file.

Failure to check for errors then the program may behave abnormally therefore an unchecked error may result in premature termination for the program or incorrect output.

Below are some Error handling functions during file operations in C/C++:

ferror():

In C/C++, the library function ferror() is used to check for the error in the stream. Its prototype is written as:

 int ferror (FILE *stream);

The ferror() function checks for any error in the stream. It returns a value zero if no error has occurred and a non-zero value if there is an error. The error indication will last until the file is closed unless it is cleared by the clearerr() function. 

Below is the program to implement the use of ferror():

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    char feedback[100];

    int i;

    fp = fopen("GeeksForGeeks.TXT", "w");

    if (fp == NULL) {

        printf("n The file could "

               "not be opened");

        exit(1);

    }

    printf("n Provide feedback on "

           "this article: ");

    fgets(feedback, 100, stdin);

    for (i = 0; i < feedback[i]; i++)

        fputc(feedback[i], fp);

    if (ferror(fp)) {

        printf("n Error writing in file");

        exit(1);

    }

    fclose(fp);

}

C++

#include <bits/stdc++.h>

int main()

{

    FILE* fp;

    char feedback[100];

    int i;

    fp = fopen("GeeksForGeeks.TXT", "w");

    if (fp == NULL) {

        printf("n The file could "

               "not be opened");

        exit(1);

    }

    printf("n Provide feedback on "

           "this article: ");

    fgets(feedback, 100, stdin);

    for (i = 0; i < feedback[i]; i++)

        fputc(feedback[i], fp);

    if (ferror(fp)) {

        printf("n Error writing in file");

        exit(1);

    }

    fclose(fp);

}

Output:

Explanation: After executing this code “Provide feedback on this article:“ will be displayed on the screen and after giving some feedback “Process exited after some seconds with return value 0″ will be displayed on the screen.

clearerr():

The function clearerr() is used to clear the end-of-file and error indicators for the stream. Its prototype can be given as:

void clearerr(FILE *stream);

The clearerr() clears the error for the stream pointed by the stream. The function is used because error indicators are not automatically cleared. Once the error indicator for a specific stream is set, operations on the stream continue to return an error value until clearerr(), fseek(), fsetpos(), or rewind() is called.

Below is the program to implement the use of clearerr():

C

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    char feedback[100];

    char c;

    fp = fopen("file.txt", "w");

    c = fgetc(fp);

    if (ferror(fp)) {

        printf("Error in reading from"

               " file : file.txtn");

    }

    clearerr(fp);

    if (ferror(fp)) {

        printf("Error in reading from "

               "file : file.txtn");

    }

    fclose(fp);

}

C++

#include <bits/stdc++.h>

int main()

{

    FILE* fp;

    char feedback[100];

    char c;

    fp = fopen("file.txt", "w");

    c = fgetc(fp);

    if (ferror(fp)) {

        printf("Error in reading from"

               " file : file.txtn");

    }

    clearerr(fp);

    if (ferror(fp)) {

        printf("Error in reading from "

               "file : file.txtn");

    }

    fclose(fp);

}

Output:

The function perror() stands for print error. In case of an error, the programmer can determine the type of error that has occurred using the perror() function. When perror() is called, then it displays a message describing the most recent error that occurred during a library function call or system call. Its prototype can be given as:

void perror (char*msg);

  • The perror() takes one argument which points to an optional user-defined message the message is printed first followed by a colon and the implementation-defined message that describes the most recent error.
  • If a call to perror() is made when no error has actually occurred then ‘No error’ will be displayed.
  • The most important thing to remember is that a call to perror() and nothing is done to deal with the error condition, then it is entirely up to the program to take action. For example, the program may prompt the user to do something such as terminate the program.
  • Usually, the program’s activities will be determined by checking the value of errno and the nature of the error.
  • In order to use the external constant errno, you must include the header file ERRNO.H

Below is the program given below illustrates the use of perror(). Here, assume that the file “file.txt” does not exist.

C

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    rename("file.txt", "newfile.txt");

    fp = fopen("file.txt", "r");

    if (fp == NULL) {

        perror("Error: ");

        return (-1);

    }

    fclose(fp);

    return (0);

}

C++

#include <bits/stdc++.h>

#include <errno.h>

int main()

{

    FILE* fp;

    rename("file.txt", "newfile.txt");

    fp = fopen("file.txt", "r");

    if (fp == NULL) {

        perror("Error: ");

        return (-1);

    }

    fclose(fp);

    return (0);

}

Output:

It is quite common that errors may occur while reading data from a file in C++ or writing data to a file. For example, an error may arise due to the following:

  • When trying to read a file beyond indicator.
  • When trying to read a file that does not exist.
  • When trying to use a file that has not been opened.
  • When trying to use a file in an inappropriate mode i.e., writing data to a file that has been opened for reading.
  • When writing to a file that is write-protected i.e., trying to write to a read-only file.

Failure to check for errors then the program may behave abnormally therefore an unchecked error may result in premature termination for the program or incorrect output.

Below are some Error handling functions during file operations in C/C++:

ferror():

In C/C++, the library function ferror() is used to check for the error in the stream. Its prototype is written as:

 int ferror (FILE *stream);

The ferror() function checks for any error in the stream. It returns a value zero if no error has occurred and a non-zero value if there is an error. The error indication will last until the file is closed unless it is cleared by the clearerr() function. 

Below is the program to implement the use of ferror():

C

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    char feedback[100];

    int i;

    fp = fopen("GeeksForGeeks.TXT", "w");

    if (fp == NULL) {

        printf("n The file could "

               "not be opened");

        exit(1);

    }

    printf("n Provide feedback on "

           "this article: ");

    fgets(feedback, 100, stdin);

    for (i = 0; i < feedback[i]; i++)

        fputc(feedback[i], fp);

    if (ferror(fp)) {

        printf("n Error writing in file");

        exit(1);

    }

    fclose(fp);

}

C++

#include <bits/stdc++.h>

int main()

{

    FILE* fp;

    char feedback[100];

    int i;

    fp = fopen("GeeksForGeeks.TXT", "w");

    if (fp == NULL) {

        printf("n The file could "

               "not be opened");

        exit(1);

    }

    printf("n Provide feedback on "

           "this article: ");

    fgets(feedback, 100, stdin);

    for (i = 0; i < feedback[i]; i++)

        fputc(feedback[i], fp);

    if (ferror(fp)) {

        printf("n Error writing in file");

        exit(1);

    }

    fclose(fp);

}

Output:

Explanation: After executing this code “Provide feedback on this article:“ will be displayed on the screen and after giving some feedback “Process exited after some seconds with return value 0″ will be displayed on the screen.

clearerr():

The function clearerr() is used to clear the end-of-file and error indicators for the stream. Its prototype can be given as:

void clearerr(FILE *stream);

The clearerr() clears the error for the stream pointed by the stream. The function is used because error indicators are not automatically cleared. Once the error indicator for a specific stream is set, operations on the stream continue to return an error value until clearerr(), fseek(), fsetpos(), or rewind() is called.

Below is the program to implement the use of clearerr():

C

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    char feedback[100];

    char c;

    fp = fopen("file.txt", "w");

    c = fgetc(fp);

    if (ferror(fp)) {

        printf("Error in reading from"

               " file : file.txtn");

    }

    clearerr(fp);

    if (ferror(fp)) {

        printf("Error in reading from "

               "file : file.txtn");

    }

    fclose(fp);

}

C++

#include <bits/stdc++.h>

int main()

{

    FILE* fp;

    char feedback[100];

    char c;

    fp = fopen("file.txt", "w");

    c = fgetc(fp);

    if (ferror(fp)) {

        printf("Error in reading from"

               " file : file.txtn");

    }

    clearerr(fp);

    if (ferror(fp)) {

        printf("Error in reading from "

               "file : file.txtn");

    }

    fclose(fp);

}

Output:

The function perror() stands for print error. In case of an error, the programmer can determine the type of error that has occurred using the perror() function. When perror() is called, then it displays a message describing the most recent error that occurred during a library function call or system call. Its prototype can be given as:

void perror (char*msg);

  • The perror() takes one argument which points to an optional user-defined message the message is printed first followed by a colon and the implementation-defined message that describes the most recent error.
  • If a call to perror() is made when no error has actually occurred then ‘No error’ will be displayed.
  • The most important thing to remember is that a call to perror() and nothing is done to deal with the error condition, then it is entirely up to the program to take action. For example, the program may prompt the user to do something such as terminate the program.
  • Usually, the program’s activities will be determined by checking the value of errno and the nature of the error.
  • In order to use the external constant errno, you must include the header file ERRNO.H

Below is the program given below illustrates the use of perror(). Here, assume that the file “file.txt” does not exist.

C

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

    FILE* fp;

    rename("file.txt", "newfile.txt");

    fp = fopen("file.txt", "r");

    if (fp == NULL) {

        perror("Error: ");

        return (-1);

    }

    fclose(fp);

    return (0);

}

C++

#include <bits/stdc++.h>

#include <errno.h>

int main()

{

    FILE* fp;

    rename("file.txt", "newfile.txt");

    fp = fopen("file.txt", "r");

    if (fp == NULL) {

        perror("Error: ");

        return (-1);

    }

    fclose(fp);

    return (0);

}

Output:

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

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

  • FileNotFoundException,
    если файла с указанным именем в указанном
    каталоге не существует;

  • DirectoryNotFoundException,
    если не существует указанный каталог;

  • ArgumentEception,
    если неверно задан режим открытия
    файла;

  • IOException,
    если файл не открывается из-за ошибок
    ввода-вывода.

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

try

{

FileStream
f=new FileStream( @»d:C#text.txt»,

FileMode.Open, FileAccess.Read);

… //действия
над
файлом

f.Close();

}

catch(FileNotFoundException
e)

{

Console.WriteLine(e.Message);

Console.WriteLine(«Проверьте
правильность
имени
файла!
«);

return;

}

catch(Exception
e)

{

Console.WriteLine(«Error:
»
+ e.Message);

return;
}

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

Текстовые файлы

Символьные
потоки — классы StreamWriterиStreamReaderработают сUnicode-символами, следовательно,
ими удобнее всего пользоваться для
работы с файлами, предназначенными для
восприятия человеком. Эти потоки являются
наследниками классовTextWriterиTextReaderсоответственно.
В таблицах 11.5 и 11.6 приведены основные
элементы этих классов.Произвольный
доступ
для текстовых файловне
поддерживается.

Таблица
11.5 – Основные элементы класса TextWriter

Элемент Описание

­CloseЗакрыть
файл и освободить связанные с ним
ресурсы. Если в процессе

записи
используется буфер, он будет очищен

FlushОчистить
все буферы для текущего файла и записать
накопленные

в
них данные в место их постоянного
хранения. Сам файл при этом

не
закрывается

NewLineИспользуется
для задания последовательности символов,
означающих

начало
новой строки. По умолчанию используется
последовательность

«возврат
каретки» — «перевод строки» (rn)

WriteЗаписать
фрагмент текста в поток

WriteLineЗаписать
строку в поток и перейти на другую строку

Таблица
11.6 — Основные элементы класса TextReader

Элемент Описание

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

ReadСчитать
данные из входного потока

ReadBlockСчитать
из входного потока указанное пользователем
количество

символов
и записать их в буфер, начиная с заданной
позиции

ReadLineСчитать
строку из текущего потока и возвратить
ее как значение

типа
string. Пустая строка (null)
означает конец файла(EOF)

ReadToEndСчитать
все символы до конца потока, начиная с
текущей позиции,

и
возвратить считанные данные как одну
строку типа string

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

В
данном примере создается текстовый
файл, в который записываются 2 строки.
Вторая формируется из преобразования
численных значений переменных и
поясняющего текста. Содержимое файла
можно посмотреть в любом текстовом
редакторе. Файл создается в том же
каталоге, куда среда записывает
исполняемый файл. По умолчанию это
каталог …ConsoleApplication1binDebug.

//ЗАПИСЬ
В ТЕКСТОВЫЙ ФАЙЛ

using
System;

using
System.IO;

namespace
ConsoleApplication1

{
class
Class1

{
static
void
Main()

{
try

{ StreamWriter
f=new
StreamWriter(«text.txt»);

f.WriteLine(«Запись
в текстовый файл:»);

double
a =12/234;

int
b=29;


f.WriteLine
(«a={0,6:C}
b={1,2:X}»,
a, b);

f.Close();

}

catch
(Exception
e)

{ Console.WriteLine(«Error:»
+e.Message);

Console.ReadKey();

return;
} } }}

Файл,
созданный в предыдущем примере выводиться
на экран.

//ЧТЕНИЕ
ТЕКСТОВОГО ФАЙЛА

using
System;

using
System.IO;

namespace
ConsoleApplication1

{
class
Class1

{
static
void
Main()

{
try

{ StreamReader
f=new
StreamReader
(«text.txt»);

string
s=f.ReadToEnd();

Console.WriteLine(s);

f.Close();

}

catch
(FileNotFoundException
e)

{

Console.WriteLine(e.Message);

Console.WriteLine(«Проверьте
правильность
имени
файла!»);

Console.ReadKey();

return;
}

catch
(Exception
e)

{

Console.WriteLine(«Error:»
+ e.Message);

Console.ReadKey();

return;
} } }}

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

Такой
пример приведен ниже. Каждая строка при
выводе представляется номером.

//Построчное
чтение текстового периода

using
System;

using
System.IO;

namespace
ConsoleApplication1

{
class
Class1

{
static
void
Main()

{
try

{ StreamReader
f=new
StreamReader
(«text.txt»);

string
s;

long
i=0;

while((s=f.ReadLine())
!=
null)

Console.WriteLine(«{0}:
{1}»
,
++i, s);

f.Close();

}

catch
(FileNotFoundException
e)

{
Console.WriteLine(e.Message);

Console.WriteLine(«Проверьте
правильность имени файла!»);

Console.ReadKey();

return;
}

catch
(Exception
e)

{
Console.WriteLine(«Error:»
+ e.Message);

Console.ReadKey();
return;
} } }}

Соседние файлы в папке Все лекции С#

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

Довольно часто ошибки могут возникать при чтении данных из файла на C ++ или записи данных в файл. Например, ошибка может возникнуть по следующим причинам:

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

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

Ниже приведены некоторые функции обработки ошибок во время файловых операций в C / C ++:

феррор ():

В C / C ++ библиотечная функция ferror () используется для проверки наличия ошибки в потоке. Его прототип записывается так:

 int ferror (FILE *stream);

Функция ferror () проверяет наличие ошибок в потоке. Он возвращает нулевое значение, если ошибок не произошло, и ненулевое значение, если ошибка есть. Индикация ошибки будет длиться до тех пор, пока файл не будет закрыт, если он не будет очищен функцией clearerr () .

Ниже приведена программа для реализации использования ferror () :

#include <stdio.h>

#include <stdlib.h>

int main()

{

FILE * fp;

char feedback[100];

int i;

fp = fopen ( "GeeksForGeeks.TXT" , "w" );

if (fp == NULL) {

printf ( "
The file could "

"not be opened" );

exit (1);

}

printf ( "
Provide feedback on "

"this article: " );

fgets (feedback, 100, stdin);

for (i = 0; i < feedback[i]; i++)

fputc (feedback[i], fp);

if ( ferror (fp)) {

printf ( "
Error writing in file"
);

exit (1);

}

fclose (fp);

}

C ++

#include <bits/stdc++.h>

int main()

{

FILE * fp;

char feedback[100];

int i;

fp = fopen ( "GeeksForGeeks.TXT" , "w" );

if (fp == NULL) {

printf ( "
The file could "

"not be opened" );

exit (1);

}

printf ( "
Provide feedback on "

"this article: " );

fgets (feedback, 100, stdin);

for (i = 0; i < feedback[i]; i++)

fputc (feedback[i], fp);

if ( ferror (fp)) {

printf ( "
Error writing in file"
);

exit (1);

}

fclose (fp);

}

Выход:

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

clearrr ():

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

void clearerr(FILE *stream);

Clearerr () очищает ошибку для потока, на который указывает поток. Функция используется, потому что индикаторы ошибок не очищаются автоматически. После того, как индикатор ошибки для конкретного потока устанавливается, операции на потоке продолжают возвращаться значение ошибки до clearerr (), FSEEK (), fsetpos () или перемотки назад () вызывается.

Ниже приведена программа для реализации использования clearerr () :

C

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

FILE * fp;

char feedback[100];

char c;

fp = fopen ( "file.txt" , "w" );

c = fgetc (fp);

if ( ferror (fp)) {

printf ( "Error in reading from"

" file : file.txt
"
);

}

clearerr (fp);

if ( ferror (fp)) {

printf ( "Error in reading from "

"file : file.txt
"
);

}

fclose (fp);

}

C ++

#include <bits/stdc++.h>

int main()

{

FILE * fp;

char feedback[100];

char c;

fp = fopen ( "file.txt" , "w" );

c = fgetc (fp);

if ( ferror (fp)) {

printf ( "Error in reading from"

" file : file.txt
"
);

}

clearerr (fp);

if ( ferror (fp)) {

printf ( "Error in reading from "

"file : file.txt
"
);

}

fclose (fp);

}

Выход:

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

void perror (char*msg);

  • Perror () принимает один аргумент, который указывает на необязательное определяемое пользователем сообщение, сообщение печатается первым, за которым следует двоеточие и сообщение, определяемое реализацией, которое описывает самую последнюю ошибку.
  • Если вызов perror () выполняется, когда на самом деле ошибок не было, то отображается сообщение «Нет ошибки».
  • Самая важная вещь, о которой следует помнить, — это то, что при вызове perror () ничего не делается для исправления состояния ошибки, тогда принятие мер полностью зависит от программы. Например, программа может предложить пользователю что-то сделать, например, завершить программу.
  • Обычно действия программы определяются путем проверки значения errno и характера ошибки.
  • Чтобы использовать внешнюю константу errno , вы должны включить заголовочный файл ERRNO.H

Ниже приведенная ниже программа иллюстрирует использование perror () . Предположим, что файл «file.txt» не существует.

C

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

int main()

{

FILE * fp;

rename ( "file.txt" , "newfile.txt" );

fp = fopen ( "file.txt" , "r" );

if (fp == NULL) {

perror ( "Error: " );

return (-1);

}

fclose (fp);

return (0);

}

C ++

#include <bits/stdc++.h>

#include <errno.h>

int main()

{

FILE * fp;

rename ( "file.txt" , "newfile.txt" );

fp = fopen ( "file.txt" , "r" );

if (fp == NULL) {

perror ( "Error: " );

return (-1);

}

fclose (fp);

return (0);

}

Выход:

Хотите учиться на лучших видео и практических задачах, ознакомьтесь с Базовым курсом C для базового и продвинутого C.

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

Лучше в заголовке цикла while выполнять само чтение с проверкой — например, в программе на C это могло бы выглядеть как

while(fread(&data,sizeof(data),1,file)==1)
{
    // Обработка считанных данных
}

/* Или, скажем,
while(fgets(buf, bufsize, file)) { .... }
*/


if (feof(file)) // Достигнут конец файла
    puts("Ошибка чтения: достигнут конец файла");
else if (ferror(file)) {
    puts("Ошибка чтения файла");

или на C++ — наподобие

for(int n; file >> n; ) 
{
   // Обработка считанного значения n
}

if (file.bad())
    std::cout << "Ошибка ввода-вывода при чтенииn";
else if (file.eof())
    std::cout << "Достигнут конец файлаn";
else if (file.fail())
    std::cout << "Неверный формат данныхn";

Лабораторные работы си шарп и задания по теме «Язык программирования c sharp: файлы»

Содержание:

  • Теория
    • Классификация файлов
    • Операции с файлами
    • Классы и пространства имен .NET
    • Основные методы класса File
    • Конструкция try .. catch
    • ИнструкцияUsing
  • Задания и лабораторные работы
    • Использование режима для создания файла и работы с ним без класса BinaryReader
    • Обработка ошибок при работе с файлами. Оператор Try. Считывание данных из файла

Теория

    Классификация файлов

    • Компонентный тип:
    • текстовые файлы (состоит из строк в некоторой кодировке)
    • бинарные файлы
    • Тип доступа к файлу:
    • Произвольный доступ: время доступа = Θ(1), компоненты данных имеют одинаковый размер
      (байты в простейшем случае)
    • Последовательный доступ: компоненты данных имеют различный размер, для поиска i-го компонента необходимо считать предыдущий i-1 компонент (пример: текстовые файлы)
    • Типы операций с файлами:
    • только для чтения
    • только для записи
    • чтение и запись

    Операции с файлами

    с закрытыми файлами:
    открыть
    проверить существует ли
    удалить
    скопировать
    переименовать
    переместить
    С уже открытыми файлами:
    закрыть
    записать информацию
    читать информацию
    проверить, достигнут ли конец файла
    поиск n-й позиции

    Классы и пространства имен .NET

      Пространства имен:

    • using System.IO;
    • using System.Text;
    • В платформе .net есть пространство имен System.IO, именно там расположено множество классов для работы с файлами и каталогами.

      Классы:

    • File – статический класс, операции с закрытыми файлами
    • FileMode – режим открытия файла
    • FileStream
    • StreamReader/StreamWriter – потоки для чтения-записи в текстовые файлы
    • BinaryReader/BinaryWriter — потоки для чтения-записи в двоичные файлы
    • Encoding – кодировки файлов
    • Классы File и FileInfo оба предоставляют методы для создания, копирования, удаления, перемещения и открытия файлов. Они имеют очень похожие интерфейсы, разница лишь в том, что FileInfo обеспечивает методы экземпляра, тогда как File обеспечивает методы static.
    • Разница в том, что если у вас будет небольшое количество операций, удобнее обращаться к статическим методам класса File. Если у вас будет много операций, более эффективно создать класс FileInfo и получить доступ ко всем его методам экземпляра.
    • Класс Directory предоставляет статические методы, в то время как DirectoryInfo предоставляет методы экземпляра.
    • У нас также есть класс Path, который предоставляет методы для работы со строкой, содержащей информацию о пути к файлу или каталогу.

    FileMode тип перечисления

  • FileMode.Create
  • FileMode.Open
  • FileMode.OpenOrCreate
  • FileMode.Append
  • Основные методы класса File

      Operations with closed files:

      using System.IO;
       
      // File.Exists("a.dat")
      Console.WriteLine(File.Exists("a.dat")); // true или false
      // File.Exists("d:a.dat")
      Console.WriteLine(File.Exists("d:a.dat")); // true или false
      // File.Exists(@"d:a.dat")
      Console.WriteLine(File.Exists(@"d:a.dat"); // true или false
       
      File.Delete("a.dat");
      File.Copy("d:a.dat", "d:b.dat"); // будет создан файл b.dat, если он существует - возникнет исключение
      File.Copy("a.dat", @"d:a.dat");
      File.Move("a.dat", @"..a.dat");

    Конструкция try .. catch

    try
    {
      // код с возможным исключением 
    }
    catch (Exception e)
    {
      // для обработки исключения
    }

    Пример:

    try
      {
        var path = @"d:a.dat";
        var fs = new FileStream(path, FileMode.Open);
        ...
      }
    catch (FileNotFoundException e)
      {
        Console.WriteLine($"Файл с именем {e.FileName} не найден");
      }
    catch (FileLoadException e)
      {
         Console.WriteLine($"К файлу с именем {e.FileName} невозможно получить доступ");
      }

    ИнструкцияUsing

    Пример работы с двоичными файлами:

    using System.IO;
    // ...
     
    string path = @"Lesson14.dat";
    // данные в файле: 1 2 3 4 
    var fs = new FileStream(path, FileMode.Open);
    var br = new BinaryReader(fs);
    var a=br.ReadInt32();
    Console.WriteLine(a); // 1
    var b = br.ReadInt32(); 
    Console.WriteLine(b); // 2
    var c = br.ReadInt32();
    Console.WriteLine(c); // 3
     
    fs.Close();
    • Инструкция Using обеспечивает автоматический вызов метода Close() при работе с классом FileStream.

    Example:

    var path = @"d:a.dat";
    using (var fs = new FileStream(path, FileMode.Create))
    {
      fs.WriteByte(1);
      fs.WriteByte(2);
      fs.WriteByte(3);
    }
    using (var fs = new FileStream(path, FileMode.Open))
    {
      Console.WriteLine(fs.ReadByte());
      Console.WriteLine(fs.ReadByte());
      Console.WriteLine(fs.ReadByte());
    }

Задания и лабораторные работы

Использование режима для создания файла и работы с ним без класса BinaryReader

Задание 0:

Выполнить: Create a file with a name myFile.txt on your root folder d or c (@"D:myFile.txt"). Open created file and write there some entered string (don’t forget to convert it into a byte array -> Encoding.Default.GetBytes()). Then, read the file’s data and output it to the console window (by convering data again into string -> Encoding.Default.GetString(...)).
Создайте файл с именем myFile.txt в вашей корневой папке d или c (@"D:myFile.txt"). Откройте созданный файл и запишите туда некоторую введенную строку (не забудьте преобразовать ее в байтовый массив -> Encoding.Default.GetBytes()). Затем считайте данные файла и выводите их в окно консоли (путем повторного преобразования данных в строку -> Encoding.Default.GetString(...)).

    
Примерный вывод:

Введите строку:
Hello, world!
Строка из файла:
Hello, world!

[Название проекта: Lesson_14Task0, Название файла L14Task0.cs]

Обработка ошибок при работе с файлами. Оператор Try. Считывание данных из файла

Лабораторная работа 1. Ошибка доступа на чтение к несуществующему файлу. Считывание данных из файла

  
Выполнить:

  • Создайте программу для вывода содержимого файла в окно консоли (числа могут быть выведены через пробелы в строку). Вы должны использовать класс BinaryReader.
  • Скачайте файл L01.dat и поместите его в свою рабочую папку (~/Lesson_14 Lab1/bin/Debug). В файле записано 15 целых чисел..
  • Вы должны использовать инструкцию using при работе с уже открытым файлом. Тогда, независимо от успеха работы с открытым файлом, он всегда будет закрыт.
  • using (var fs = new FileStream(path, FileMode.Create))
    {
      ...
    }
  • Используйте код для обработки исключений:
    • Чтобы предотвратить «сбой» программы и не напугать пользователя, добавьте обработку исключений — блок try..catch. Оператор using должен находиться внутри блока try..catch.
    • ...
      try
      {
           ...
      }
      catch (IOException e)
      { 
            Console.WriteLine($"Ошибка чтения из файла: {e.Message}");
      }
  • Измените имя файла в программном коде на несуществующее. Запустите приложение и проверьте обработку исключения. Снова измените имя на правильное имя.
  • Здесь нет необходимости создавать методы.

Примерный вывод:

Данные из файла:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

+++++++++++++
Данные из файла:
Ошибка чтения из: Файл 'C:UsersUserDocumentsVisual Studio 2015ProjectsL14_Lab1binDebugL02.dat' не найден

 
[Название проекта: Lesson_14Lab1, название файла L14Lab1.cs]

✍ Алгоритм:

  1. Создайте новый проект с именем файла, как указано в задании.
  2. Загрузите файл L01.dat и поместите его в свою рабочую папку (~/Lesson_14Lab1/bin/Debug).
  3. Чтобы избежать необходимости постоянно упоминать класс Console, мы можем включить его объявление прямо в начале окна редактора:
  4. ...
    using static System.Console;
    ...
    
  5. Ниже этого кода подключите пространство имен System.IO — для работы с файлами:
  6. using System.IO;
    ...
    
  7. В функции Main объявите переменную для хранения пути к файлу. Лучше использовать дословную строку (символ @):
  8. string path = @"L01.dat";
    
  9. Чтобы прочитать что-то из файла, сначала нужно открыть файл. Чтобы открыть файл, требуется указать путь к файлу в системе и режим.
  10. Итак, нам нужно инициализировать новый экземпляр класса FileStream с указанным путем и режимом. Будем использовать режим open (для чтения из файла), потому что нам не нужно ничего записывать в файл. Переменная fs будет хранить входной поток:
  11. using (var fs = new FileStream(path, FileMode.Open))
    

    Класс FileStream предоставляет поток (последовательность байтов) для ввода/считывания из файла; поддерживает как синхронные, так и асинхронные операции чтения и записи.

  12. После этого нам нужно создать переменную (br) — экземпляр класса BinaryReader, чтобы иметь возможность считывать данные из файла в виде двоичных значений:
  13. ...
    using (var br = new BinaryReader(fs))
    
  14. Чтобы не возникало ошибки, если файл не существует или если имя файла написано неверно, мы будем использовать блок try...catch. Поместите добавленные инструкции using в блок try:
  15. ...
    try
              {
                    using (var fs = new FileStream(path, FileMode.Open))
                    using (var br = new BinaryReader(fs))
              }
    
  16. Кроме того, внутри блока try мы собираемся считывать байты или символы из файла и выводить их в консоль. Для этой цели будем использовать метод PeekChar класса BinaryReader:
  17. // в блоке try, после использования инструкций using:
    while (br.PeekChar() != -1)
           {
               var x = br.ReadInt32();
               Write($"{x} ");
            }
    

    BinaryReader класс считывает примитивные типы данных как двоичные значения в определенной кодировке.

    PeekChar метод возвращает следующий доступный символ или -1, если больше нет доступных символов или поток не поддерживает поиск.

  18. В блоке catch мы собираемся распечатать сообщение в случае возникновения какой-либо ошибки, например, в случае неправильного имени файла:
  19. // under try block:
    catch (IOException e)
                    {
                        WriteLine($"Ошибка чтения из файла: {e.Message}");
                    }
    

    Класс IOException хранит исключение, которое генерируется при возникновении ошибки ввода-вывода.

    Message — это атрибут класса Exception, который возвращает сообщение об ошибке, объясняющее причину исключения, или пустую строку.

  20. В конце программного кода поместите метод ReadKey, чтобы не закрывать окно консоли при запуске программы в режиме отладки:
  21. // после закрывающей скобки блока catch
    ReadKey();
    

    Метод ReadKey ожидает ввода или нажатия клавиши клавиатуры. Нажатая клавиша отображается в окне консоли.

  22. Нажмите клавишу F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
  23. Чтобы увидеть результат при возникновении ошибки, измените имя файла, например:
  24. string path = @"L02.dat";
    
  25. Нажмите клавишу F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
  26. Верните прежнее название файла
  27. Загрузите файл .cs на проверку.

Задание 1:

Выполнить: Скопируйте файл L01.dat для предыдущей лабораторной работы и вставьте его в папку текущего задания, пусть к файлу: (~/Lesson_14Task1/bin/Debug).

1. Создайте программу для вывода чисел в квадрате из файла в окно консоли (числа могут быть выведены через пробел в пределах одной строки), а также для вычисления количества четных цифр среди чисел. Вы должны использовать класс BinaryReader. Создайте программу, используя блок try..catch.

Указание: Здесь нет необходимости создавать методы.
     

Примерный вывод:

Квадраты чисел:
1 4 9 16 25 36 49 64 81 100 121 144 169 196 225
Количество четных: 7
+++++++++++++++
Ошибка чтения из файла: Файл 'c:usersuserdocumentsvisual studio 2015ProjectsL_14Task1binDebugL02.dat' не найден.

[Название проекта: Lesson_14Task1, название файла L14Task1.cs]

Лабораторная работа 2. Несколько блоков try..catch. Считывание из файла

  
Выполнить:

  • Загрузите файл в папку с проектом L01.dat. В файле записаны целые числа. Выведите эти числа в окно консоли по N чисел в каждой строке (N вводится (N > 0) и имеет значение по умолчанию = 10). Необходимо использовать класс BinaryReader. В случае если файл пустой выведите сообщение «пустой файл».
  • Может быть несколько блоков try..catch, и каждый из них может обрабатывать разные ошибки. Напишите свой код так, чтобы один блок try..catch обрабатывал ошибки, возникающие при открытии файла, а другой блок обрабатывал ошибки, возникающие при работе с уже открытым файлом.
    • Тогда структура программы должна быть следующей:
    • ...
      try 
      {
          using ( ... )
          using ( ... )
          { 
              try 
              {
                  // работа с открытым файлом...
              }
              catch 
              {     
                  // обработка ошибки при работе с уже открытым файлом
              }
         }
      catch 
      {
          // обработка ошибки, связанной с открытием файла
      }
  • Создайте метод с двумя параметрами для выполнения задачи. Сигнатура метода:
  • static void PrintFileInRows(string path, int N=10)
  • Проверьте, правильно ли работают блоки try..catch. Смоделируйте ошибку при работе с уже открытым файлом и ошибку с именем файла. После проверки верните предыдущий (правильный) код и закомментируйте неверный код.

Примерный вывод:

Введите N:
3
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
+++++++++++++
Введите N:
3
Ошибка чтения из файла: Файл 'c:usersuserdocumentsvisual studio 2015ProjectsL_14Lab2binDebugL02.dat' не найден.
+++++++++++++
Введите N:
3
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15 
Ошибка работы с данными файла: Чтение после конца потока невозможно.

 
[Название проекта: Lesson_14Lab2, название файла L14Lab2.cs]

✍ Алгоритм:

  1. Создайте новый проект с именем и именем файла, как указано в задаче.
  2. Загрузите файл L01.dat и разместите его в рабочей папке проекта (~/Lesson_14Lab2/bin/Debug).
  3. Чтобы не печатать постоянно класс Console, мы можем включить его объявление прямо в начале окна редактора:
  4. ...
    using static System.Console;
    ...
    
  5. Подключите пространство имен <код>System.IO для работы с файлами:
  6. using System.IO;
    ...
    
  7. В функции Main объявите переменную для хранения пути к файлу. Лучше использовать дословную строку (символ @):
  8. string path = @"L01.dat";
    
  9. Мы собираемся вывести числа из файла в нескольких строках: <код> N чисел в каждой строке. В функции main нам нужно запросить пользователя число <код>N:
  10. ...
    WriteLine($"Введите N:");
    var n = int.Parse(ReadLine());
    
  11. Затем необходимо объявить метод с именем PrintFileInRows с двумя параметрами — путь к файлу и количество N:
  12. // после закрывающей фигурной скобки основной функции
    static void PrintFileInRows(string path, int n = 10)
          {
           ...
          }
    

    Метод ничего не вернет, поэтому используем ключевое слово void.

  13. Чтобы прочитать что-то из файла, сначала нужно открыть файл. Но в соответствии с требованием задачи у нас должно быть два блока try..catch, один из них обрабатывает ошибки, возникающие при открытии файла, а другой блок обрабатывает ошибки, возникающие при работе с уже открытым файлом.
  14. Итак, давайте сначала создадим блоки try..catch, а затем поместим в них остальной код:
  15. // в фигурных скобках метода
    try
                {
                   /* здесь будет код, в котором могут возникать ошибки
                   при открытии файла*/
                    {
                        try
                        {
                        /* здесь будет код, в котором могут возникать ошибки
                       при работе с уже открытым файлом*/
                        }
                        catch (IOException e)
                        {
                         // сообщение об ошибке при работе с файлом
                        }
                    }
                }
                catch (IOException e)
                {
                // сообщение об ошибке при открытии файла
                }
            }
       
    
  16. Чтобы открыть файл, необходимо указать путь к файлу в вашей системе и режим открытия — как операционная система должна открывать файл. Поместите следующий код после открытой фигурной скобки первого блока try..catch:
  17. using (var f = File.Open(path, FileMode.Open))
    {
    ...
    }
    
  18. После этого мы собираемся работать с файлом, это означает, что мы будем считывать некоторые данные из файла и что-то с ними делать. Итак, нам нужно создать переменную (br) как экземпляр класса BinaryReader, чтобы иметь возможность считывать данные из файла в виде двоичных значений. Следующий код должен быть помещен во второй блок try..catch, который находится внутри инструкции using:
  19. // после открытой фигурной скобки оператора using
     try
         {
             var br = new BinaryReader(f);
    
  20. В соответствии с требованиями задачи мы должны вывести сообщение «пустой файл», если в файле нет никаких данных. Лучше использовать метод PeekChar, который возвращает -1, если файл пуст:
  21. if (br.PeekChar() == -1)
           {
               WriteLine("пустой файл");
            }
    
  22. После этого мы будем считывать числа одно за другим из файла и выводить их в консоль. Необходимо выводить <код>N чисел в каждой строке. Используем счетчик i, чтобы подсчитать, сколько чисел мы уже прочитали. Если количество считанных чисел равно N, то мы перейдем к следующей строке:
  23. // после предыдущего оператора if
    int i = 0;
    while (br.PeekChar() != -1)
          {
              if (i >= n)
                    {
                      WriteLine();
                      i = 0;
                     }
               Write(br.ReadInt32() + " ");
               i++;
           }
    
  24. В первом блоке catch мы собираемся распечатать сообщение в случае возникновения какой-либо ошибки при работе с файлом:
  25. // within the first catch block:
    catch (IOException e)
                    {
                        WriteLine($"Ошибка работы с файлом: {e.Message}");
                    }
    

    Класс IOException хранит исключение, которое генерируется при возникновении ошибки ввода-вывода.

    Message — это атрибут класса Exception, который возвращает сообщение об ошибке, объясняющее причину исключения, или пустую строку («»).

  26. Во втором блоке catch мы собираемся распечатать сообщение в случае возникновения какой-либо ошибки при открытии файла:
  27. // в пределах первого блока catch:
    catch (IOException e)
                    {
                        Console.WriteLine($"Ошибка считывания из файла: {e.Message}");
                    }
    
  28. В конце кода программы поместите метод ReadKey, чтобы не закрывать окно консоли при запуске программы в режиме отладки:
  29. // после закрывающей скобки блока фиксации:
    ReadKey();
    

    Метод ReadKey получает следующий символ или функциональную клавишу, нажатую пользователем. Нажатая клавиша отображается в окне консоли.

  30. Нажмите F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
  31. Чтобы увидеть результат при возникновении ошибки, измените имя файла, например:
  32. string path = @"L02.dat";
    
  33. Нажмите F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
  34. Верните правильное имя файлу.
  35. Чтобы увидеть результат при возникновении ошибки во время работы с файлом, добавьте следующую строку после инструкции while:
  36. // после закрытия фигурной скобки оператора while:
    WriteLine(br.ReadInt32());
    

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

  37. Нажмите F5, чтобы запустить программу в режиме отладки и проверить выходные данные.
  38. Прокомментируйте неправильную строку кода.
  39. Загрузите файл .cs в систему moodle.

Задание 2:

Выполнить: Загрузите файл Task02.dat и вставьте его в папку с проектом: (~/Lesson_14Task2/bin/Debug). В файле записаны целые числа. Создайте программу, которая сначала выведет эти числа в окно консоли, а после этого подсчитает количество чисел, которые меньше, чем их сосед слева (меньше, чем предыдущее число в последовательности чисел).

Указание 1: Создайте метод для печати данных из файла:

static void PrintData(string path)

Указание 2: Создайте метод для вывода количества чисел, меньших, чем их сосед слева:

static int CountLessThanLeft(string path)

Указание 3: Возможно, потребуется использовать определенную кодировку символов при чтении из файла:

     using (var fs = new FileStream(path, FileMode.Open))
     using (var br = new BinaryReader(fs, Encoding.ASCII))

Указание 4: Может быть несколько блоков try..catch, и каждый из них может обрабатывать разные ошибки. Напишите свой код так, чтобы один блок try..catch обрабатывал ошибки, возникающие при открытии файла, а другой блок обрабатывал ошибки, возникающие при работе с уже открытым файлом.

Тогда структура программы должна быть следующей:

...
try 
{
    using ( ... )
    using ( ... )
    { 
        try 
        {
            //работа с открытым файлом...
        }
        catch 
        {     
            // обработка ошибки при работе с уже открытым файлом
        }
   }
catch 
{
    // обработка ошибки открытия файла
}

Указание 5: Проверьте, правильно ли работают блоки try..catch. Смоделируйте ошибку при работе с уже открытым файлом и ошибку с именем файла. После проверки верните предыдущий (правильный) код и закомментируйте неправильный.

Примерный вывод:

Числа в файле:
-35 25 28 -37 13 -9 -24 12 -35 37 -24 20 29 -11 -45 -8 43 12 12 44
Количество чисел, меньших, чем их левый сосед: 8
+++++++++++++++
Числа в файле:
-35 25 28 -37 13 -9 -24 12 -35 37 -24 20 29 -11 -45 -8 43 12 12 44 Ошибка работы  с файлом: Чтение после конца потока невозможно.
Количество чисел, меньших, чем их левый сосед: 8
+++++++++++++++

[Название проекта: Lesson_14Task2, Название файла L14Task2.cs]


Содержание

  • Исключения (Exceptions) и инструкция try
  • Оговорка catch
  • Блок finally
  • Инструкция using
  • Выбрасывание исключений
  • Основные свойства System.Exception
  • Основные типы исключений
  • Директивы препроцессора
    • Pragma Warning
    • Атрибут Conditional
  • Классы Debug и Trace
    • TraceListener
    • Fail и Assert

Исключения, их обработка, и некоторые другие моменты, связанные с ошибками в приложении на C#.

Исключения (Exceptions) и инструкция try

Инструкция try отмечает блок кода как объект для обработки ошибок или очистки. После блока try обязательно должен идти либо блок catch, либо блок finally, либо они оба. Блок catch выполняется, когда внутри блока try возникает ошибка. Блок finally выполняется после того, как прекращает выполнять блок try (или, если присутствует, блок catch), независимо от того, выполнился ли он до конца или был прерван ошибкой, что позволяет выполнить так называемый код очистки.

Блок catch имеет доступ к объекту исключения (Exception), который содержит информацию об ошибке. Блок catch позволяет обработать исключительную ситуацию и как-либо скорректировать ошибку или выбросить новое исключение. Повторное выбрасывание исключения в блоке catch обычно применяется с целью логирования ошибок или чтобы выбросить новое, более специфическое исключение.

Блок finally добавляет в программу прогнозируемость, позволяя выполнить определенный код при любых обстоятельствах. Это может быть полезно для выполнения операций очистки, например, закрытия сетевого подключения и т.д.

В целом конструкция try выглядит следующим образом:

try

{

  ... // в пределах этого блока может быть выброшено исключение

}

catch (ExceptionA ex)

{

  ... // обработчик исключений типа ExceptionA

}

catch (ExceptionB ex)

{

  ... // обработчик исключений типа ExceptionB

}

finally

{

  ... // код очистки

}

Например, следующий код выбросит ошибку DivideByZeroException (поскольку делить на ноль нельзя) и наша программа завершить досрочно:

int x = 3, y = 0;

Console.WriteLine (x / y);

Чтобы этого избежать можно использовать конструкцию try:

try

{

  int x = 3, y = 0;

  Console.WriteLine (x / y);

}

catch (DivideByZeroException ex)

{

  Console.Write («y cannot be zero. «);

}

// выполнение программы продолжится отсюда

Обработка исключений довольно ресурсоёмкая операция, поэтому на практике для таких случаев как в примере ее лучше не использовать (лучше непосредственно перед делением проверить делить на равенство нулю).

Когда выбрасывается исключение, CLR проверяет выброшено ли оно непосредственно внутри блока try, который может обработать данное исключение. Если да, выполнение переходит в соответствующий блок catch. Если блок catch успешно завершается, выполнение переходит к следующей после блока try инструкции (если имеется блок finally, то сначала выполняется он). Если же исключение выброшено не внутри блока try или конструкция try не содержит соответствующего блока catch, выполнение переходит в точку вызова метода (при этом сначала выполняется блок finally), и проверка повторяется снова.

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

Оговорка catch

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

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

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

Можно обработать несколько типов исключений с помощью нескольких оговорок catch:

try

{

  DoSomething();

}

catch (IndexOutOfRangeException ex) { ... }

catch (FormatException ex) { ... }

catch (OverflowException ex) { ... }

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

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

catch (StackOverflowException) // без переменной

{ ... }

Более того, в оговорке catch можно опустить и переменную и тип исключения — такая оговрка будет перехватывать все исключения:

Блок finally

Блок finally выполняется всегда, независимо от того выброшено исключение или нет. Блок finally обычно содержит код очистки.

Блок finally выполняется в следующих случаях:

  • после завершения блока catch
  • если выполнение блока try прервано jump-инструкциями: return, goto и т.д.
  • после выполнения блока try полностью, если исключений так и не было выброшено

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

static void ReadFile()

{

  StreamReader reader = null;

  try

  {

      reader = File.OpenText («file.txt»);

      if (reader.EndOfStream) return;

      Console.WriteLine (reader.ReadToEnd());

  }

  finally

  {

      if (reader != null) reader.Dispose();

  }

}

В пример для закрытия файла вызывается метод Dispose. Использование этого метода внутри блока finally является стандартной практикой. C# даже позволяет заменить всю конструкцию инструкцией using.

Инструкция using

Многие классы инкапсулируют неуправляемые ресурсы, такие как дескриптор файла, соединение с базой данных и т.д. Эти классы реализуют интерфейс System.IDisposable, который содержит единственный метод без параметров Dispose, освобождающий соответствующие машинные ресурсы. Инструкция using предусматривает удобный синтаксис вызова метода Dispose для объектов реализующих IDisposable внутри блока finally:

using (StreamReader reader = File.OpenText («file.txt»))

{

  ...

}

Что эквивалентно следующей конструкции:

StreamReader reader = File.OpenText («file.txt»);

try

{

  ...

}

finally

{

  if (reader != null) ((IDisposable)reader).Dispose();

}

Выбрасывание исключений

Исключение может быть выброшено автоматически во время выполнения программы либо явно в коде программы с помощью ключевого слова throw:

static void Display (string name)

{

  if (name == null)

  throw new ArgumentNullException («name»);

  Console.WriteLine (name);

}

Также исключение может быть выброшено повторно внутри блока catch:

try { ... }

catch (Exception ex)

{

  // логирование ошибки

  ...

  throw; // повторное выбрасывание того же самого исключения

}

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

Если throw заменить на throw ex, то пример по прежнему будет работать, но свойство исключения StackTrace не будет отражать исходную ошибку.

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

try

{

  ... // парсинг даты рождения из xml-данных

}

catch (FormatException ex)

{

  throw new XmlException («Неправильная дата рождения», ex);

}

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

Основные свойства System.Exception

К наиболее важным свойствам класса System.Exception можно отнести:

  • StackTrace — строка, представляющая все методы, которые были вызваны, начиная с того, в котором было выброшено исключение, и заканчивая тем, в котором содержится блок catch, перехвативший исключение;
  • Message — строка с описанием ошибки;
  • InnerException — содержит ссылку на объект Exeption, который вызвал текущее исключение (например, при повторном выбрасывании исключения).

Основные типы исключений

Следующие типы исключений являются наиболее распространенными в среде CLR и .NET Framework. Их можно выбрасывать непосредственно или использовать как базовые классы для пользовательских типов исключений.

  • System.ArgumentException — выбрасывается при вызове функции с неправильным аргументом.
  • System.ArgumentNullException — производный от ArgumentException класс, выбрасывается если один из аргументов функции неожиданно равен null.
  • System.ArgumentOutOfRangeException — производный от ArgumentException класс, выбрасывается когда аргумент функции имеет слишком большое или слишком маленькое значение для данного типа (обычно касается числовых типов). Например, такое исключение будет выброшено если попытаться передать отрицательное число в функцию, которая ожидает только положительные числа.
  • System.InvalidOperationException — выбрасывается когда состояние объекта является неподходящим для нормального выполнения метода, например, при попытке прочесть не открытый файл.
  • System.NotSupportedException — выбрасывается, когда запрошенный функционал не поддерживается, например, если попытаться вызвать метод Add для коллекции доступной только для чтения (свойство коллекции IsReadOnly возвращает true).
  • System.NotImplementedException — выбрасывается, когда запрошенный функционал еще не реализован.
  • System.ObjectDisposedException — выбрасывается при попытке вызвать метод объекта, который уже был уничтожен (disposed).

Директивы препроцессора

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

#define DEBUG

class MyClass

{

  int x;

  void Foo()

  {

      # if DEBUG

      Console.WriteLine («Testing: x = {0}», x);

      # endif

  }

}

В этом классе инструкции в методе Foo скомпилируются если определен символ DEBUG, а если его удалить — инструкции не скомпилируются. Символы препроцессора могут быть определены в исходном коде (как в примере), а могут быть переданы компилятору в командной строке с помощью параметра /define:symbol.

С директивами #if и #elif можно использовать операторы ||, && и ! с несколькими символами:

Директивы #error и #warning предотвращают некорректное использование условных директив, заставляя компилятор генерировать предупреждение или ошибку при передаче неверного набора символов.

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

  • условное включение атрибута
  • изменение типа, объявляемого для переменной
  • переключение между разными пространствами имен или псевдонимами типа в директиве using:

    using TestType =

      #if V2

          MyCompany.Widgets.GadgetV2;

      #else

          MyCompany.Widgets.Gadget;

      #endif

  • создавать новые версии кода и быстро переключаться между ними при компиляции
  • создавать библиотеки, компилируемые для разных версий .NET Framework

Полный список директив препроцессора:

  • #define symbol — определяет символ
  • #undef symbol — удаляет символ
  • #if symbol [оператор symbol2]... — условная компиляция; допустимые операторы ==, !=, && и ||
  • #else — выполняет код после #endif
  • #elif symbol [оператор symbol2] — объединяет #else и #if
  • #endif — конец условных директив
  • #warning text — текст предупреждения, которое появится в выдаче компилятора
  • #error text — текст ошибки, которая появится в выдаче компилятора
  • #line [число["файл"] | hidden]число указывает номер строки в исходном коде; файл — имя файла, которое появится в выдаче компилятора; hidden — дает указание дебагеру пропустить код от этой точки до следующей директивы #line
  • #region name — отмечает начало области
  • #endregion — отмечает конец области
  • #pragma warning

Pragma Warning

Компилятор генерирует предупреждения, когда что-то в коде ему кажется неуместным (но корректным). В отличии от ошибок предупреждения не препятствуют компиляции программы. Предупреждения компилятора могут быть очень полезны при поиске багов в программе. Однако часто предупреждения оказываются ложными, поэтому целесообразно иметь возможность получать предупреждения только о действительных багах. С этой целью компилятор дает возможность выборочно подавить предупреждения с помощью директивы #pragma warning.

public class Foo

{

  static void Main() { }

  #pragma warning disable 414

  static string Message = «Hello»;

  #pragma warning restore 414

}

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

Если не указывать номер директива #pragma warning отменит или восстановит вывод всех предупреждений.

Если скомпилировать программу с параметром /warnaserror, то все не отмененные директивой #pragma warning предупреждения будут расцениваться компилятором как ошибки.

Атрибут Conditional

Атрибут Conditional указывает компилятору на необходимость игнорировать все обращения к определенному классу или методу, если заданный символ не был определен:

[Conditional («LOGGINGMODE»)]

static void LogStatus (string msg)

{

  ...

}

Это равносильно тому, что каждый вызов метода будет окружен условными директивами:

#if LOGGINGMODE

LogStatus («Message Headers: « + GetMsgHeaders());

#endif

Классы Debug и Trace

Статические классы Debug и Trace предлагают базовые возможности логирования. Оба класса схожи, отличие заключается в их назанчении. Класс Debug предназначен для отладочных сборок, класс Trace — для отладочных и финальных. В связи с этим все методы класса Debug определены с атрибутом [Conditional("DEBUG")], а методы класса Trace — с атрибутом [Conditional("TRACE")]. Это значит, что все обращения к Debug и Trace будут подавляться компилятором, пока не определен символ DEBUG или TRACE.

Класс Debug и Trace определяют методы Write, WriteLine и WriteIf. По умолчанию они отправляют сообщения в окно вывода отладчика:

Debug.Write («Data»);

Debug.WriteLine (23 * 34);

int x = 5, y = 3;

Debug.WriteIf (x > y, «x is greater than y»);

Класс Trace также содержит методы TraceInformation, TraceWarning и TraceError. Их действия зависят от зарегистрированных прослушивателей.

TraceListener

Классы Debug и Trace имеют свойство Listeners, которое представляет собой статическую коллекцию экземпляров TraceListener. Они отвечают за обработку данных, возвращаемых методами Write, Fail и Trace.

По умолчанию коллекция Listeners обоих классов включает единственный прослушиватель — DefaultTraceListener — стандартный прослушиватель, имеющий две ключевые возможности:

  • при подключении к отладчику (например, Visual Studio) сообщения записываются в окно вывода отладчика, во всех остальных случаях сообщения игнорируются
  • при вызове метода Fail отображается диалоговое окно, запрашивающее у пользователя дальнейшие действия: продолжить, прервать или повторить отладку (независимо от того, подключен ли отладчик)

Это поведение можно изменить или дополнить, удалив (на обязательно) стандартный прослушиватель и/или добавив один или более собственных прослушивателей.

Прослушиваетли трассировки можно написать с нуля (создав производный класс от TraceListener) или воспользоваться готовыми классами:

  • TextWriterTraceListener записывает в Stream или TextWriter или добавляет в файл; имеет четыре подкласса: ConsoleTraceListener, DelimitedListTraceListener, XmlWriterTraceListener и EventSchemaTraceListener
  • EventLogTraceListener записывает в журнал событий Windows
  • EventProviderTraceListener записывает в систему трассировки событий Windows (Event Tracing for Windows — ETW)
  • WebPageTraceListener выводит на веб-страницу ASP.NET

Ни один из этих прослушивателе не отображает диалоговое окно при вызове Fail, это делает только DefaultTraceListener.

// Удалить стандартный прослушиватель, очистив коллекцию прослушивателей:

Trace.Listeners.Clear();

// Добавить средство записи в файл trace.txt:

Trace.Listeners.Add (new TextWriterTraceListener («trace.txt»));

// Добавит средство записи в консоль:

System.IO.TextWriter tw = Console.Out;

Trace.Listeners.Add (new TextWriterTraceListener (tw));

// Добавить средство записи в журнал событий Windows:

if (!EventLog.SourceExists («DemoApp»))

  EventLog.CreateEventSource («DemoApp», «Application»);

Trace.Listeners.Add (new EventLogTraceListener («DemoApp»));

В случае журнала событий Windows сообщения, отправляемые с помощью Write, Fail или Assert, записываются как сведения, а сообщения методов TraceWarning и TraceError записываются как предупреждения или ошибки.

Каждый экземпляр TraceListener имеет свойство Filter и TraceFilter, с помощью которых можно управлять, будет ли сообщение записано в этот прослушиватель. Для этого необходимо создать экземпляр классов EventTypeFilter или SourceFilter (производных от TraceFilter) или создать свой класс, наследующий от TraceFilter и переопределить в нем метод ShouldTrace.

В TraceListener также определены свойства IndentLevel и IndentSize для управления отступами и свойство TraceOutputOptions для записи дополнительных данных:

TextWriterTraceListener tl = new TextWriterTraceListener (Console.Out);

tl.TraceOutputOptions = TraceOptions.DateTime | TraceOptions.Callstack;

// Это применяется при использовании метода Trace:

Trace.TraceWarning («Orange alert»);

DiagTest.vshost.exe Warning: 0 : Orange alert

DateTime=20070308T05:57:13.6250000Z

Callstack= at System.Environment.GetStackTrace(Exception e, Boolean

needFileInfo)

at System.Environment.get_StackTrace() at ...

Прослушиватели, которые записывают данные в поток, кэшируются. По этой причине данные не появляются в потоке немедленно, а также поток перед завершением приложения должен быть закрыт, или хотя бы сброшен, чтоб не потерять данные в кэше. Для этой цели классы Trace и Debug содержат статические методы Close и Flush, которые вызывают Close и Flush во всех прослушивателях (а они в свою очередь закрывают или сбрасывают все потоки). Метод Close вызывает метод Flush, закрывает файловые дескрипторы и предотвращает дальнейшую запись.

Классы Trace и Debug также определяют свойство AutoFlush, которое если равно true вызывает Flush после каждого сообщения.

Fail и Assert

Классы Debug и Trace содержат методы Fail и Assert.

Метод Fail отправляет сообщения каждому TraceListener:

Debug.Fail («File data.txt does not exist!»);

Метод Assert вызывает Fail если аргумент типа bool равен false. Это называется созданием утверждения и указывает на ошибку, если оно нарушено. Можно также создать необязательное сообщение об ошибке:

Debug.Assert (File.Exists («data.txt»), «File data.txt does not exist!»);

var result = ...

Debug.Assert (result != null);

Методы Write, Fail и Assert также могут принимать категорию в виде строки ,которая может быть использована при обработке вывода.

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

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

#include<iostream>
#include<windows.h>
#include<fstream>
#include<conio.h>

using namespace std;       

class Player{
public:
    Player(){
        age =  exp = 0;
        name = "player";
        level = 1;
        balance = 3000;
        HP = 100;
        nxtLvl = 500;
        damage = 150;
    }
    Player(int age, string name):Player(){
        this->age = age;
        this->name = name;
    }
    Player(const Player &obj){
        age = obj.age;
        name = obj.name;
        level = obj.level;
        balance = obj.balance;
        HP = obj.HP;
        nxtLvl = obj.nxtLvl;
        damage = obj.damage;
        exp = obj.exp;
    }
    string getName(){return name;}
    int getAge(){return age;}
    int getLevel(){return level;}
    int getHP(){return HP;}
    int getBalance(){return balance;}
    int getNxt(){return nxtLvl;}
    int getDamage(){return damage;}
    void printHero(){
        cout << name << " " << age << " лет.n" << level << " lvl.n"
        << "Бабки: " << balance << "$nЗдоровье: " << HP << " ХПn" << "Сила удара: максимум " << damage << "nОпыт: " << exp << "/" <<nxtLvl << "n";
    }
    void upLevel(){
        ++level;
        nxtLvl = nxtLvl * 2 + (nxtLvl/2);
        damage += (damage/10);
        }
    void addExp(int exp){this->exp += exp;}
    void addHealth(int health){HP += health;}
    void remHealth(int health){HP -= health;}
    void addDamage(int damage){this->damage += damage;}
private:
    int age, level, balance, HP, exp, nxtLvl, damage;
    string name;
};

void Arena();
void myHero();
void Shop();
main(){
    setlocale(LC_ALL, "rus");

    Player me;

    string path = "game_saves.txt";
    ofstream fout;
    fout.open(path, ofstream::app);
    fout.close();

    ifstream fin;
    fin.open(path);

    if(!fin.read((char*)&me, sizeof(Player))){
        cout << "Введите ваше имя:n";
        string name;
        cin >> name;
        system("cls");
        cout << "Введите сколько вам лет:n";
        int age;
        cin >> age;
        me = Player(age, name);
        ofstream fout;
        fout.open(path);
        fout.write((char*)&me, sizeof(Player));
        fout.close();
    }
    fin.close();
    system("cls");
     //int l; cin >> l;
    cout << "Hello " << me.getName() << "!n";

    cout << ">Новая играn Продолжить игруn";
    char c;
    int choose = 1;
    while(c != 13){
        c = _getch();
        if(c == 72){
            system("cls");
            cout << "Hello " << me.getName() << "!n";
            cout << ">Новая играn Продолжить игруn";
            choose = 1;
        }
        if(c == 80){
            system("cls");
            cout << "Hello " << me.getName() << "!n";
            cout << " Новая играn>Продолжить игруn";
            choose = 2;
        }
    }
    if(choose == 1){
        system("cls");
        cout << "Введите ваше имя:n";
        string name;
        cin >> name;

        cout << "Введите сколько вам лет:n";
        int age;
        cin >> age;
        ofstream fout;
        fout.open(path);
        fout.write((char*)&me, sizeof(Player));
        fout.close();
    }
    else{
        system("cls");
        cout << ">Аренаn Мой геройn Магазинn";
        char k='a';
        char vote = 1;
        while(k != 13){
            k = _getch();
            if(k == 72){
                system("cls");
                if(vote == 2){
                    cout << ">Аренаn Мой геройn Магазинn";
                    vote = 1;
                }
                if(vote == 3){
                    cout << " Аренаn>Мой геройn Магазинn";
                    vote = 2;
                }
            }
            if(k == 80){
                system("cls");
                if(vote == 1){
                    cout << " Аренаn>Мой геройn Магазинn";
                    vote = 2;
                }
                else{
                    cout << " Аренаn Мой геройn>Магазинn";
                    vote = 3;
                }
            }
        }
      /* if(vote == 1) Arena();
        if(vote == 2) myHero();
        if(vote == 3) Shop();*/    
    }    
}

void Arena(){    
}

Буду рад помощи. Прошу не ругаться, я начал изучать ООП и работу с файлами только позавчера.

Большинство компьютерных программ работают с файлами, и поэтому возникает необходимость создавать, удалять, записывать читать, открывать файлы. Что же такое файл? Файл – именованный набор  байтов, который может быть сохранен на некотором накопителе. Ну, теперь ясно, что под файлом понимается некоторая последовательность байтов, которая имеет своё, уникальное имя, например файл.txt. В одной директории  не могут находиться файлы с одинаковыми именами. Под именем файла понимается не только его название, но и расширение, например: file.txt  и file.dat — разные файлы, хоть и имеют одинаковые названия. Существует такое понятие, как полное имя файлов – это полный адрес к директории файла с указанием имени файла, например: D:docsfile.txt. Важно понимать эти базовые понятия, иначе сложно будет работать с файлами.

Для работы с файлами необходимо подключить заголовочный файл <fstream>В <fstream> определены несколько классов и подключены заголовочные файлы <ifstream> — файловый ввод и  <ofstream>  — файловый вывод.

Файловый ввод/вывод аналогичен стандартному вводу/выводу, единственное отличие – это то, что ввод/вывод выполнятся не на экран, а в файл. Если ввод/вывод на стандартные устройства выполняется с помощью объектов cin и cout, то для организации файлового ввода/вывода достаточно создать собственные объекты, которые можно использовать аналогично операторам cin и cout.

Например, необходимо создать текстовый файл и записать в него строку Работа с файлами в С++. Для этого необходимо проделать следующие шаги:

  1. создать объект класса ofstream;
  2. связать объект класса с файлом, в который будет производиться запись;
  3. записать строку в файл;
  4. закрыть файл.

Почему необходимо создавать объект класса ofstream, а не класса ifstream? Потому, что нужно сделать запись в файл, а если бы нужно было считать данные из файла, то создавался бы объект класса ifstream.

// создаём объект для записи в файл
ofstream /*имя объекта*/; // объект класса ofstream

Назовём объект – fout, Вот что получится:

ofstream fout;

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

fout.open("cppstudio.txt"); // связываем объект с файлом

Через операцию точка получаем доступ к методу класса open(), в круглых скобочках которого указываем имя файла. Указанный файл будет создан в текущей директории с программой. Если файл с таким именем существует, то существующий файл будет заменен новым. Итак, файл открыт, осталось записать в него нужную строку. Делается это так:

fout << "Работа с файлами в С++"; // запись строки в файл

Используя операцию передачи в поток совместно с объектом fout строка Работа с файлами в С++ записывается в файл. Так как больше нет необходимости изменять содержимое файла, его нужно закрыть, то есть отделить объект от файла.

fout.close(); // закрываем файл

Итог – создан файл со строкой Работа с файлами в С++.

Шаги 1 и 2 можно объединить, то есть в одной строке создать объект и связать его с файлом. Делается это так:

ofstream fout("cppstudio.txt"); // создаём объект класса ofstream и связываем его с файлом cppstudio.txt

Объединим весь код и получим следующую программу.

// file.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"
#include <fstream>
using namespace std;

int main(int argc, char* argv[])
{
    ofstream fout("cppstudio.txt"); // создаём объект класса ofstream для записи и связываем его с файлом cppstudio.txt
    fout << "Работа с файлами в С++"; // запись строки в файл
    fout.close(); // закрываем файл
    system("pause");
    return 0;
}

Осталось проверить правильность работы программы, а для этого открываем файл cppstudio.txt и смотрим его содержимое, должно быть — Работа с файлами в С++.

Для того чтобы прочитать файл понадобится выполнить те же шаги, что и при записи в файл с небольшими изменениями:

  1. создать объект класса ifstream и связать его с файлом, из которого будет производиться считывание;
  2. прочитать файл;
  3. закрыть файл.
// file_read.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "rus"); // корректное отображение Кириллицы
    char buff[50]; // буфер промежуточного хранения считываемого из файла текста
    ifstream fin("cppstudio.txt"); // открыли файл для чтения

    fin >> buff; // считали первое слово из файла
    cout << buff << endl; // напечатали это слово

    fin.getline(buff, 50); // считали строку из файла
    fin.close(); // закрываем файл
    cout << buff << endl; // напечатали эту строку

    system("pause");
    return 0;
}

В программе показаны два способа чтения из файла, первый – используя операцию передачи в поток, второй – используя функцию getline(). В первом случае считывается только первое слово, а во втором случае считывается строка, длинной 50 символов. Но так как в файле осталось меньше 50 символов, то считываются символы включительно до последнего. Обратите внимание на то, что считывание во второй раз (строка 17) продолжилось, после первого слова, а не с начала, так как первое слово было прочитано в строке 14. Результат работы программы показан на рисунке 1.

CppStudio.com

Работа
 с файлами в С++
Для продолжения нажмите любую клавишу . . .

Рисунок 1 — Работа с файлами в С++

Программа сработала правильно, но не всегда так бывает, даже в том случае, если с кодом всё впорядке. Например, в программу передано имя несуществующего файла или в имени допущена ошибка. Что тогда? В этом случае ничего не произойдёт вообще. Файл не будет найден, а значит и прочитать его не возможно. Поэтому компилятор проигнорирует строки, где выполняется работа с файлом. В результате корректно завершится работа программы, но ничего, на экране показано не будет. Казалось бы это вполне нормальная реакции на такую ситуацию. Но простому пользователю не будет понятно, в чём дело и почему на экране не появилась строка из файла. Так вот, чтобы всё было предельно понятно в С++ предусмотрена такая функция — is_open(), которая возвращает целые значения: 1 — если файл был успешно открыт, 0 — если файл открыт не был. Доработаем программу с открытием файла, таким образом, что если файл не открыт выводилось соответствующее сообщение.

// file_read.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "rus"); // корректное отображение Кириллицы
    char buff[50]; // буфер промежуточного хранения считываемого из файла текста
    ifstream fin("cppstudio.doc"); // (ВВЕЛИ НЕ КОРРЕКТНОЕ ИМЯ ФАЙЛА)

    if (!fin.is_open()) // если файл не открыт
        cout << "Файл не может быть открыт!n"; // сообщить об этом
    else
    {
    fin >> buff; // считали первое слово из файла
    cout << buff << endl; // напечатали это слово

    fin.getline(buff, 50); // считали строку из файла
    fin.close(); // закрываем файл
    cout << buff << endl; // напечатали эту строку
    }
    system("pause");
    return 0;
}

Результат работы программы показан на рисунке 2.

CppStudio.com

Файл не может быть открыт!
Для продолжения нажмите любую клавишу . . .

Рисунок 2 — Работа с файлами в С++

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

Режимы открытия файлов

Режимы открытия файлов устанавливают характер использования файлов. Для установки режима в классе ios_base предусмотрены константы, которые определяют режим открытия файлов (см. Таблица 1).

Таблица 1 — режимы открытия файлов

Константа Описание
ios_base::in открыть файл для чтения
ios_base::out открыть файл для записи
ios_base::ate при открытии переместить указатель в конец файла
ios_base::app открыть файл для записи в конец файла
ios_base::trunc удалить содержимое файла, если он существует
ios_base::binary открытие файла в двоичном режиме

Режимы открытия файлов можно устанавливать непосредственно при создании объекта или при вызове функции open().

ofstream fout("cppstudio.txt", ios_base::app); // открываем файл для добавления информации к концу файла
fout.open("cppstudio.txt", ios_base::app); // открываем файл для добавления информации к концу файла

Режимы открытия файлов можно комбинировать с помощью поразрядной логической операции или |, например: ios_base::out | ios_base::trunc — открытие файла для записи, предварительно очистив его.

Объекты класса ofstream, при связке с файлами по умолчанию содержат режимы открытия файлов  ios_base::out | ios_base::truncТо есть файл будет создан, если не существует. Если же файл существует, то его содержимое будет удалено, а сам файл будет готов к записи. Объекты класса ifstream связываясь с файлом, имеют по умолчанию режим открытия файла   ios_base::in  — файл открыт только для чтения. Режим открытия файла ещё называют — флаг, для удобочитаемости в дальнейшем будем использовать именно этот термин. В таблице 1 перечислены далеко не все флаги, но для начала этих должно хватить.

Обратите внимание на то, что флаги ate и app по описанию очень похожи, они оба перемещают указатель в конец файла, но флаг app позволяет производить запись, только в конец файла, а флаг ate просто переставляет флаг в конец файла и не ограничивает места записи.

Разработаем программу, которая, используя операцию sizeof(), будет вычислять характеристики основных типов данных в С++ и записывать их в файл. Характеристики:

  1. число байт, отводимое под тип данных
  2. максимальное значение, которое может хранить определённый тип данных.

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

/*  data type      byte          max value  
bool               =  1         255.00
char               =  1         255.00
short int          =  2         32767.00
unsigned short int =  2         65535.00
int                =  4         2147483647.00
unsigned int       =  4         4294967295.00
long int           =  4         2147483647.00
unsigned long int  =  4         4294967295.00
float              =  4         2147483647.00
long float         =  8         9223372036854775800.00
double             =  8         9223372036854775800.00  */

Такая программа уже разрабатывалась ранее в разделе Типы данных С++ , но там вся информация о типах данных выводилась на стандартное устройство вывода, а нам необходимо программу переделать так, чтобы информация записывалась в файл. Для этого необходимо открыть файл в режиме записи, с предварительным усечением текущей информации файла (строка 14). Как только файл создан и успешно открыт (строки 16 — 20), вместо оператора cout, в строке 22 используем объект fout. таким образом, вместо экрана информация о типах данных запишется в файл.

// write_file.cpp: определяет точку входа для консольного приложения.

#include "stdafx.h"
#include <iostream>
#include <fstream> // работа с файлами
#include <iomanip> // манипуляторы ввода/вывода
using namespace std;

int main(int argc, char* argv[])
{
    setlocale(LC_ALL, "rus");

    // связываем объект с файлом, при этом файл открываем в режиме записи, предварительно удаляя все данные из него
    ofstream fout("data_types.txt", ios_base::out | ios_base::trunc); 

    if (!fout.is_open()) // если файл небыл открыт 
    { 
     cout << "Файл не может быть открыт или созданn"; // напечатать соответствующее сообщение
     return 1; // выполнить выход из программы
    }

        fout << "     data type      "   << "byte"                      << "      "    << "    max value  " << endl // заголовки столбцов
             << "bool               =  " << sizeof(bool)                << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных bool*/                           << (pow(2,sizeof(bool) * 8.0) - 1)               << endl
         << "char               =  " << sizeof(char)                << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных char*/                           << (pow(2,sizeof(char) * 8.0) - 1)               << endl
         << "short int          =  " << sizeof(short int)           << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных short int*/                      << (pow(2,sizeof(short int) * 8.0 - 1) - 1)      << endl
             << "unsigned short int =  " << sizeof(unsigned short int)  << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных unsigned short int*/             << (pow(2,sizeof(unsigned short int) * 8.0) - 1) << endl
             << "int                =  " << sizeof(int)                 << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных int*/                            << (pow(2,sizeof(int) * 8.0 - 1) - 1)            << endl
             << "unsigned int       =  " << sizeof(unsigned int)        << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных unsigned int*/                   << (pow(2,sizeof(unsigned int) * 8.0) - 1)       << endl
             << "long int           =  " << sizeof(long int)            << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных long int*/                       << (pow(2,sizeof(long int) * 8.0 - 1) - 1)       << endl
             << "unsigned long int  =  " << sizeof(unsigned long int)   << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных undigned long int*/              << (pow(2,sizeof(unsigned long int) * 8.0) - 1)  << endl
             << "float              =  " << sizeof(float)               << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных float*/                          << (pow(2,sizeof(float) * 8.0 - 1) - 1)          << endl
             << "long float         =  " << sizeof(long float)          << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных long float*/                     << (pow(2,sizeof(long float) * 8.0 - 1) - 1)     << endl
             << "double             =  " << sizeof(double)              << "         " << fixed << setprecision(2) 
/*вычисляем максимальное значение для типа данных double*/                         << (pow(2,sizeof(double) * 8.0 - 1) - 1)         << endl;
        fout.close(); // программа больше не использует файл, поэтому его нужно закрыть
    cout << "Данные успешно записаны в файл data_types.txtn";
    system("pause");
    return 0;
}

Нельзя не заметить, что изменения в программе минимальны, а всё благодаря тому, что стандартный ввод/вывод и файловый ввод/вывод используются абсолютно аналогично. В конце программы, в строке 45 мы явно закрыли файл, хотя это и не обязательно, но считается хорошим тоном программирования. Стоит отметить, что все функции и манипуляторы используемые для форматирования стандартного ввода/вывода актуальны и для файлового ввода/вывода. Поэтому не возникло никаких ошибок, когда оператор cout был заменён объектом fout.

При открытии файла при помощи wifstream программа крашится и выдает такую ошибку. Файл формата txt существует и путь к нему указан верно. Может у кого нибудь была похожая проблема?
5b0d6a89ddd7f213939101.png
Код функции main:

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
	//setlocale(LC_ALL, "rus");
	wifstream nja(L"text1.txt");
	if (!nja.is_open())
		cout<<"Ошибка!";
	Parm::PARM parm;
	cout << argc;
	cout << "---- Тест Error::geterror   ---" << endl << endl;
	try { ERROR_THROW(104); }
	catch (Error::ERROR e)
	{
		cout << "Ошибка " << e.id << ": " << e.message << endl << endl;
	};

	cout << "---- Тест Error::geterrorin   ---" << endl << endl;
	try { ERROR_THROW_IN(111, 7, 7); }
	catch (Error::ERROR e)
	{
		cout << "Ошибка " << e.id << ": " << e.message
			<< ", строка " << e.inext.line
			<< ", позиция " << e.inext.col << endl << endl;
	};

	cout << "---- Тест Parm::getparm   ---" << endl << endl;
	try
	{
		parm = Parm::getparm(argc, argv);
		wcout << L"-in:" << parm.in << L", -out:" << parm.out << L", -log:" << parm.log << endl << endl;
	}
	catch (Error::ERROR e)
	{
		cout << "Ошибка " << e.id << ": " << e.message << endl << endl;
	};
	cout << "---- Тест Parm::getin   ---" << endl << endl;
	try
	{
		In::IN in = In::getin(parm.in);
		cout << in.text << endl;
		cout << "Всего символов: " << in.size << endl;
		cout << "Всего строк: " << in.lines << endl;
		cout << "Пропущено: " << in.ignor << endl;
	}
	catch (Error::ERROR e)
	{
		cout << "Ошибка " << e.id << ": " << e.message << endl << endl;
	};
	system("pause");
	return 0;
}

Содержимое stdafx.h:
#pragma once

#include "targetver.h"

#include <fstream>
#include <iostream>
#include <tchar.h>
#include <stdio.h>
#include <cwchar>
#include <stdio.h>
#include <cstring>
#include <wchar.h>
#include <locale>

#include "Error.h"
#include "Parm.h"
#include "In.h"

using namespace std;

Понравилась статья? Поделить с друзьями:
  • Ошибка при включении камеры на сони
  • Ошибка при взаимодействии с сервисом маркировки сигма
  • Ошибка при включении камеры на ноутбуке
  • Ошибка при взаимодействии с сервером mydss
  • Ошибка при включении камеры на xiaomi