Chapter 1: Introduction and Basic Concepts
1. Linux follows the philosophy that everything is a file. A file is referenced by a unique file descriptor (FD). The file descriptor is an integer (INT type of C ). FD is shared by user space programs, and user space programs can directly use FD to access files.
2. Regular files contain data bytes and are organized into a linear array called byte stream ). These byte streams can have any value and can be organized together in any way. At the system level, Linux does not have any structure on the file except for the byte stream.
When a file is opened for the first time, the file location is zero. You can manually set the location of the file. If it is set to the end of the file, directly write the location after the end of the file, the bytes in the middle will be added to zero, and the bytes cannot be written to the position before the beginning of the file.
Writing a byte to the intermediate position of the file will overwrite the previous byte at this offset. Therefore, it is impossible to expand the file to the intermediate position of the file written by yourself.
Chapter 2: file I/O
**************************************** ********
The open () system call is used to map the file specified by the path name to a file descriptor, and return the file descriptor after successful ing. The file location is set to zero.
Int open (const char * Name, int flags );
Int open (const char * Name, int flags, mode_t mode );
The mode parameter is ignored unless a new file is created.
Int FD;
FD = open ("/home/Kidd/Madagascar", o_rdonly );
If (FD =-1)
/* Error */
**************************************** ************
Creat () is the open call of the o_wronly | o_creat | o_trunc Parameter
Int creat (const char * Name, mode_t mode );
Int FD;
FD = creat (file, 644 );
If (FD =-1)
/* Error */
**************************************** *************
# Include <unistd. h>
Ssize_t read (int fd, void * Buf, size_t Len );
Each call Reads len bytes from the current file location referenced by the FD parameter to the Buf. After the execution is successful, the number of bytes written to the Buf is returned. If the execution fails,-1 is returned and errno is set. The file location will forward the number of bytes read from Fd. If FD does not have the ability to find the location (character device file), it will only read data from the current location each time.
Unsigned long word;
Ssize_t NR;
Nr = read (FD, & Word, sizeof (unsigned long ));
If (Nr =-1)
/* Error */
Read () returns a non-zero positive value less than Len: the number of bytes that can be read is less than Len, the system call may receive a signal and interrupt the pipeline (if FD is a pipeline.
Read () returns zero to indicate that the object has reached the end (end of file (EOF). In blocking mode, this call is blocked (enters sleep state ), until the bytes available for reading appear. In non-blocking mode,-1 is returned for the call, which should be performed later.
Read all Bytes:
Ssize_t ret;
While (Len! = 0 & (ret = read (FD, Buf, Len ))! = 0 ){
If (ret =-1 ){
If (errno = eintr)
Continue;
Perror ("read ");
Break;
}
Len-= ret;
BUF + = ret;
}
Unblocking read operation: Check the eagain; otherwise, the "severe error" and "only lack of data" will be confused.
Char Buf [bufsiz]
Ssize_t NR;
Start:
Nr = read (FD, Buf, bufsiz );
If (Nr =-1 ){
If (errno = eintr)
Goto start;
If (errno = eagain)
/* Later */
Else
/* Error */
}
**************************************** ************************************
Write () system call:
# Include <unistd. h>
Ssize_t write (int fd, const void * Buf, size_t count );
When the write () operation is performed, the Count bytes are written from the Buf to the current file location of the file indicated by FD. If the object referred to by FD does not support the search function (character device), it is always written from (head.
Write bytes are returned successfully. If an error occurs,-1 is returned. If 0 is returned, only 0 bytes are written.
Basic usage:
Const char * Buf = "my ship is solid ";
Ssize_t NR;
Nr = write (FD, Buf, strlen (BUF ));
If (Nr =-1)
/** Error/
Check the possibility of partial write
..................
Else if (NR! = Count)
/* Maybe error, but not errno */
Linux writes are delayed
**************************************** *************************************
Fsync () system call:
# Include <unistd. h>
Int fsync (int fd );
Calling fsync () ensures that all dirty data in the file mapped by the file descriptor FD is written back to the disk. FD must be enabled for writing. This call will write back data and metadata, and will not be returned until the hard disk returns data and metadata have been written back to the disk.
Fdatasync () system call:
# Include <unistd. h>
Int fdatasync (int fd );
This call is the same as fsync, but it only refreshes data (flush data ). This call cannot guarantee that the data is synchronized with the disk, so the speed may be faster.
The usage of the two functions is the same:
Int ret;
Ret = fsync (FD );
If (ret =-1)
/* Error */
These two functions cannot guarantee that any change to the directory items containing files can be synchronized with the disk. To ensure that any changes to the directory items can be written back to the disk, you must call fsync () for the Directory itself ().
Sync () system call:
Synchronize all buffers with disks.
# Include <unistd. h>
Void sync (void );
This function does not require parameters or return values, but can return successfully.
The standard does not require sync () to be returned only when all the buffers are cleared to the disk. It only requires the call to deliver all the buffers to the disk. However, Linux will wait until all the buffers are delivered, therefore, one sync call is enough,
Applications should use fsync and fdatasync to submit necessary data to disks. In a busy system, it may take several minutes to call sync.
PS:
O_sync flag
Passing the o_sync flag to open () indicates that all the IO of the file must be synchronized:
Int FD;
FD = open (file, o_wronly | o_sync );
If (FD =-1 ){
Perror ("open ");
Return-1;
}
Read requests usually need to be synchronized; otherwise, you cannot know whether the data provided in the buffer zone is correct. However, as previously described, write () calls do not usually require synchronization. The returned results of this call are irrelevant to whether the data is submitted to the disk.
However, this relationship can be established using the o_sync flag to ensure that write () performs Io synchronization. Procedure:
Fsync () is called implicitly after each write () call and before the return operation. This degrades the user time and Kernel Time of the write operation. Unless otherwise, it is best not to use synchronous Io.
Generally, applications use fsync and fdatasync to ensure that data has been written back to the disk during write operations. Compared with o_sync, the cost is lower because they have fewer chances of being called.
**************************************** ************************************
Close () system call
# Include <unistd. h>
Int close (int fd );
Cancels the FD ing between the opened file descriptor FD and isolates the process from the associated file. If the execution succeeds, zero is returned. If the execution fails,-1 is returned and errno is set. The most common error is that the return value of close () is not checked, leading to missed key errors.
Basic usage:
If (close (FD) =-1)
Perror ("close ");
**************************************** *************************************
Lseek () system call
# Include <sys/types. h>
# Include <unistd. h>
Off_t lseek (int fd, off_t POs, int origin );
The behavior of lseek () depends on the origin parameter:
Seek_cur file location is set to its current value plus POS
The seek_end file location is set to the current length of the file plus the POs
The position of the seek_set file is set to POS. When the POS is zero, the offset value is set to the beginning of the file.
For example, set the file location to 1825.
Off_t ret;
Ret = lseek (FD, (off_t) 1825, seek_set );
If (ret = (off_t)-1)
/* Error */
Set the FD location to the end of the file:
Off_t ret;
Ret = lseek (FD, 0, seek_end );
If (ret = (off_t)-1)
/* Error */
Find the current location:
Int Pos;
Pos = lseek (FD, 0, seek_cur );
If (Pos = (off_t)-1)
/* Error */
Else
/* POS is the current position of the file */
**************************************** **************************************** * ******** 8
Read and Write operations at specific locations
Read:
# DEFINE _ xopen_source 500
# Include <unistd. h>
Ssize_t pread (int fd, void * Buf, size_t count, off_t POS );
Reads count bytes to Buf from the position POS of the file descriptor.
Write:
# DEFINE _ xopen_source 500
# Include <unistd. h>
Ssize_t pwrite (int fd, const void * Buf, size_t count, off_t POS );
It writes count bytes from the Buf to the file location POS of the file descriptor FD
Different from read () or write:
1. After the work is completed, the file pointer will not be changed.
2. this can avoid competition when lseek () is used. If multiple threads share file descriptors, after the first thread calls lseek (), before it reads or writes data, another thread of the same program may change the file location. Using pread () and pwrite () can avoid such competition conditions.
**************************************** **************************************** ****