Lseek Function
Off_t lseek (intFiledes, Off_tOffset, Int whence );
Whence: seek_set, which indicates that the offset of the file is set to the offset byte starting from the file.
Seek_cur. Currently, the value is + offset bytes. The offset value can be positive or negative.
Seek_end: the length of the file + offset bytes. It can be positive or negative.
If the operation succeeds, the system returns the new file offset. If the operation fails, the system returns-1.
Lseek only records the current file offset in the kernel and does not cause any I/O operations. Then, the offset is used for the next read/write operation.
Empty
Offset can be greater than the current length of the file. In this case, the next write to the file will lengthen the file and create a hole in the file, which is allowed. In the file, but the bytes that have not been written are read as 0.
Empty space does not occupy disk space. The specific processing method is related to the file implementation. When it is located beyond the end of the file and then written, the newly written data needs to be allocated disk blocks, however, you do not need to allocate space for the parts between the end of the original file and the new start write location.
Although the lengths of empty and empty files can be the same, but they actually occupy different disk blocks.
File Sharing
UNIX supports sharing open files between different processes. The kernel uses three data structures to indicate open files.
- Progress table item
- File descriptor flag
- Pointer to a file table Project
- File Table items
- File status flag (such as read, write, append, sync, and nonblocking)
- Current file offset
- Pointer to the V node of the file
- V-node table item
- V node information (including the file type, pointer to various operations on the file process ...)
- I node information (index node), (including the file owner, file length, device where the file is located ...)
- Current file length
- Each process corresponds to a process entry. A process can open many files, so there are many FD entries in the process entry;
- One FD represents a file. It can also be said that a file can be represented by multiple FD;
- Different processes may have different operations on the same file. The file table items are actually related to the file and process, which contains some operations performed by the process on the file, then it points to the file with a pointer.
DUP and dup2 Functions
#include <unistd.h>int dup(int filedes);int dup2(int filedes, int filedes2);
DUP and dup2 are functions used to copy an existing file descriptor (opened file descriptor. Success. A new descriptor is returned. If the descriptor fails,-1 is returned.
DUP: Returns the minimum value of the currently available FD;
Dup2: You can specify the returned descriptor as fd2. If fd2 is enabled, disable it first. If FD is equal to fd2, fd2 is returned directly, replacing FD with fd2 without disabling it.
The new file descriptor returned by these two functions shares the same file table item with the original FD. For example, fd0 and fd4.
/Dev/FD
The new system provides a directory named/dev/FD. The directory item is a file named 0, 1, 2, and so on. Open/dev/FD/N It is equivalent to the replication descriptor n.
Some systems provide the path name/dev/stdin,/dev/stdout,/dev/stderr. It is equivalent to/dev/FD/0,/dev/FD/1,/dev/FD/2.
Atomic operation
The so-called atomic operation is an operation that will not be interrupted by the thread scheduling mechanism. Once this operation starts, it will continue to run until the end, and there will be no context switch (switch to another thread) in the middle)
If a process needs to add data to the end of a file, because early UNIX systems do not support open o_append, lseek is used to end the file and then write. However, if there are multiple processes, this method will cause problems.
if (lseek(fd, OL, 2) < 0) //position to EOF err_sys("lseek error");if (write(fd, buf, 100) != 100) err_sys("write error");
Assume that two independent processes A and B add the same file. Each process has opened the file, but the o_append flag is not used. At this time, both A and B have their own file table items, but share a V-node table item. If lseek is called by a, it sets the current offset of process a to 1500 bytes (at the end of the current file ). Then the kernel switches to B, B executes lseek, and sets the current offset of process B to 1500 bytes (at the end of the file ). Then B calls write to increase the current offset of the file B to 1600. Because the file length is increased, the Kernel updates the current file length in the V node to 1600. Then, when switching back to A and then writing, because the offset recorded in the current file table is 1500, the data written to B overwrites the data written to this file.
Solution:The lseek and write operations are an atomic operation for other processes. UNIX provides a method to set the o_append flag when opening a file so that the Kernel updates the current offset of the process to the end of the file every time before writing the file, therefore, you do not need to call lseek before each write.
Sync, fsync, fdatasync
In traditional Unix systems, a buffer or page cache is provided in the kernel. Most disk I/O operations are performed through the buffer. When we write data to a file, the data is usually copied to one of its buffers by the kernel and queued for writing to the disk at a later time. This is called delayed write ). This method reduces the number of disk reads and writes, but reduces the file content update speed. If the system fails, the file update content will be lost.
So, to ensure that the actual file system on the disk is consistent with the content in the cache of the buffer, Unix provides the sync, fsync, and fdatasync functions to forcibly write the buffer to the disk file.
# Include <unistd. h> int fsync (INT filedes); int fdatasync (INT filedes); // success, 0 is returned; error,-1 void sync (void) is returned );
Sync: Global, flush to the entire system. No matter whether you actually finish writing the disk or not, you can enter the write queue if there are any modifications, that is, you can fl the kernel block buffer as long as there is a slight change.
Fsync: refers to only one file, which is specified by the file descriptor and waits until the disk write is completed before the return.
Fdatasync: As the name implies, only the data part is updated, because fsync will also synchronously Update file attributes.
The above three methods are system calls provided by the system. The C language has a function fflush extended to the C standard, which also has similar functions.
#include <stdio.h>int fflush(FILE* stream);
UNIX _ file I/O