2、文件IO操作(linux系统编程)

1、文件读写

	//IO函数测试--->open close read write lseek
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR | O_CREAT, 0777);//0777表示文件权限
	if(fd<0)
	{
		perror("open error");
		return -1;
	}

	//写文件
	//ssize_t write(int fd, const void *buf, size_t count);
	write(fd, "hello world", strlen("hello world"));

	//移动文件指针到文件开始处
	//off_t lseek(int fd, off_t offset, int whence);
	lseek(fd, 0, SEEK_SET);

	//读文件
	//ssize_t read(int fd, void *buf, size_t count);
	char buf[1024];
	memset(buf, 0x00, sizeof(buf));
	int n = read(fd, buf, sizeof(buf));
	printf("n==[%d], buf==[%s]\n", n, buf);

	//关闭文件
	close(fd);

	return 0;
}

2、//lseek函数获取文件大小

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

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR);
	if(fd<0)
	{
		perror("open error");
		return -1;
	}

	//调用lseek函数获取文件大小
	int len = lseek(fd, 0, SEEK_END);
	printf("file size:[%d]\n", len);

	//关闭文件
	close(fd);

	return 0;
}

1 文件权限计算方法:

mode & ~umask
O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。
O_TRUNC 如果文件已存在, 将其长度截断为为0字节。
O_NONBLOCK 对于设备文件, 以O_NONBLOCK方式打开可以做非阻塞I/O(NonblockI/O),非阻塞I/O。

2 思考: 阻塞和非阻塞是文件的属性还是read函数的属性?

通过读普通文件测试得知: read函数在读完文件内容之后, 若再次read,则
read函数会立刻返回, 表明read函数读普通文件是非阻塞的.

	//验证read函数读普通文件是否阻塞
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR);
	if(fd<0)
	{
		perror("open error");
		return -1;
	}

	//读文件
	char buf[1024];
	memset(buf, 0x00, sizeof(buf));
	int n = read(fd, buf, sizeof(buf));
	printf("FIRST: n==[%d], buf==[%s]\n", n, buf);

	//再次读文件, 验证read函数是否阻塞
	memset(buf, 0x00, sizeof(buf));
	n = read(fd, buf, sizeof(buf));
	printf("SECOND: n==[%d], buf==[%s]\n", n, buf);

	//关闭文件
	close(fd);

	return 0;
}

设备文件: /dev/tty 标准输入STDIN_FILENO
通过读/dev/tty终端设备文件, 表明read函数读设备文件是阻塞的.

//验证read函数读设备文件是阻塞的 标准输入STDIN_FILENO
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//读标准输入
	char buf[1024];
	memset(buf, 0x00, sizeof(buf));
	int n = read(STDIN_FILENO, buf, sizeof(buf));
	printf("FIRST: n==[%d], buf==[%s]\n", n, buf);

	return 0;
}

结论: 阻塞和非阻塞不是read函数的属性, 而是文件本身的属性.
socket pipe这两种文件都是阻塞的.

使用st_mode成员判断文件类型:
	    if((sb.st_mode & S_IFMT) ==S_IFLNK)
	    {   
	        printf("连接文件\n");
	    }   
	    

	    if (S_ISREG(sb.st_mode)) 
	    {   
	        printf("普通文件\n");
	    }
判断文件权限:
	    if(sb.st_mode & S_IROTH)
	    {
	        printf("---R----");
	    }

lstat和stat函数:函数描述: 获取文件属性

1 对于普通文件来说, lstat函数和stat函数一样
2 对于软连接文件来说, lstat函数获取的是连接文件本身的属性,
stat函数获取的是连接文件指向的文件的属性.

//stat函数测试: 获取文件大小, 文件属主和组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//int stat(const char *pathname, struct stat *buf);
	struct stat st;
	stat(argv[1], &st);
	printf("size:[%d], uid:[%d], gid:[%d]\n", st.st_size, st.st_uid, st.st_gid);

	return 0;
}

//stat函数测试: 获取文件类型和权限

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

	int main(int argc, char *argv[])
	{
		//int stat(const char *pathname, struct stat *buf);
		//获取文件属性
		struct stat sb;
		stat(argv[1], &sb);

		//获取文件类型
		if ((sb.st_mode & S_IFMT) == S_IFREG) 
		{
			printf("普通文件\n");
		}	
		else if((sb.st_mode & S_IFMT) ==S_IFDIR)
		{
			printf("目录文件\n");
		}
		else if((sb.st_mode & S_IFMT) ==S_IFLNK)
		{
			printf("连接文件\n");
		}
		

		if (S_ISREG(sb.st_mode)) 
		{
			printf("普通文件\n");
		}
		else if(S_ISDIR(sb.st_mode))
		{
			printf("目录文件\n");
		}
		else if(S_ISLNK(sb.st_mode))
		{
			printf("连接文件\n");
		}

		//判断文件权限
		if(sb.st_mode & S_IROTH)
		{
			printf("---R----");
		}

		if(sb.st_mode & S_IWOTH)
		{
			printf("---W----");
		}
		
		if(sb.st_mode & S_IXOTH)
		{
			printf("---X----");
		}

		printf("\n");

		return 0;
	}
	

//stat函数测试: 获取文件大小, 文件属主和组

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

	int main(int argc, char *argv[])
	{
		//int stat(const char *pathname, struct stat *buf);
		struct stat st;
		lstat(argv[1], &st);
		printf("size:[%d], uid:[%d], gid:[%d]\n", st.st_size, st.st_uid, st.st_gid);

		return 0;
	}

目录操作:

1 打开目录 opendir
	函数原型: DIR *opendir(const char *name);
	函数返回值: 指向目录的指针
	函数参数: 要遍历的目录(相对路径或者绝对路径)
	
2 循环读目录: readdir
	函数原型: struct dirent *readdir(DIR *dirp);
	函数返回值: 读取的目录项指针
	函数参数: opendir函数的返回值

3 关闭目录: closedir
	函数原型: int closedir(DIR *dirp);
	函数返回值: 成功返回0, 失败返回-1
	函数参数: opendir函数的返回值
	
	//目录操作测试: opendir readdir closedir
#include <stdio.h>
	#include <stdlib.h>
	#include <string.h>
	#include <sys/types.h>
	#include <unistd.h>
	#include <dirent.h>

	int main(int argc, char *argv[])
	{
		//打开目录
		//DIR *opendir(const char *name);
		DIR *pDir = opendir(argv[1]);
		if(pDir==NULL)
		{
			perror("opendir error");
			return -1;
		}

		//循环读取目录项
		//struct dirent *readdir(DIR *dirp);
		struct dirent *pDent = NULL;
		while((pDent=readdir(pDir))!=NULL)
		{
			//过滤掉.和..文件
			if(strcmp(pDent->d_name, ".")==0 || strcmp(pDent->d_name, "..")==0)
			{
				continue;
			}

			printf("[%s]---->", pDent->d_name);

			//判断文件类型
			switch(pDent->d_type)
			{
				case DT_REG:
					printf("普通文件");
					break;

				case DT_DIR:
					printf("目录文件");
					break;

				case DT_LNK:
					printf("链接文件");
					break;

				default:
					printf("未知文件");
			}

			printf("\n");
		}

		//关闭目录
		closedir(pDir);

		return 0;
	}

dup和dup2函数:

复制文件描述符----详情看图

在这里插入图片描述

//测试dup函数复制文件描述符

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

	int main(int argc, char *argv[])
	{
		//打开文件
		int fd = open(argv[1], O_RDWR);
		if(fd<0)
		{
			perror("open error");
			return -1;
		}

		//调用dup函数复制fd
		int newfd = dup(fd);
		printf("newfd:[%d], fd:[%d]\n", newfd, fd);

		//使用fd对文件进行写操作
		write(fd, "hello world", strlen("hello world"));

		//调用lseek函数移动文件指针到开始处
		lseek(fd, 0, SEEK_SET);

		//使用newfd读文件
		char buf[64];
		memset(buf, 0x00, sizeof(buf));
		int n = read(newfd, buf, sizeof(buf));
		printf("read over: n==[%d], buf==[%s]\n", n, buf);

		//关闭文件
		close(fd);
		close(newfd);

		return 0;
	}
//使用dup2函数实现标准输出重定向操作
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR | O_CREAT, 0777);
	if(fd<0)
	{
		perror("open error");
		return -1;
	}

	//调用dup2函数实现文件重定向操作
	dup2(fd, STDOUT_FILENO);
		
	printf("ni hao hello world");

	close(fd);
	//close(STDOUT_FILENO); 不可以写

	return 0;
}

fcntl函数:函数描述: 改变已经打开的文件的属性

1 复制文件描述符: int fd = fcntl(oldfd, F_DUPFD, 0);
2 获得和设置文件的flag属性: 
	int flag = fcntl(fd, F_GETFL, 0);
	flag |= O_APPEND;
	fcntl(fd, F_SETFL, flag);

3 fcntl函数常用的操作:

	3-1 复制一个新的文件描述符:
	int newfd = fcntl(fd, F_DUPFD, 0);
	3-2 获取文件的属性标志
	int flag = fcntl(fd, F_GETFL, 0)
	3-3 设置文件状态标志
	flag = flag | O_APPEND;
	fcntl(fd, F_SETFL, flag)
	3-4 常用的属性标志
	O_APPEND-----设置文件打开为末尾添加
	O_NONBLOCK-----设置打开的文件描述符为非阻塞
//修改文件描述符的flag属性
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
	//打开文件
	int fd = open(argv[1], O_RDWR);
	if(fd<0)
	{
		perror("open error");
		return -1;
	}

	//获得和设置fd的flags属性
	int flags = fcntl(fd, F_GETFL, 0);
	flags = flags | O_APPEND;
	fcntl(fd, F_SETFL, flags);

	//写文件
	write(fd, "hello world", strlen("hello world"));

	//关闭文件
	close(fd);

	return 0;
}

	




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值