I l @ ve RuBoard |
16.7 Unbuffered I/OIn buffered I/O, data is buffered and then sent to the file. In unbuffered I/O, the data is immediately sent to the file. If you drop a number of paperclips on the floor, you can pick them up in buffered or unbuffered mode. In buffered mode, you use your right hand to pick up a paper clip and transfer it to your left hand. The process is repeated until your left hand is full, then you dump a handful of paperclips into the box on your desk. In unbuffered mode, you pick up a paperclip and dump it into the box. There is no left-hand buffer. In most cases, buffered I/O should be used instead of unbuffered. In unbuffered I/O, each read or write requires a system call. Any call to the operating system is expensive. Buffered I/O minimizes these calls. Unbuffered I/O should be used only when reading or writing large amounts of binary data or when direct control of a device or file is required. Back to the paperclip example ”if you were picking up small items like paperclips, you would probably use a left-hand buffer. But if you were picking up cannon balls (which are much larger), no buffer would be used. The open system call is used for opening an unbuffered file. The macro definitions used by this call differ from system to system. Since the examples have to work for both Unix and MS-DOS/Windows, conditional compilation ( #ifdef / #endif ) is used to bring in the correct files: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #ifdef _ _MSDOS_ _ // If we are MS-DOS #include <io.h> // Get the MS-DOS include file for raw I/O #else /* _ _MSDOS_ _ */ #include <unistd.h> // Get the Unix include file for raw I/O #endif /* _ _MSDOS_ _ */ The syntax for an open call is: int file_descriptor = open( name , flags ); // Existing file file_descriptor = open( name , flags , mode ); //New file
Table 16-6. Open flags
For example, to open the existing file data.txt in text mode for reading, you use the following: data_fd = open("data.txt", O_RDONLY); The next example shows how to create a file called output.dat for writing only: out_fd = open("output.dat", O_CREATO_WRONLY, 0666); Notice that you combined flags using the OR ( ) operator. This is a quick and easy way of merging multiple flags. When any program is initially run, three files are already opened. These are described in Table 16-7. Table 16-7. Standard unbuffered files
The format of the read call is: read_size = read( file_descriptor , buffer , size );
Example 16-5 copies a file. Unbuffered I/O is used because of the large buffer size. It makes no sense to use buffered I/O to read 1K of data into a buffer (using an std:: ifstream ) and then transfer it into a 16K buffer. Example 16-5. copy2/copy2.cpp/**************************************** * copy -- copy one file to another. * * * * Usage * * copy <from> <to> * * * * <from> -- the file to copy from * * <to> -- the file to copy into * ****************************************/ #include <iostream> #include <cstdlib> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #ifdef _ _WIN32_ _ // if we are Windows32 #include <io.h> // Get the Windows32 include file for raw i/o #else /* _ _WIN32_ _ */ #include <unistd.h> // Get the Unix include file for raw i/o #endif /* _ _WIN32_ _ */ const int BUFFER_SIZE = (16 * 1024); // use 16k buffers int main(int argc, char *argv[]) { char buffer[BUFFER_SIZE]; // buffer for data int in_file; // input file descriptor int out_file; // output file descriptor int read_size; // number of bytes on last read if (argc != 3) { std::cerr << "Error:Wrong number of arguments\n"; std::cerr << "Usage is: copy <from> <to>\n"; exit(8); } in_file = open(argv[1], O_RDONLY); if (in_file < 0) { std::cerr << "Error:Unable to open " << argv[1] << '\n'; exit(8); } out_file = open(argv[2], O_WRONLY O_TRUNC O_CREAT, 0666); if (out_file < 0) { std::cerr << "Error:Unable to open " << argv[2] << '\n'; exit(8); } while (true) { read_size = read(in_file, buffer, sizeof(buffer)); if (read_size == 0) break; // end of file if (read_size < 0) { std::cerr << "Error:Read error\n"; exit(8); } write(out_file, buffer, (unsigned int) read_size); } close(in_file); close(out_file); return (0); } Several things should be noted about this program. First of all, the buffer size is defined as a constant, so it is easily modified. Rather than have to remember that 16K is 16,384, the programmer used the expression (16 * 1024) . This form of the constant is obviously 16K. If the user improperly uses the program, an error message results. To help the user get it right, the message tells how to use the program. You may not read a full buffer for the last read. That is why read_size is used to determine the number of bytes to write. |
I l @ ve RuBoard |