Construction of the path of rays in a prism. Path of rays in a triangular prism

For ease of access, information in storage devices is stored in the form of files.

A file is a named area of ​​external memory allocated for storing an array of data. The data contained in the files is of a very diverse nature: programs in algorithmic or machine language; initial data for program operation or program execution results; free texts; graphic images, etc.

Directory (folder, directory) - a named collection of bytes on a storage medium containing the names of subdirectories and files, used in the file system to simplify the organization of files.

File system called the functional part of the operating system that performs operations on files. Examples of file systems are FAT (FAT – File Allocation Table), NTFS, UDF (used on CDs).

There are three main versions of FAT: FAT12, FAT16 and FAT32. They differ in the bit depth of records in the disk structure, i.e. the number of bits allocated to store the cluster number. FAT12 is used mainly for floppy disks (up to 4 KB), FAT16 - for small-capacity disks, FAT32 - for high-capacity FLASH drives (up to 32 GB).

Let's look at the structure of the file system using FAT32 as an example.

FAT32 file structure

External memory devices in the FAT32 system have block addressing rather than byte addressing. Information is written to an external memory device in blocks or sectors.

A sector is the minimum addressable unit of information storage on external storage devices. Typically, the sector size is fixed at 512 bytes. To increase the address space of external memory devices, sectors are combined into groups called clusters.

A cluster is an association of several sectors, which can be considered as an independent unit with certain properties. The main property of a cluster is its size, measured in the number of sectors or number of bytes.

The FAT32 file system has the following structure.

The clusters used for writing files are numbered starting from 2. As a rule, cluster No. 2 is used by the root directory, and starting from cluster No. 3 the data array is stored. Sectors used to store information above the root directory are not clustered.
The minimum file size required on disk corresponds to 1 cluster.

The boot sector begins with the following information:

  • EB 58 90 – unconditional jump and signature;
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
  • 00 02 – number of bytes in the sector (usually 512);
  • 1 byte – number of sectors in the cluster;
  • 2 bytes – number of reserve sectors.

In addition, the boot sector contains the following important information:

  • 0x10 (1 byte) – number of FAT tables (usually 2);
  • 0x20 (4 bytes) – number of sectors on the disk;
  • 0x2С (4 bytes) – cluster number of the root directory;
  • 0x47 (11 bytes) – volume label;
  • 0x1FE (2 bytes) – boot sector signature (55 AA).

The file system information sector contains:

  • 0x00 (4 bytes) – signature (52 52 61 41);
  • 0x1E4 (4 bytes) – signature (72 72 41 61);
  • 0x1E8 (4 bytes) – number of free clusters, -1 if unknown;
  • 0x1EC (4 bytes) – number of the last recorded cluster;
  • 0x1FE (2 bytes) – signature (55 AA).

The FAT table contains information about the state of each cluster on the disk. The lower 2 bytes of the FAT table store F8 FF FF 0F FF FF FF FF (which corresponds to the state of clusters 0 and 1, which are physically absent). Further, the state of each cluster contains the number of the cluster in which the current file continues or the following information:

  • 00 00 00 00 – cluster is free;
  • FF FF FF 0F – end of the current file.
  • 8 bytes – file name;
  • 3 bytes – file extension;

The root directory contains a set of 32-bit information records about each file, containing the following information:

In case of working with long names files (including Russian names), the file name is encoded in the UTF-16 encoding system. In this case, 2 bytes are allocated for encoding each character. In this case, the file name is written in the following structure:

  • 1 sequence byte;
  • 10 bytes contain the lower 5 characters of the file name;
  • 1 byte attribute;
  • 1 byte reserved;
  • 1 byte – DOS name checksum;
  • 12 bytes contain the lower 3 characters of the file name;
  • 2 bytes – number of the first cluster;
  • the remaining characters of the long name.

Working with files in C language

To the programmer, an open file is represented as a sequence of data being read or written. When a file is opened, it is associated with I/O stream. Output information is written to the stream, input information is read from the stream.

When a stream is opened for I/O, it is associated with a standard FILE structure, which is defined in stdio.h. The FILE structure contains the necessary information about the file.

Opening a file is done using the fopen() function, which returns a pointer to a FILE structure that can be used for subsequent operations on the file.

FILE *fopen(name, type);


name – name of the file to open (including path),
type is a pointer to a string of characters that define how the file is accessed:
  • "r" - open the file for reading (the file must exist);
  • "w" - open an empty file for writing; if the file exists, its contents are lost;
  • "a" - open the file for writing to the end (for appending); the file is created if it does not exist;
  • "r+" - open the file for reading and writing (the file must exist);
  • "w+" - open an empty file for reading and writing; if the file exists, its contents are lost;
  • "a+" - open the file for reading and appending; if the file does not exist, then it is created.

The return value is a pointer to the open stream. If an error is encountered, NULL is returned.

The fclose() function closes the stream or streams associated with files opened using the fopen() function. The stream to be closed is determined by the argument of the fclose() function.

Return value: value 0 if the stream was closed successfully; constant EOF if an error occurred.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include
int main() (
FILE *fp;
char name = "my.txt" ;
if ((fp = fopen(name, "r" )) == NULL )
{
printf( "Failed to open file");
getchar();
return 0;
}
// succeeded in opening the file
... // required actions on data
fclose(fp);
getchar();
return 0;
}

Reading a character from a file:

char fgetc(stream);


The function argument is a pointer to a stream of type FILE. The function returns the code of the read character. If the end of the file is reached or an error occurs, the constant EOF is returned.

Writing a symbol to a file:

fputc(char, stream);

The function's arguments are a character and a pointer to a stream of type FILE. The function returns the code of the read character.

The fscanf() and fprintf() functions are similar to the scanf() and printf() functions, but work with data files, and have a file pointer as their first argument.

fscanf(stream, "InputFormat", arguments);

Previously, when inputting and outputting data, we worked with standard streams - the keyboard and monitor. Now let's look at how the C language implements receiving data from files and writing them there. Before you can perform these operations, you must open the file and access it.

In the C programming language, a pointer to a file is of type FILE and its declaration looks like this:
FILE *myfile;

On the other hand, the fopen() function opens a file at the address specified as the first argument in read mode ("r"), write mode ("w"), or append mode ("a") and returns a pointer to it to the program. Therefore, the process of opening a file and connecting it to the program looks something like this:
myfile = fopen("hello.txt", "r");

When reading or writing data to a file, it is accessed through a file pointer (in this case, myfile).

If for one reason or another (there is no file at the specified address, access to it is denied) the fopen() function cannot open the file, then it returns NULL. In real programs, they almost always handle a file opening error in the if branch, but we will omit this further.

The fopen() function declaration is contained in the stdio.h header file, so it must be included. Also in stdio.h the structure type FILE is declared.

After working with a file is finished, it is customary to close it to free the buffer from data and for other reasons. This is especially important if the program continues to run after working with the file. Breaking the connection between an external file and a pointer to it from the program is done using the fclose() function. A pointer to the file is passed to it as a parameter:
fclose(myfile);

More than one file can be opened in the program. In this case, each file must be associated with its own file pointer. However, if the program first works with one file and then closes it, then the pointer can be used to open a second file.

Reading from and writing to a text file

fscanf()

The fscanf() function is similar in meaning to the scanf() function, but unlike it, it provides formatted input from a file rather than the standard input stream. The fscanf() function takes parameters: file pointer, format string, addresses of memory areas for writing data:
fscanf(myfile, "%s%d", str, &a);

Returns the number of successfully read data or EOF. Spaces and newline characters are counted as data delimiters.

Let's say we have a file containing the following description of objects:

Apples 10 23.4 bananas 5 25.0 bread 1 10.3

#include main () ( FILE * file; struct food ( char name[ 20 ] ; unsigned qty; float price; ) ; struct food shop[ 10 ] ; char i= 0 ; file = fopen ( "fscanf.txt" , "r" ) ; while (fscanf (file, "%s%u%f" , shop[ i].name , & (shop[ i].qty ) , & (shop[ i].price ) != EOF) ( printf ("%s %u %.2f \n", shop[ i].name, shop[ i].qty, shop[ i].price) ; i++; ) )

In this case, a structure and an array of structures are declared. Each line from the file corresponds to one element of the array; an array element is a structure containing a string and two numeric fields. The loop reads one row per iteration. When the end of file is encountered, fscanf() returns EOF and the loop ends.

fgets()

The fgets() function is similar to the gets() function and performs line-by-line input from a file. One call to fgets() will read one line. In this case, you can not read the entire line, but only part of it from the beginning. fgets() parameters look like this:
fgets (character_array, number_of_characters_read, pointer_to_file)

For example:
fgets(str, 50, myfile)

This function call will read from the file associated with the myfile pointer one full line of text if its length is less than 50 characters, including the "\n" character, which the function will also store in an array. The last (50th) element of the str array will be the "\0" character added by fgets() . If the string is longer, the function will read 49 characters and write "\0" at the end. In this case, "\n" will not be contained in the read line.

#include #define N 80 main () ( FILE * file; char arr[ N] ; file = fopen ("fscanf.txt" , "r" ) ; while (fgets (arr, N, file) != NULL) printf (" %s" , arr) ; printf (" \n") ; fclose(file); )

In this program, unlike the previous one, the data is read line by line into the arr array. When the next line is read, the previous one is lost. The fgets() function returns NULL if it cannot read the next line.

getc() or fgetc()

The getc() or fgetc() function (both work) allows you to get the next single character from a file.

while ((arr[ i] = fgetc (file) ) != EOF) ( if (arr[ i] == " \n") (arr[i] = " \0 " ; printf("%s \n", arr) ; i = 0 ; ) else i++; )arr[i] = " \0 " ; printf("%s \n", arr) ;

The example code displays data from a file on the screen.

Writing to a text file

Just like input, output to a file can be different.

  • Formatted output. Function fprintf (file_index, format_string, variables) .
  • Post-by-line output. Function fputs(string, file_pointer) .
  • Character-by-character output. Function fputc() or putc(symbol, file_pointer) .

Below are code examples that use three methods of outputting data to a file.

Writing fields of one structure to each line of the file:

file = fopen ("fprintf.txt" , "w" ) ; while (scanf ("%s%u%f" , shop[ i].name , & (shop[ i].qty ) , & (shop[ i].price ) ) != EOF) ( fprintf (file, " %s %u %.2f \n", shop[ i].name, shop[ i].qty, shop[ i].price) ; i++; )

Line-by-line output to a file (fputs(), unlike puts() itself, does not place “\n” at the end of the line):

while (gets (arr) != NULL) ( fputs (arr, file); fputs (" \n", file); )

Example of character-by-character output:

while ((i = getchar () ) != EOF) putc (i, file) ;

Reading from and writing to a binary file

You can work with a file not as a sequence of characters, but as a sequence of bytes. In principle, it is not possible to work with non-text files any other way. However, this can also be used to read and write to text files. The advantage of this method of accessing a file is the read-write speed: a significant block of information can be read/written in one access.

When opening a file for binary access, the second parameter to fopen() is the string "rb" or "wb".

The topic of working with binary files is quite complex and requires a separate lesson to study it. Here only the features of the functions of reading and writing to a file, which is considered as a byte stream, will be noted.

The fread() and fwrite() functions take as parameters:

  1. address of the memory area where data is written or read from,
  2. the size of one given type,
  3. the amount of data read of the specified size,
  4. file index.

These functions return the number of data successfully read or written. Those. you can “order” the reading of 50 data elements, but receive only 10. There will be no error.

An example of using the fread() and fwrite() functions:

#include #include main () ( FILE * file; char shelf1[ 50 ], shelf2[ 100 ] ; int n, m; file = fopen ("shelf1.txt" , "rb" ) ; n= fread (shelf1, sizeof (char ) , 50 , file) ; fclose (file) ; file = fopen ("shelf2.txt" , "rb" ) ; m= fread (shelf2, sizeof (char ) , 50 , file) ; = " \0 " ; shelf2[m] = " \n"; shelf2[ m+ 1 ] = " \0 " ; file = fopen ("shop.txt" , "wb" ) ; fwrite (strcat (shelf2, shelf1) , sizeof (char ) , n+ m, file) ; fclose(file); )

Here an attempt is made to read 50 characters from the first file. n stores the number of characters actually read. The value of n can be 50 or less. The data is placed in a row. The same thing happens with the second file. Next, the first line is appended to the second, and the data is dumped into the third file.

Problem solving

  1. Write a program that asks the user for the name (address) of a text file, then opens it and counts the number of characters and lines in it.
  2. Write a program that writes to a file data received from another file and modified in some way before writing. Each line of data obtained from a file must fit into a structure.

Tags: Text files, fopen, fclose, feof, setbuf, setvbuf, fflush, fgetc, fprintf, fscanf, fgets, buffered stream, unbuffered stream.

Working with text files

Working with a text file is similar to working with the console: using formatted input functions we save data to a file, using formatted output functions we read data from a file. There are many nuances that we will look at later. The main operations that need to be done are

  • 1. Open the file so that it can be accessed. Accordingly, you can open it for reading, writing, reading and writing, rewriting or writing to the end of the file, etc. When you open a file, a bunch of errors can also happen - the file may not exist, it may be the wrong file type, you may not have permission to work with the file, etc. All this must be taken into account.
  • 2. Directly working with the file - writing and reading. Here we also need to remember that we are not working with random access memory, but with a buffered stream, which adds its own specifics.
  • 3. Close the file. Since the file is a resource external to the program, if it is not closed, it will continue to hang in memory, possibly even after the program is closed (for example, it will not be possible to delete an open file or make changes, etc.). In addition, sometimes it is necessary not to close, but to “re-open” a file in order, for example, to change the access mode.

In addition, there are a number of tasks when we do not need to access the contents of the file: renaming, moving, copying, etc. Unfortunately, the C standard does not contain a description of functions for these needs. They are, of course, available for each of the compiler implementations. Reading the contents of a directory (folder, directory) is also accessing a file, because the folder itself is a file with metainformation.

Sometimes it is necessary to perform some auxiliary operations: move to the desired location in the file, remember current situation, determine the file length, etc.

To work with a file, you need a FILE object. This object stores the file stream's identifier and information needed to manage it, including a pointer to its buffer, a file position indicator, and status indicators.

The FILE object is itself a structure, but its fields should not be accessed. The portable program must treat the file as an abstract object that allows access to the file stream.

Creation and allocation of memory for an object of type FILE is carried out using the fopen or tmpfile function (there are others, but we will only focus on these).

The fopen function opens a file. It receives two arguments - a string with the file address and a string with the file access mode. The file name can be either absolute or relative. fopen returns a pointer to a FILE object that can be used to further access the file.

FILE* fopen(const char* filename, const char* mode);

For example, let's open a file and write Hello World into it

#include #include #include void main() ( //Using the file variable we will access the file FILE *file; //Open a text file with write permissions file = fopen("C:/c/test.txt", "w+t") ; //Write to the file fprintf(file, "Hello, World!"); //Close the file fclose(file);

The fopen function itself allocates memory for the object; cleaning is carried out by the fclose function. It is necessary to close the file; it will not close on its own.

The fopen function can open a file in text or binary mode. The default is text. The access mode can be as follows

File access options.
Type Description
r Reading. The file must exist.
w Write a new file. If a file with the same name already exists, its contents will be lost.
a Write to the end of the file. Positioning operations (fseek, fsetpos, frewind) are ignored. The file is created if it did not exist.
r+ Reading and updating. You can both read and write. The file must exist.
w+ Recording and updating. A new file is created. If a file with the same name already exists, its contents will be lost. You can both write and read.
a+ End post and update. Positioning operations are read-only and ignored for writes. If the file did not exist, a new one will be created.

If it is necessary to open the file in binary mode, then the letter b is added to the end of the line, for example “rb”, “wb”, “ab”, or, for mixed mode, “ab+”, “wb+”, “ab+”. Instead of b, you can add the letter t, then the file will open in text mode. It depends on the implementation. In the new C standard (2011), the letter x means that fopen should fail if the file already exists. Let's complement our old program: Let's re-open the file and consider what we wrote there.

#include #include #include void main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); fclose(file); file = fopen("C:/c/test.txt", "r"); fgets(buffer, 127, file); printf("%s", buffer(file);

Instead of the fgets function, you could use fscanf, but you need to remember that it can only read the line up to the first space.
fscanf(file, "%127s", buffer);

Also, instead of opening and closing a file, you can use the freopen function, which “re-opens” the file with new access rights.

#include #include #include void main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); fprintf(file, "Hello, World!"); freopen("C:/ c/test.txt", "r", file); fgets(buffer, 127, file); printf("%s", buffer); fclose(file); getch(); )

The functions fprintf and fscanf differ from printf and scanf only in that they take as their first argument a pointer to the FILE to which they will output or from which they will read data. It’s worth adding right away that the printf and scanf functions can be easily replaced by the fprintf and fscanf functions. In the OS (we consider the most common and adequate operating systems) there are three standard streams: standard output stdout, standard input stdin and standard error output stderr. They are automatically opened when the application is launched and are associated with the console. Example

#include #include #include void main() ( int a, b; fprintf(stdout, "Enter two numbers\n"); fscanf(stdin, "%d", &a); fscanf(stdin, "%d", &b); if (b == 0) ( fprintf(stderr, "Error: divide by zero"); ) else ( fprintf(stdout, "%.3f", (float) a / (float) b); ) getch();

Error opening file

If the fopen function call fails, it will return NULL. Errors while working with files occur quite often, so every time we open a file, we need to check the result of the work

#include #include #include #define ERROR_OPEN_FILE -3 void main() ( FILE *file; char buffer; file = fopen("C:/c/test.txt", "w"); if (file == NULL) ( printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); ) fprintf(file, "Hello, World!"); freopen("C:/c/test.txt", "r", file); if (file = = NULL) ( printf("Error opening file"); getch(); exit(ERROR_OPEN_FILE); ) fgets(buffer, 127, file); printf("%s", buffer(file); ; )

The problem arises when several files are opened at once: if one of them cannot be opened, then the rest must also be closed

FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile = fopen(INPUT_FILE, READ_ONLY); if (inputFile == NULL) ( printf("Error opening file %s", INPUT_FILE); getch(); exit(3); ) outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) ( printf("Error opening file %s", OUTPUT_FILE); getch(); if (inputFile != NULL) ( fclose(inputFile); ) exit(4); ) ...

IN simple cases you can act head-on, as in the previous piece of code. In more difficult cases methods are used that replace RAII from C++: wrappers, or compiler features (cleanup in GCC), etc.

Data Buffering

As mentioned earlier, when we output data, it is first placed in a buffer. The buffer is cleared

  • 1) If it is full
  • 2) If the stream is closed
  • 3) If we explicitly indicate that it is necessary to clear the buffer (there are exceptions here too :)).
  • 4) Also cleared if the program completed successfully. At the same time, all files are closed. In case of a runtime error, this may not happen.

You can force buffer unloading by calling the fflush(File *) function. Let's look at two examples - with and without cleaning.

#include #include #include void main() ( FILE *file; char c; file = fopen("C:/c/test.txt", "w"); do ( c = getch(); fprintf(file, "%c", c ); fprintf(stdout, "%c", c); //fflush(file); while(c != "q");

Uncomment the fflush call. At runtime, open the text file and look at the behavior.

You can assign a file buffer yourself by setting your own size. This is done using the function

Void setbuf(FILE * stream, char * buffer);

which takes an already open FILE and a pointer to a new buffer. The size of the new buffer must be no less than BUFSIZ (for example, on the current workstation BUFSIZ is 512 bytes). If you pass NULL as a buffer, the stream becomes unbuffered. You can also use the function

Int setvbuf(FILE * stream, char * buffer, int mode, size_t size);

which accepts a buffer of arbitrary size size. The mode can take the following values

  • _IOFBF- full buffering. Data is written to the file when it is full. On a read, the buffer is considered full when an input operation is requested and the buffer is empty.
  • _IOLBF- linear buffering. Data is written to the file when it is full or when a newline character is encountered. On read, the buffer is filled to the newline character when an input operation is requested and the buffer is empty.
  • _IONBF– no buffering. In this case, the size and buffer parameters are ignored.
If successful, the function returns 0.

Example: let's set our own buffer and see how reading from a file is carried out. Let the file be short (something like Hello, World!), and we read it character by character

#include #include #include void main() ( FILE *input = NULL; char c; char buffer = (0); input = fopen("D:/c/text.txt", "rt"); setbuf(input, buffer); while ( !feof(input)) ( c = fgetc(input); printf("%c\n", c); printf("%s\n", buffer); _getch(); ) fclose(input )

It can be seen that the data is already in the buffer. Reading character by character is done from the buffer.

feof

Function int feof(FILE * stream); returns true if the end of the file is reached. The function is convenient to use when you need to go through the entire file from beginning to end. Let there be a file with text content text.txt. We read the file character by character and display it on the screen.

#include #include #include void main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("Error opening file") ; _getch(); exit(0); while (!feof(input)) ( c = fgetc(input); fprintf(stdout, "%c", c); ) fclose(input());

Everything would be fine, but the feof function does not work correctly... This is due to the fact that the concept of “end of file” is not defined. An error that often occurs when using feof is that the last data read is printed twice. This is due to the fact that the data is written to the input buffer, the last read occurs with an error and the function returns the old value read.

#include #include #include void main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("Error opening file") ; _getch(); exit(0); while (!feof(input)) ( fscanf(input, "%c", &c); fprintf(stdout, "%c", c); ) fclose(input); _getch();

This example will fail (most likely) and print the last character of the file twice.

The solution is not to use feof. For example, store total quantity records or use the fact that fscanf etc. functions usually return the number of values ​​correctly read and matched.

#include #include #include void main() ( FILE *input = NULL; char c; input = fopen("D:/c/text.txt", "rt"); if (input == NULL) ( printf("Error opening file") ; _getch(); exit(0); while (fscanf(input, "%c", &c) == 1) ( fprintf(stdout, "%c", c); ) fclose(input); ; )

Examples

1. One file contains two numbers - the dimensions of the array. Let's fill the second file with an array of random numbers.

#include #include #include #include //File names and permissions #define INPUT_FILE "D:/c/input.txt" #define OUTPUT_FILE "D:/c/output.txt" #define READ_ONLY "r" #define WRITE_ONLY "w" //Maximum value for array size #define MAX_DIMENSION 100 //Error when opening a file #define ERROR_OPEN_FILE -3 void main() ( FILE *inputFile, *outputFile; unsigned m, n; unsigned i, j; inputFile = fopen(INPUT_FILE, READ_ONLY); if ( inputFile == NULL) ( printf("Error opening file %s", INPUT_FILE); getch(); exit(ERROR_OPEN_FILE); ) outputFile = fopen(OUTPUT_FILE, WRITE_ONLY); if (outputFile == NULL) ( printf("Error opening file %s", OUTPUT_FILE); getch(); //If the file could be opened for reading, then it must be closed if (inputFile != NULL) ( fclose(inputFile); ) exit(ERROR_OPEN_FILE); ) fscanf(inputFile, "%ud %ud", &m, &n); if (m > MAX_DIMENSION) ( m = MAX_DIMENSION; ) if (n > MAX_DIMENSION) ( n = MAX_DIMENSION; ) srand(time(NULL)); i< n; i++) { for (j = 0; j < m; j++) { fprintf(outputFile, "%8d ", rand()); } fprintf(outputFile, "\n"); } //Закрываем файлы fclose(inputFile); fclose(outputFile); }

2. The user copies the file, and first selects the operating mode: the file can be output either to the console or copied to a new file.

#include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *origin = NULL; FILE *output = NULL; char filename; int mode; printf("Enter filename: "); scanf("%1023s", filename); origin = fopen (filename, "r"); if (origin == NULL) ( printf("Error opening file %s", filename); getch(); exit(ERROR_FILE_OPEN); ) printf("enter mode: "); "%d", &mode); if (mode == 1) ( printf("Enter filename: "); scanf("%1023s", filename); output = fopen(filename, "w"); if (output = = NULL) ( printf("Error opening file %s", filename); getch(); fclose(origin); exit(ERROR_FILE_OPEN); ) ) else ( output = stdout; ) while (!feof(origin)) ( fprintf (output, "%c", fgetc(origin)); fclose(origin);

3. The user enters data from the console and it is written to a file until the esc key is pressed. Check out the program and see. how it behaves if you enter backspace: what is output to the file and what is output to the console.

#include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *output = NULL; char c; output = fopen("D:/c/test_output.txt", "w+t"); if (output == NULL) ( printf ("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); for (;;) ( c = _getch(); if (c == 27) ( break; ) fputc(c, output); fputc( c, stdout);

4. The file contains integers. Find the maximum of them. Let's take advantage of the fact that the fscanf function returns the number of correctly read and matched objects. The number 1 should be returned each time.

#include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) ( printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); ) maxn = INT_MIN; hasRead = 1; while (hasRead == 1) ( hasRead = fscanf(input, "%d", &num); if (hasRead != 1) ( continue; ) if (num >

Another solution is to read numbers until we reach the end of the file.

#include #include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *input = NULL; int num, maxn, hasRead; input = fopen("D:/c/input.txt", "r"); if (input == NULL) ( printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); ) maxn = INT_MIN; while (!feof(input)) ( fscanf(input, "%d", &num); if (num > maxn ) ( maxn = num; ) ) printf("max number = %d", maxn);

5. The file contains the words: Russian word, tab, English word, in several rows. The user enters an English word, it is necessary to output the Russian one.

The translation file looks something like this

sun sun
pencil pen
ballpoint pen pencil
door door
windows window
chair chair
armchair

and saved in cp866 encoding (OEM 866). It is important: the last pair of words also ends with a line feed.

The algorithm is as follows: we read a line from a file, find a tab sign in the line, replace the tab sign with zero, copy a Russian word from the buffer, copy an English word from the buffer, check for equality.

#include #include #include #include #define ERROR_FILE_OPEN -3 void main() ( FILE *input = NULL; char buffer; char enWord; char ruWord; char usrWord; unsigned index; int length; int wasFound; input = fopen("D:/c/input.txt ", "r"); if (input == NULL) ( printf("Error opening file"); _getch(); exit(ERROR_FILE_OPEN); ) printf("enter word: "); fgets(usrWord, 127, stdin ); wasFound = 0; while (!feof(input)) ( fgets(buffer, 511, input); length = strlen(buffer); for (index = 0; index< length; index++) { if (buffer == "\t") { buffer = "\0"; break; } } strcpy(ruWord, buffer); strcpy(enWord, &buffer); if (!strcmp(enWord, usrWord)) { wasFound = 1; break; } } if (wasFound) { printf("%s", ruWord); } else { printf("Word not found"); } fclose(input); _getch(); }

6. Count the number of lines in the file. We will read the file character by character, counting the number of "\n" characters until we encounter the EOF character. EOF is a special character that indicates that the input is complete and there is no more data to read. The function returns a negative value in case of error.
NOTE: EOF is of type int, so you need to use int to read the characters. Additionally, the value of EOF is not defined by the standard.

#define _CRT_SECURE_NO_WARNINGS #include #include #include int cntLines(const char *filename) ( int lines = 0; int any; //any is of type int because EOF is of type int! FILE *f = fopen(filename, "r"); if (f == NULL) ( return -1; ) do ( any = fgetc(f); //printf("%c", any);//debug if (any == "\n") ( lines++; ) ) while(any != EOF); ​​fclose(f); return lines; ) void main() ( printf("%d\n", cntLines("C:/c/file.txt")); _getch(); )

Ru-Cyrl 18-tutorial Sypachev S.S. 1989-04-14 [email protected] Stepan Sypachev students

Still not clear? – write questions to the mailbox

Last updated: 10/31/2015

Class FileStream represents the capabilities of reading from a file and writing to a file. It allows you to work with both text files and binary ones.

Let's consider its most important properties and methods:

    Length property: returns the length of the stream in bytes

    Position property: returns the current position in the stream

    Read method: Reads data from a file into a byte array. Takes three parameters: int Read(byte array, int offset, int count) and returns the number of bytes successfully read. The following parameters are used here:

    • array - an array of bytes where the data read from the file will be placed

      offset represents the offset in bytes in the array into which the read bytes will be placed

      count - maximum number bytes to be read. If there are fewer bytes in the file, then all of them will be read.

    Method long Seek(long offset, SeekOrigin origin): sets the position in the stream with an offset by the number of bytes specified in the offset parameter.

    Write method: Writes data from a byte array to a file. Takes three parameters: Write(byte array, int offset, int count)

    • array - an array of bytes from which data will be written to the file

      offset - the offset in bytes in the array from where bytes begin to be written to the stream

      count - maximum number of bytes to be written

FileStream represents file access at the byte level, so, for example, if you need to read or write one or more lines into a text file, then the byte array must be converted to strings using special methods. Therefore, other classes are used to work with text files.

At the same time, when working with various binary files that have a certain structure, FileStream can be very useful for extracting certain pieces of information and processing it.

Let's look at an example of reading and writing to a text file:

Console.WriteLine("Enter a line to write to the file:"); string text = Console.ReadLine(); // writing to a file using (FileStream fstream = new FileStream(@"C:\SomeDir\noname\note.txt", FileMode.OpenOrCreate)) ( // convert the string to bytes byte array = System.Text.Encoding.Default. GetBytes(text); // writing an array of bytes to a file fstream.Write(array, 0, array.Length); Console.WriteLine("Text written to file"); // reading from file using (FileStream fstream = File. OpenRead(@"C:\SomeDir\noname\note.txt")) ( // convert the string into bytes byte array = new byte; // read the data fstream.Read(array, 0, array.Length); // decode bytes to string string textFromFile = System.Text.Encoding.Default.GetString(array); Console.WriteLine("Text from file: (0)", textFromFile ) Console.ReadLine();

Let's look at this example. Both reading and writing use the using statement. This statement should not be confused with the using directive, which includes namespaces at the beginning of the code file. The using statement allows you to create an object in a block of code, upon completion of which the Dispose method of that object is called, and thus the object is destroyed. In this case, the fstream variable serves as such an object.

The fstream object is created in two different ways: through the constructor and through one of the static methods of the File class.

Here two parameters are passed to the constructor: the file path and the FileMode enumeration. This enumeration indicates the file access mode and can take the following values:

    Append: if the file exists, the text is appended to the end of the file. If the file does not exist, it is created. The file is opened for writing only.

    Create : A new file is created. If such a file already exists, it is overwritten

    CreateNew : A new file is created. If such a file already exists, then the application throws an error

    Open: Opens a file. If the file does not exist, an exception is thrown

    OpenOrCreate : if the file exists, it is opened, if not, a new one is created

    Truncate: If the file exists, it is overwritten. The file is opened for writing only.

The static OpenRead method of the File class opens a file for reading and returns a FileStream object.

The FileStream class constructor also has a number of overloads that allow you to more precisely customize the object being created. All these versions can be viewed on msdn.

Both writing and reading use the Encoding.Default encoding object from the System.Text namespace. In this case, we use two of its methods: GetBytes to get a byte array from a string and GetString to get a string from a byte array.

As a result, the string we entered is written to the file note.txt. Essentially, this is a binary file (not a text file), although if we write only a line into it, we can view this file in a readable form by opening it in a text editor. However, if we write random bytes into it, for example:

Fstream.WriteByte(13); fstream.WriteByte(103);

Then we may have problems understanding it. Therefore, separate classes are designed to work directly with text files - StreamReader and StreamWriter.

Random access to files

Often binary files represent a specific structure. And, knowing this structure, we can take the necessary piece of information from the file or, conversely, write a certain set of bytes in a certain place in the file. For example, in wav files, the audio data itself starts at 44 bytes, and up to 44 bytes there is various metadata - the number of audio channels, sampling frequency, etc.

Using the Seek() method, we can control the position of the stream cursor, starting from which the file is read or written. This method takes two parameters: offset and position in the file. A position in a file is described by three values:

    SeekOrigin.Begin : beginning of the file

    SeekOrigin.End : end of file

    SeekOrigin.Current : current position in the file

The cursor of the stream from which reading or writing begins is shifted forward by offset relative to the position specified as the second parameter. The offset can be negative, then the cursor moves backward, if positive, then forward.

Let's look at an example:

Using System.IO; using System.Text; class Program ( static void Main(string args) ( string text = "hello world"; // writing to a file using (FileStream fstream = new FileStream(@"D:\note.dat", FileMode.OpenOrCreate)) ( // convert the string to bytes input = Encoding.Default.GetBytes(text); // write an array of bytes to a file fstream.Write(input, 0, input.Length); Console.WriteLine("Text written to file"); move the pointer to the end of the file, five bytes to the end of the file fstream.Seek(-5, SeekOrigin.End); // minus 5 characters from the end of the stream // read four characters from the current position byte output = new byte( output, 0, output.Length); // decode the bytes into a string string textFromFile = Encoding.Default.GetString(output); Console.WriteLine("Text from file: (0)", textFromFile); in the file the word world to the word house string replaceText = "house"; fstream.Seek(-5, SeekOrigin.End); // minus 5 characters from the end of the stream input = Encoding.Default.GetBytes(replaceText); , 0, input.Length); // read the entire file // return the pointer to the beginning of the file fstream.Seek(0, SeekOrigin.Begin); output = new byte; fstream.Read(output, 0, output.Length); // decode the bytes into a string textFromFile = Encoding.Default.GetString(output); Console.WriteLine("Text from file: (0)", textFromFile); // hello house ) Console.Read(); ) )

Console output:

Text written to file Text from file: worl Text from file: hello house

Calling fstream.Seek(-5, SeekOrigin.End) moves the stream cursor to the end of the files back five characters:

That is, after writing the line “hello world” to a new file, the cursor will be at the position of the “w” character.

After this, we read four bytes starting with the character "w". In this encoding, 1 character will represent 1 byte. Therefore, reading 4 bytes will be equivalent to reading four characters: "worl".

Then, again, we move to the end of the file, not reaching the end of five characters (that is, again from the position of the “w” character), and write the string “house”. So the string "house" replaces the string "world".

Closing a thread

In the examples above, a using construct is used to close a stream. After all the operators and expressions in the using block have been processed, the FileStream object is destroyed. However, we can choose another way:

FileStream fstream = null; try ( fstream = new FileStream(@"D:\note3.dat", FileMode.OpenOrCreate); // operations with the stream ) catch(Exception ex) ( ) finally ( if (fstream != null) fstream.Close(); )

If we do not use a using construct, then we need to explicitly call the Close() method: fstream.Close()

Text files

Let's look at working with a text file in C using an example. Create a text file on drive C named TextFile.txt. Type the following lines in this file:

String_1 123 String_11, 456
String_2
String_3

Save the file.

And this is the code for a C program that opens our file and reads lines from it:

/* *Author: @author Subbotin B.P..h> #include #define LEN 50 int main(void) ( puts("Text file operations"); char cArray; FILE *pTextFile = fopen("C:\\TextFile.txt", "r"); if(pTextFile == NULL) ( puts("Problems"); return EXIT_FAILURE; ) while(fgets(cArray, LEN, pTextFile) != NULL) ( printf("%s", cArray); ) fclose(pTextFile); return EXIT_SUCCESS;

To open a text file in C, use the fopen function:

FILE *pTextFile = fopen("C:\\TextFile.txt", "r");

The first argument to the fopen function points to a file, and the second says that the file is open for reading from it.

We read the lines using the fgets function:

fgets(cArray, LEN, pTextFile);

The first argument of the fgets function points to a character array in which the received strings will be stored, the second argument is the maximum number of characters to read, and the third is our file.

After finishing working with the file, you need to close it:

fclose(pTextFile);

We get:

Russian letters also appear in the lines.

By the way, I made this program in Eclipse. You can see how to work with C/C++ in Eclipse.

So, we opened and read data from a text file.

Now let's learn how to programmatically create a text file and write data to it.

/* Author: @author Subbotin B.P..h> #include int main(void) ( FILE *pTextFile = fopen("C:\\TextFileW.txt", "w"); char *cString = "This is a string"; char cNewLine = "\n"; int nVal = 123 ; if(pTextFile == NULL) ( puts("Problems"); return EXIT_FAILURE; ) fprintf(pTextFile, "%s%c", cString, cNewLine); ; )

Create a text file to write data to:

FILE *pTextFile = fopen("C:\\TextFileW.txt", "w");

if the file already exists, it will be opened and all data from it will be deleted.

The C-string cString and the number nVal are written by the program to a text file. cNewLine is simply a new line.

We write data to a text file using the fprintf function:

fprintf(pTextFile, "%s%c", cString, cNewLine);

the first argument here is our file, the second is the format string, the third or more is the number of arguments required for this format.



Did you like the article? Share with your friends!