《UNIX环境高级编程》笔记 第三章——文件IO(1)

本文详细介绍了C语言中的文件IO操作,包括open,openat函数的区别,常用的打开文件标志如O_RDONLY,O_WRONLY,O_CREAT等,以及lseek函数的三种定位方法。还通过实例展示了如何正确处理read和write函数的错误情况。
摘要由CSDN通过智能技术生成

1. 简介

文件IO是不带缓冲的IO,指的是每次read和wite都调用内核中的一个系统调用。对内核而言,所有打开的文件都通过一个非负整数去引用,这个非负整数被称为文件描述符,应用程序通过文件描述符对文件进行读、写、定位、控制和关闭等操作。文件描述符的范围是0~OPEN_MAX - 1,符号常量STDIN_FILENO(0)、STDOUT_FILENO(1)和STDERR_FILENO(2)分别是标准输入、标准输出和标准错误的文件描述符。

2. 函数原型

表1列出的函数原型中,path参数可以是目录或文件名(不适合则会出错),oflag(表2)参数是打开文件描述符的标志,openat的fd参数是一个被打开目录的文件描述符,mode(表3)参数只有在创建新文件时才使用,用来控制用户对文件的访问权限。

表1 函数原型

int open(const char *path, int oflag, .../* mode_t mode */)

打开文件

返回值:若成功,返回文件描述符;若出错。返回-1

int openat(int fd, const char *path, int oflag, .../* mode_t mode */)

打开文件

(1)path参数是一个绝对路径,fd被忽略,相当于open函数

(2)path参数是一个相对路径,则path是相对于打开fd目录的一个相对路径,比如打开fd的路径是/tmp,path是./test.txt,则openat打开文件的完整路径是/tmp/test.txt

(3)path参数是一个相对路径,fd值是AT_FDCWD,则path是相对于进程当前工作目录的一个相对路径

返回值:若成功,返回文件描述符;若出错。返回-1

int creat(const char *path, mode_t mode)

创建一个新文件,相当于调用open(path, O_CREAT | O_WRONLY | O_TRUNC, mode)

返回值:若成功,返回只写打开的文件描述符;若出错,返回-1

int close(int fd)

 关闭文件描述符

返回值:若成功,返回0;若出错,返回-1

off_t lseek(int fd, off_t offset, int whence)

设置文件的偏移量,whence可取常量值:

SEEK_SET:偏移量从文件开始处计算,即0+offset

SEEK_CUR:偏移量从当前位置计算,即

current_pos+offset

SEEK_END:偏移量从文件末尾计算,即

file_size+offset

返回值:若成功,返回新的文件偏移量,若出错。返回-1

ssize_t read(int fd, void *buf, size_t nbytes)

读取文件数据

返回值:若成功,返回读到的字节数;若出错,返回-1;若已到文件末尾,返回0

ssize_t write(int fd, void *buf, size_t nbytes)

写入文件数据

返回值:若成功,返回已写的字节数;若出错,返回-

表2 oflag常用标志

O_RDONLY   只读打开
O_WRONLY 只写打开
O_RDWR       读、写打开
O_APPEND  文件被被打开时,默认位置是0;使用这个选项位置会被定位到文件大小的位置,即每次写都追加到末尾
O_CLOEXEC执行时关闭,在调用exec函数族时自动关闭设置该标志的文件描述符
O_CREAT     若文件不存在则创建它 ,使用这个选项,同时应指定mode参数
O_EXCL    如果指定了O_CREAT ,而文件已经存在,则出错;这样可以测试一个文件是否存在,不存在则创建它,测试和创建这两个步骤是一个原子操作
O_NOFOLLOW如果path引用的是一个符号链接,则出错
O_NONBLOCK将IO设置为非阻塞模式,即read没有读到给定的字节数时也返回
O_TRUNC       若文件打开模式是O_WRONLY或O_RDWR,则将其文件长度截断为0
O_SYNC          同步写,每次wite等待物理IO操作完成才返回,更新文件数据和属性
O_DSYNC同步写,每次wite等待物理IO操作完成才返回,如果该操作并不影响刚写入数据的读取,则不需要等待文件的属性被更

表3 mode常用标志

S_IRWXU 用户可读、写、和执行
S_IRUSR   用户可读
S_IWUSR 用户可写
S_IXUSR   用户可执行
S_IRWXG  组可读、写、和执行
S_IRGRP   组可读
S_IWGRP  组可写
S_IXGRP   组可执行
S_IRWXO 其他人可读、写、和执行
S_IROTH   其他人可读
S_IWOTH 其他人写
S_IXOTH   其他人可执行
S_ISUID   设置用户ID位,当文件是可执行文件时,其进程有效用户ID是文件所有者ID
S_ISGID   

设置组ID位,与创建目录有关

3. 实例

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

int test_open_file(const char *path, int oflag, int mode)
{
	int fd;

	if (oflag&O_CREAT) {
		fd = open(path, oflag, mode);
	} else {
		fd = open(path, oflag);
	}
	printf("Open %s: fd = %2d, error = %s\n", path, fd, fd>=0?"success":strerror(errno));
	
	return fd;
}

#define TEST_STR1 "hello world! 1"
#define TEST_STR2 "hello world! 22"
#define TEST_STR3 "hello world! 3333"
#define TEST_STR4 "hello world! 44444"

int main()
{
	test_open_file("tmp/t1.txt", O_RDWR, 0);	
	test_open_file("tmp/t1.txt", O_RDWR|O_CREAT, (S_IRUSR|S_IWUSR)|(S_IRGRP|S_IWGRP)|(S_IROTH));	
	test_open_file("tmp/t1.txt", O_RDWR|O_CREAT|O_EXCL, (S_IRUSR|S_IWUSR)|(S_IRGRP|S_IWGRP)|(S_IROTH));	
	test_open_file("tmp/t2.txt", O_RDWR|O_CREAT|O_EXCL, (S_IRUSR|S_IWUSR)|(S_IRGRP|S_IWGRP)|(S_IROTH));	
	test_open_file("tmp/t2.txt", O_RDWR|O_CREAT|O_APPEND|O_SYNC, (S_IRUSR|S_IWUSR)|(S_IRGRP|S_IWGRP)|(S_IROTH));	

	int dir_fd = open("tmp", O_RDONLY|O_DIRECTORY, 0);
	int fd = openat(dir_fd, "t3.txt", O_RDWR|O_CREAT|O_APPEND, (S_IRUSR|S_IWUSR)|(S_IRGRP|S_IWGRP)|(S_IROTH));
	printf("Open t3.txt: fd = %2d, error = %s\n", fd, fd>=0?"success":strerror(errno));
	
	if (fd >= 0) {
		char buf[64] = {0};
		write(fd, TEST_STR1, strlen(TEST_STR1));
		write(fd, TEST_STR2, strlen(TEST_STR2));
		write(fd, TEST_STR3, strlen(TEST_STR3));
		write(fd, TEST_STR4, strlen(TEST_STR4));

		read(fd, buf, strlen(TEST_STR1));
		printf("str = %s\n", buf);

		lseek(fd, 0, SEEK_SET);
		read(fd, buf, strlen(TEST_STR1));
		printf("str1 = %s\n", buf);
		
		lseek(fd, strlen(TEST_STR2)-1, SEEK_CUR);
		read(fd, buf, strlen(TEST_STR3));
		printf("str3 = %s\n", buf);

		lseek(fd, strlen(TEST_STR4) * -1, SEEK_END);
		read(fd, buf, strlen(TEST_STR4));
		printf("str4 = %s\n", buf);

		close(fd);
	}

	return 0;
}

4. 小结

1. open和openat函数的用法及区别

2. 理解打开文件常用的标志和模式,尤其是每个标志的作用

3.  lseek函数的三种定位方法的理解及应用

4. 注意read和write函数在应用程序中的错误处理

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值