头文件和函数声明
#include
int close(int fd);
函数功能
关闭一个文件描述符
返回值
成功时返回 0。失败则返回 -1,并设置 errno 为相应的错误标志。
参数
fd:文件描述符
说明
像其它所有系统调用一样,应对 close() 的调用进行错误检查,如下所示:
if (-1 == close(fd)) {
perror("close error");
exit(EXIT_FAILURE);
}
以上代码能够捕获的错误有:
例子
以下程序功能:打开 "./log.txt" 文件,然后调用 close() 函数关闭打开的文件
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int flags = O_WRONLY | O_CREAT | O_APPEND; /* 只写,没有该文件则创建,写时从文件内容的末尾附加新内容 */
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /* rw-rw-rw- */
int fd = open("./log.txt", flags, mode);
if (fd < 0) {
perror("open error");
exit(EXIT_FAILURE);
}
int ret = close(fd); /* 关闭文件描述符 */
if (ret < 0) {
perror("close error");
exit(EXIT_FAILURE);
}
printf("process exit success\n");
return 0;
}
每个打开的文件都有一个与其相关联的当前文件偏移量(current file offset),它通常是一个非负整数,用以度量从文件开始处计算的字节数。
读写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数。
系统默认的情况,当打开一个文件时,除非指定 O_APPEND 选项打开,否则该偏移量被设置为 0。可以调用 lseek() 函数为一个打开的文件设置偏移量。
头文件和函数声明
#include
#include
typedef long off_t;
off_t lseek(int fd, off_t offset, int whence);
函数功能
为一个打开的文件设置偏移量
返回值
成功返回新的文件偏移量,失败返回 -1,并设置 errno 为相对应的错误标志。(注意:成功返回新的文件偏移量可能为负数,所以在判断 lseek() 函数一定要谨慎,应该判断返回值是否等于 -1)
参数
fd:文件描述符
offset:参数 offset 的含义跟参数 whence 的值有关
off_t new_offset = lseek(fd, 0, SEEK_SET); // 将 fd 引用的文件的文件偏移量设置到文件开始处
off_t new_offset = lseek(fd, 0, SEEK_END); // 将 fd 引用的文件的文件偏移量设置到文件尾部
off_t new_offset = lseek(fd, -1, SEEK_END); // 将 fd 引用的文件的文件偏移量设置到文件尾部的前一个字节处
linux 内核中对 SEEK_SET、SEEK_CUR、SEEK_END 的定义如下所示:
#define SEEK_SET 0 /* seek relative to beginning of file */
#define SEEK_CUR 1 /* seek relative to current file position */
#define SEEK_END 2 /* seek relative to end of file */
例子
以下程序功能:打开 "./log.txt" 文件,调用 lseek() 函数将文件偏移量设置为文件尾部,然后从文件尾部开始写入 “hello world\n” 字符串,最后调用 close() 函数关闭打开的文件
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int flags = O_WRONLY | O_CREAT; /* 只写,没有该文件则创建,文件偏移量默认为 0 */
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /* rw-rw-rw- */
int fd = open("./log.txt", flags, mode);
if (fd < 0) {
perror("open error");
exit(EXIT_FAILURE);
}
off_t new_offset = lseek(fd, 0, SEEK_END); // 将文件偏移量设置为文件尾部,也可用于获取文件长度(文件所占字节数)的方法
if (-1 == new_offset) {
perror("lseek error");
exit(EXIT_FAILURE);
}
off_t length = new_offset;
printf("before write, file length = %ld\n", length);
char buf[] = "hello world\n"; // strlen(buf) = 12; sizeof(buf) = 13
ssize_t nwrite = write(fd, buf, strlen(buf));
if (nwrite < 0) {
perror("write error");
exit(EXIT_FAILURE);
}
length = lseek(fd, 0, SEEK_END);
if (-1 == length) {
perror("lseek error");
exit(EXIT_FAILURE);
}
printf("after write, file length = %ld\n", length);
if (-1 == close(fd)) {
perror("close error");
exit(EXIT_FAILURE);
}
return 0;
}
头文件和函数声明
#include
/********************/
/* 32位系统 */
typedef unsigned int size_t ;
typedef int ssize_t ;
/* 64位系统 */
typedef unsigned long size_t ;
typedef long ssize_t;
/********************/
ssize_t read(int fd, void *buf, size_t count);
函数功能
从文件描述符 fd 引用的文件中请求读取 count 字节的数据并存储到从 buf 开始的缓冲区中
返回值
说明
一次 read() 调用所读取到的字节数可能会小于请求的字节数。
参数
fd:文件描述符
buf:存储读取到的数据的首地址
count:请求读取 count 字节数据
头文件和函数声明
#include
/********************/
/* 32位系统 */
typedef unsigned int size_t ;
typedef int ssize_t ;
/* 64位系统 */
typedef unsigned long size_t ;
typedef long ssize_t;
/********************/
ssize_t write(int fd, const void *buf, size_t count);
函数功能
向文件描述符 fd 引用的文件中写入从 buf 开始的缓冲区中 count 字节的数据。
返回值
成功时返回被写入的字节数(若为 0 则表示没有写入数据)。失败则返回 -1,并设置 errno 为相应的错误标志。
参数
fd:文件描述符
buf:要被写入文件的数据在内存中的首地址
count:请求写入 count 字节
说明
如果 write() 调用成功,将会返回实际写入文件的字节数。该返回值可能会小于 count 参数值,这被叫做部分写。
例子
以下程序功能:拷贝一个普通文件。命令行格式:./copyfile_demo log.txt log2.txt
#include
#include
#include
#include
#include
#include
#include
#define BUF_SIZE 4096
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("%s input_file out_put_file\n", argv[0]);
exit(EXIT_FAILURE);
}
int ifd = open(argv[1], O_RDONLY); // 只读方式打开
if (-1 == ifd) {
fprintf(stderr, "open %s error: %s\n", argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
int flags = O_WRONLY | O_CREAT | O_EXCL; // 只读,创建新文件,O_EXCL:此标志,保证 open() 调用只能创建新文件,如果文件存在则报错
int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /* rw-rw-rw- */
int ofd = open(argv[2], flags, mode);
if (-1 == ofd)
{
if (-1 == close(ifd))
perror("close error");
fprintf(stderr, "open %s error: %s\n", argv[2], strerror(errno));
exit(EXIT_FAILURE);
}
char buf[BUF_SIZE] = "";
ssize_t nread = 0;
while ((nread = read(ifd, buf, BUF_SIZE)) > 0) {
if (write(ofd, buf, nread) != nread) {
if (-1 == close(ifd))
perror("close error");
if (-1 == close(ofd))
perror("close error");
perror("write error");
exit(EXIT_FAILURE);
}
}
// 成功 read() 完整个文件,nread = 0
if (-1 == nread) {
if (-1 == close(ifd))
perror("close error");
if (-1 == close(ofd))
perror("close error");
perror("read error");
exit(EXIT_FAILURE);
}
if (-1 == close(ifd))
perror("close error");
if (-1 == close(ofd))
perror("close error");
printf("copy %s success\n", argv[1]);
return 0;
}
注:对实例代码中 open() 函数有疑惑的小伙伴,欢迎浏览我的这篇博文,这里就不再过多阐述。
linux文件I/O之 open() 函数用法_微尘8的博客-CSDN博客
参考:
《UNIX环境高级编程》(第3版)
《Linux-UNIX系统编程手册》