File I/O
File I/O operations are basically open files, read files, write files, and close files. Most operations only use open, read, write, lseek, and close files.
The open function
#include <fcntl.h>
int open(const char*path, int oflag, ...);
int openat(int fd, const char *path, int oflag, ...);
// Returns the file descriptor on success, -1 on failure
Copy the code
Path specifies the file name. Oflag can specify the behavior of a function
Creat a function
The creat function creates a new file
#include <fcntl.h>
int create(const char *path, mode_t mode);
// Returns the file descriptor on success, -1 on failure
/ / equivalent to the open (path, O_WRONLY | O_CREAT | O_TRUNC, mode).
Copy the code
The disadvantage of create is that it creates a file in write-only mode
The close
Close an open file
#include <fcntl.h>
int close(int fd);
Return 0 on success, -1 on failure
Copy the code
Closing a file releases all record locks that the process has placed on the file. When a process terminates, the kernel automatically closes all open files
Lseek function
Each open file has a current file offset associated with it. It is usually a non-negative integer that measures the number of bytes counted from the beginning of the file. Typically, read and write operations start at the current file offset and increase the offset by the number of bytes read and written. By default, when opening a file, the offset is set to 0 unless the O_APPEND option is specified. Lseek can explicitly set an offset for an open file.
off_t lseek(int fd, off_t offset, int whence);
// Returns the new file offset on success, -1 on failure
Copy the code
whence parameter affects the interpretation of offset
Test the examples in the book
#include "apue.h"
int main(void)
{
if (lseek(STDIN_FILENO, 0, SEEK_CUR) == - 1)
printf("cannot seek\n");
else
printf("seek OK\n");
exit(0);
}
Copy the code
Let’s compile and test it
$ ./a.out < /etc/passwd
seek OK
$ ./a.out < /etc/passwd| ./a.out
cannot seek
Copy the code
Note that some offsets may be negative, so do not test lseek’s return value for less than 0, but for -1
An example from the test book
#include "apue.h"
#include <fcntl.h>
char buf1[] = "abcdefghij";
char buf2[] = "ABCDEFGHIJ";
int
main(void)
{
int fd;
if ((fd = creat("file.hole", FILE_MODE)) < 0)
err_sys("creat error");
if (write(fd, buf1, 10) != 10)
err_sys("buf1 write error");
/* offset now = 10 */
if (lseek(fd, 16384, SEEK_SET) == - 1)
err_sys("lseek error");
/* offset now = 16384 */
if (write(fd, buf2, 10) != 10)
err_sys("buf2 write error");
/* offset now = 16394 */
exit(0);
}
Copy the code
Let’s test it out
$ gcc hole.c -lapue $ ./a.out $ ls -l file.hole -rw-r--r-- 1 yuanzhihong yuanzhihong 16394 Jun 6 22:03 file.hole $ od -c file.hole 0000000 a b c d e f g h i j \0 \0 \0 \0 \0 \0 0000020 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 * 0040000 A B C D E F G H I J 0040012Copy the code
The functions read and write
#include<unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes);
ssize_t write(int fd, void *buf, size_t nbytes);
// Returns the number of bytes read or written. Return -1 on error
Copy the code
Sometimes you don’t read that many bytes. The buffer in the network, for example, has reached the end of the file.
Process shared file entry (I node)
Atomic operation
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
// Returns the number of bytes read/written, -1 on error
Copy the code
Dup and dup2
Used to copy a file descriptor
#include<unistd.h> int dup(int fd); int dup2(int fd, int fd2); // Returns the new file descriptor. Return -1 on errorCopy the code
Dup is equivalent to copying an original file descriptor. Dup2 is equivalent to specifying fd2 as a copy fd. If fd2 is already on, fd2 is turned off first.
The functions sync, fsync, fdatasync
All three functions are used to clear buffers
#include<unistd.h>
int fsync(int fd);
int fdatasync(int fd);
// Return 0 for success, -1 for error
void sync(void);
Copy the code
An FCNTL function
#include<fcntl.h> int fcntl(int fd, int cmd, ... /* int arg */); // Return -1 on errorCopy the code
The FCNTL function has five functions
- 1, copy an existing descriptor, CMD =
F_DUPFD
Or CMD =F_DUPFD_CLOEXEC
- 2, get/set file descriptor, CMD =
F_GETFD
Or CMD =F_SETFD
- 3, get/set the file descriptor state, CMD =
F_GETFL
Or CMD =F_SETFL
- Get/set asynchronous I/O ownership, CMD =
F_GETOWN
Or CMD =F_SETOWN
- Get/set log lock, CMD =
F_GETLK
Or CMD =F_SETLK
Or CMD =F_SETLKW
For an example from the book, the first parameter specifies the file descriptor and prints the selected file flag description for that descriptor
#include "apue.h"
#include <fcntl.h>
int
main(int argc, char *argv[])
{
int val;
if(argc ! =2)
err_quit("usage: a.out <descriptor#>");
if ((val = fcntl(atoi(argv[1]), F_GETFL, 0))"0)
err_sys("fcntl error for fd %d", atoi(argv[1]));
switch (val & O_ACCMODE) {
case O_RDONLY:
printf("read only");
break;
case O_WRONLY:
printf("write only");
break;
case O_RDWR:
printf("read write");
break;
default:
err_dump("unknown access mode");
}
if (val & O_APPEND)
printf(", append");
if (val & O_NONBLOCK)
printf(", nonblocking");
if (val & O_SYNC)
printf(", synchronous writes");
#if! defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC ! = O_SYNC)
if (val & O_FSYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}
Copy the code
Let’s compile and run
$gcc fileflags.c -lapue
$./a.out 0 < /dev/tty #0 represents standard input
read only
$ ./a.out 1 > temp.foo #1 represents standard output
$ cat temp.foo
write only
$ ./a.out 2 2>>temp.foo
write only, append
$ ./a.out 5 5<>temp.foo # 5<> opens the file temp. Foo on file descriptor 5 for reading and writing
read write
Copy the code
Let’s look at another function from the book. A function that sets one or more file status flags for a file descriptor
#include "apue.h"
#include <fcntl.h>
void
set_fl(int fd, int flags) /* flags are file status flags to turn on */
{
int val;
if ((val = fcntl(fd, F_GETFL, 0))"0)
err_sys("fcntl F_GETFL error");
val |= flags; /* turn on flags */
if (fcntl(fd, F_SETFL, val) < 0)
err_sys("fcntl F_SETFL error");
}
Copy the code
Get the state of the file descriptor, then do or with the flag to set, and then set back to the original file descriptor