PROGRAMMAZIONE I
A.A. 2017/2018
INPUT/OUTPUT
INPUT AND OUTPUT
Programs must be able to write data to files or to
physical output devices such as displays or printers, and to read in data from files or input devices such as a
keyboard.
The C standard library provides numerous functions for these purposes. Often referred as the I/O library
All of the basic functions, macros, and types for input and output are declared in the header file stdio.h.
STREAMS
From the point of view of a C program, all kinds of files and devices for input and output are uniformly
represented as logical data streams, regardless of
whether the program reads or writes a character or byte at a time, or text lines, or data blocks of a given size.
Streams in C can be either text or binary streams Opening a file by means of the function fopen( ) (or
tmpfile( )) creates a new stream, which then exists until closed by the fclose( ) function.
TEXT STREAMS
A text stream transports the characters of a text that is divided into lines.
A line of text consists of a sequence of characters ending in a newline character (‘\n’).
A line of text can also be empty, meaning that it consists of a newline character only.
The last line transported may or may not have to end with a newline character, depending on the
implementation.
TEXT STREAMS
The internal representation of text in a C program is the same regardless of the system on which the program is running.
üThus text input and output on a given system may involve removing, adding, or altering certain characters.
üFor example, on systems that are not Unix-based, end-of- line indicators ordinarily have to be converted into newline characters when reading text files, as on Windows systems, for instance, where the end-of-line indicator is a sequence of two control characters, \r (carriage return) and \n (newline).
As the programmer, you generally do not have to worry about the necessary adaptations, because they are
performed automatically by the I/O functions in the standard library.
BINARY STREAMS
A binary stream is a sequence of bytes that are transmitted without modification.
In other words, the I/O functions do not involve any interpretation of control characters when operating on binary streams.
Data written to a file through a binary stream can always be read back unchanged on the same system. However, in certain implementations there may be additional zero- valued bytes appended at the end of the stream.
Binary streams are normally used to write binary data—
for example, database records—without converting it to text.
FILES
OPENING A FILE
A file represents a sequence of bytes.
The fopen( ) function associates a file with a stream and initializes an object of the type FILE, which contains all the information necessary to control the stream.
Such information includes
üa pointer to the buffer used;
üa file position indicator, which specifies a position to access in the file;
OPENING A FILE
Each of the functions that open files—namely fopen( ), freopen( ), and tmpfile( )— returns a pointer to a FILE object for the stream associated with the file being
opened.
Once you have opened a file, you can call functions to transfer data and to manipulate the stream.
Such functions have a pointer to a FILE object—
commonly called a FILE pointer—as one of their arguments.
üThe FILE pointer specifies the stream on which the operation is carried out.
FUNCTIONS WITHOUT OPENING A FILE
The I/O library also contains functions that operate on the file system, and take the name of a file as one of their parameters.
These functions do not require the file to be opened first.
The remove( ) function deletes a file (or an empty directory). The string argument is the file’s name.
The rename( ) function changes the name of a file (or directory). The function’s two string arguments are the old and new names, in that order.
EXAMPLE
The remove( ) and rename( ) functions both have the
return type int, and return zero on success, or a non-zero value on failure.
The following statement changes the name of the file songs.dat to mysongs.dat:
Conditions that can cause the rename( ) function to fail include the following:
üno file exists with the old name;
üthe program does not have the necessary access privileges;
üthe file is open.
if ( rename( "songs.dat", "mysongs.dat" ) != 0 )
fprintf( stderr, "Error renaming \"songs.dat\".\n" );
SEQUENTIAL AND RANDOM
ACCESS
FILE POSITION
Like the elements of a char array, each character in an ordinary file has a definite position in the file.
The file position indicator in the object representing the stream determines the position of the next character to be read or written.
When you open a file for reading or writing, the file
position indicator points to the beginning of the file, so that the next character accessed has the position 0.
If you open the file in “append” mode, the file position indicator may point to the end of the file.
Each read or write operation increases the indicator by the number of characters read from the file or written to the file.
SEQUENTIAL AND RANDOM ACCESS
This behavior makes it simple to process the contents of a file sequentially.
Random access within the file is achieved by using
functions that change the file position indicator, fseek(), fgetpos( ), and rewind( ).
ürewind() sets the file position indicator to the beginning of the file
üfgetpos() retrieve the current file position
Of course, not all files support changing access
positions. Sequential I/O devices such as terminals and printers do not, for example.
BUFFERS
BUFFERS
In working with files, it is generally not efficient to read or write individual characters.
For this reason, a stream has a buffer in which it collects characters, which are transferred as a block to or from the file.
Sometimes you don’t want buffering, however:
üFor example, after an error has occurred, you might want to write data to a file as directly as possible.
THREE WAYS OF BUFFERING
Fully buffered: the characters in the buffer are normally transferred only when the buffer is full.
Line-buffered: the characters in the buffer are normally transferred only when a newline character is written to the buffer, or when the buffer is full.
Unbuffered: Characters are transferred as promptly as possible.
MORE ON BUFFERING
You can also explicitly transfer the characters in the
stream’s output buffer to the associated file by calling the fflush( ) function. The buffer is also flushed when you
close a stream, and normal program termination flushes the buffers of all the program’s streams.
When you open an ordinary file by calling fopen( ), the new stream is fully buffered.
After you have opened a file, and before you perform the first input or output operation on it, you can change the buffering mode using the setbuf( ) or setvbuf( ) function.
STANDARD STREAMS
Three standard text streams are available to every C program on starting.
These streams do not have to be explicitly opened.
stdin is usually associated with the keyboard, and stdout and stderr with the console display.
FILE pointer Common name Buffering mode
stdin Standard input Line-buffered
stdout Standard output Line-buffered
stderr Standard error output Unbuffered
EXAMPLE
#include<stdio.h>int main() {
int* p= NULL;
fprintf(stdout, "I should print something as ...");
if (p == NULL)
fprintf(stderr, "Pointer is NULL!");
else {
*p = 3;
fprintf(stdout, "%d\n", *p);
}
fprintf(stdout, "Exit from the program\n");
return 0;
stdout } stderr
I should print something as … Pointer is NULL!
Pointer is NULL!
Exit from the program\n
I should print something as … Exit from the program
READING AND WRITING TEXT
FILES
NEEDED OPERATIONS
To write to a new file or modify the contents of an existing file, you must first open the file.
When you open a file, you must specify an access mode indicating whether you plan to read, to write, or some
combination of the two.
When you have finished using a file, close it to release resources.
OPENING A FILE: FOPEN()
The standard library provides the function fopen() to open a file.
FILE *fopen( const char * restrict filename, const char * restrict mode );
This function opens the file whose name is specified by the string filename.
üThe filename may contain a directory part.
The second argument, mode, is also a string, and specifies the access mode.
The fopen( ) function associates the file with a new stream.
FREOPEN
This function redirects a stream. Like fopen(), freopen() opens the specified file in the specified mode. However, rather than creating a new stream, freopen() associates the file with the existing stream specified by the third
argument. The file previously associated with that stream is closed.
FILE *freopen( const char * restrictfilename, const char * restrict mode, FILE * restrict stream );
The most common use of freopen() is to redirect the standard streams, stdin, stdout, and stderr.
ACCESS MODE
The access mode specified by the second argument to fopen( ) or freopen( ) determines what input and output operations the new stream permits.
The first character in the mode string is always r for
“read,” w for “write,” or a for “append”.
The mode string may also contain one or both of the characters + and b
üin either order: +b has the same effect as b+.
A plus sign (+) in the mode string means that both read and write operations are permitted.
OPEN IN BINARY MODE
A b in the mode string causes the file to be opened in binary mode—that is, the new stream associated with the file is a binary stream.
If there is no b in the mode string, the new stream is a text stream.
CREATION AND ACCESS MODES
If the mode string begins with r, the file must already exist in the file system.
If the mode string begins with w, then the file will be created if it does not already exist.
If it does exist, its previous contents will be lost, because the fopen( ) function truncates it to zero length in “write”
mode.
A mode string beginning with a (for append) also causes the file to be created if it does not already exist.
If the file does exist, however, its contents are preserved, because all write operations are automatically performed at the end of the file.
FOPEN MODES
r - open for reading
w - open for writing (file need not exist)
a - open for appending (file need not exist)
r+ - open for reading and writing, start at beginning w+ - open for reading and writing (overwrite file)
a+ - open for reading and writing (append if file exists)
Note that it's possible for fopen to fail even if your
program is perfectly correct: you might try to open a file specified by the user, and that file might not exist (or it might be write-protected). In those cases, fopen will the NULL pointer.
FCLOSE
When you're done working with a file, you should close it using the function
üint fclose(FILE *a_file);
fclose returns zero if the file is closed successfully.
An example of fclose is
üfclose(fp);
int res= fclose(fp) If (res != 0)
puts(“Error while closing files”)
READING AND WRITING WITH
FPRINTF, FSCANF FPUTC, AND FGETC
To work with text input and output, you use fprintf() and fscanf(), both of which are similar to printf() and scanf() except that you must pass the FILE pointer as first
argument. For example:
FILE *fp;
fp=fopen(” /Users/francescosantini/Desktop/ProgrammI/output.txt", "w");
fprintf(fp, "Testing...\n");
FGETC
It is also possible to read (or write) a single character at a time--this can be useful if you wish to perform
character-by-character input (for instance, if you need to keep track of every piece of punctuation in a file it would make more sense to read in a single character than to read in a string at a time.)
The fgetc function, which takes a file pointer, and returns an int, will let you read a single character from a file:
üint fgetc (FILE *fp);
EXAMPLE
#include <stdio.h>
int main ( int argc, char *argv[] ) {
if ( argc != 2 ) /* argc should be 2 for correct execution */
{
/* We print argv[0] assuming it is the program name */
printf( "usage: %s filename", argv[0] );
}
else {
// We assume argv[1] is a filename to open FILE *file = fopen( argv[1], "r" );
/* fopen returns 0, the NULL pointer, on failure */
if ( file == NULL ) {
printf( "Could not open file\n" );
}
else
EXAMPLE 2
else {
int x;
/* read one character at a time from file, stopping at EOF, which indicates the end of the file. */
while ( ( x = fgetc( file ) ) != EOF ) {
printf( "%c", x );
}
fclose( file );
} } }
FPUTC
The fputc function allows you to write a character at a time, character by character.
üint fputc( int c, FILE *fp );
Note that the first argument should be in the range of an unsigned char so that it is a valid character. The second argument is the file to write to.
On success, fputc() will return the value c, and on failure, it will return EOF.
FSCANF
#include<stdio.h>
int main(void) { FILE *fp;
int a= 10;
fp=fopen("/Users/francescosantini/Desktop/ProgrammI/output.txt", "r");
if (fp == NULL) {
puts("Errore");
return -1;
}
char stringRead[30];
int returnFscanf= fscanf(fp, "%s", stringRead);
while (returnFscanf != EOF) {
printf("%s\n", stringRead);
returnFscanf= fscanf(fp, "%s", stringRead);
} fclose(fp);
}
output.text:
Testing…
Testing...10
MacBook-Francesco:ProgrammI francescosantini$ ./main Testing...
Testing...10
FSEEK
int fseek(FILE * stream, long int offset, int from);
To move the position in the file From can be one among
üSEEK_SET 0 SEEK_CUR 1 SEEK_END 2
Which correspond to
üThe beginning of the file, üThe current file position, üThe end of the file
EXAMPLE
#include <stdio.h>
int main () {
FILE *fp;
fp = fopen("file.txt","w+");
fputs("This is tutorialspoint.com", fp);
fseek( fp, 7, SEEK_SET );
fputs(" C Programming Language", fp);
fclose(fp);
return(0);
}
This is C Programming Language
READ AND WRITE
A program must not alternate immediately between reading and writing.
After a write operation, you must call the fflush() function or a positioning function (fseek( )) before performing a read operation.
üSo you are sure the file is updated before reading it
The C library function int fflush(FILE *stream) flushes the output buffer of a stream.
After a read operation, you must call a positioning function before performing a write operation.
READING AND WRITING
BINARY FILE I/O
FWRITE
For binary File I/O you use fread and fwrite. The declarations for each are similar:
size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
The first argument is the name of the array or the
address of the structure you want to write to the file. The second argument is the size of each element of the
array; it is in bytes. The third argument is number of elements. The fourth argument is the pointer to FILE.
EXAMPLE
#include<stdio.h>
int main(void) { FILE *fp;
fp=fopen("/Users/francescosantini/Desktop/ProgrammI/output.bin", ”wb");
if (fp == NULL) {
puts("Error fopen");
return -1;
}
int x[4]={1,2,3,4};
int res= fwrite(x, sizeof(x[0]), sizeof(x)/sizeof(x[0]), fp);
if (res == 0) {
puts("Error fwrite");
return -1;
}
fclose(fp);
return 0;
}
READ FROM A BINARY FILE
size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);
Remember that they are not ASCII characters!
MacBook-Francesco:ProgrammI francescosantini$ hexdump outbut.bin 0000000 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
0000010
TMPFILE()
FILE *tmpfile( void );
The tmpfile( ) function creates a new temporary file
whose name is distinct from all other existing files, and opens the file for binary writing and reading (as if the mode string "wb+" were used in an fopen() call).
If the program is terminated normally, the file is automatically deleted.
All three file-opening functions return a pointer to the
stream opened if successful, or a null pointer to indicate failure.
EXAMPLE
#include<stdio.h>
int main(void) { FILE *fp;
fp=fopen("/Users/francescosantini/Desktop/ProgrammI/output.bin",
”rb");
if (fp == NULL) {
puts("Error fopen");
return -1;
}
int a= 0;
int res= fread(&a, sizeof(int), 1, fp);
if (res == EOF) {
puts("Error fread");
return -1;
} else
printf("Value read: %d\n", a);
fclose(fp);
return 0;
}
WRITE A STRUCTURE
int main() {
int counter;
FILE *ptr_myfile;
struct rec my_record;
ptr_myfile=fopen("test.bin","wb");
if (!ptr_myfile) {
printf("Unable to open file!");
return 1;
}
for ( counter=1; counter <= 10; counter++) {
my_record.x= counter;
fwrite(&my_record, sizeof(struct rec), 1, ptr_myfile);
}
fclose(ptr_myfile);
return 0;
}
#include<stdio.h>
/* Our structure */
struct rec {
int x,y,z;
};
READ A STRUCTURE
int main() {
int counter;
FILE *ptr_myfile;
struct rec my_record;
ptr_myfile=fopen("test.bin","rb");
if (!ptr_myfile) {
printf("Unable to open file!");
return 1;
}
for ( counter=1; counter <= 10; counter++) {
fread(&my_record,sizeof(struct rec),1,ptr_myfile);
printf("%d\n",my_record.x);
}
fclose(ptr_myfile);
return 0;
}
#include<stdio.h>
/* Our structure */
struct rec {
int x,y,z;
};