1.IO文件分类
其实APP上面还有封装fopen/fread等函数,最大的特点就是引入了用户buff,使得去操作文件时,linux只用open一次文件,然后存入buff,这样提高了效率。具体需要进一步去了解。
Linux进阶-文件IO操作_io要求将当前路径下,所有文件的权限及最后一次的访问时间提取出来,-CSDN博客
2.IO编程
首先了解IO基本函数
2.1 文件描述符fd
在linux和其他unix操作系统中,文件描述符是一个非负整数,用来描述已经打开的文件。文件描述符是进程级别的概念,每个进程都有一个独立的文件描述符。
当进程启动时,通常会自动打开三个文件描述符
- 0:标准输入(stdin)
- 1:标准输出(stdout)
- 2:标准错误输出(stderr)
2.2 open函数
我们可以在虚拟机系统上使用 man 2 open命令查看open函数的用法。需要的头文件和函数原型
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname是文件路径,flags是指文件的打开模式一般有以下参数:
- O_RDONLY:只读模式打开文件
- O_WRONLY:只写模式打开文件
- O_RDWR:读写模式打开文件
- O_CREAT:如果文件不存在则创造文件
- O_EXCL:与
O_CREAT
一起使用,如果文件已经存在则返回错误。 - O_TRUNC:如果文件存在并且以写入模式打开,则将其长度截断为0
- O_APPEND:追加模式打开文件
返回值:
成功:则返回fd也就是文件描述符(非负整数)
失败:返回-1,并设置“erron”以指示错误
实例:
int main(int argc,char **argv)
{
int fd;
if(argc != 2 )
{
printf("usage %s <file>\n",argv[0]);
return -1;
}
/*
//int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
flags:O_RDONLY (只读),O_WRONLY (只写),O_RDWR (读写),O_CREAT,O_EXCL,O_TRUNC,O_APPEND
mode_t mode:文件权限赋予
*/
fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0777);
if (fd < 0) {
printf("can not open %s\n",argv[1]);
perror("Failed to open file\n");
printf("errno = %d\n",errno);
printf("err %s\n",strerror(errno));
} else {
printf("fd = %d\n",fd);
}
while(1) {
sleep(10);
}
close(fd);
return 0;
}
我们使用open函数,去操作一个文件,如果这个文件存在而且以写模式打开则截取其长度为0,如果不存在,则创建这个文件并赋予对应的权限。能赋予的权限最终要看系统umask给的值。
例如umask 为0002,则表示,其他用户不能有写权限,那能拥有的权限则是取反后和赋予的权限相与。
2.2 write函数
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符(使用open函数打开文件时会返回文件描述符)
buf:写入的内容
count:写入的长度大小
实例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
/*
argc = 2
agrv[0] = "./open"
agrv[1] = "1.txt"
*/
int main(int argc,char **argv)
{
int fd;
int len;
int i;
if(argc < 3 )
{
printf("usage %s write <file> <string> <string> ...\n",argv[0]);
return -1;
}
/*
//int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
flags:O_RDONLY (只读),O_WRONLY (只写),O_RDWR (读写),O_CREAT,O_EXCL,O_TRUNC,O_APPEND
mode_t mode:文件权限赋予
*/
fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0777);
if (fd < 0) {
printf("can not open %s\n",argv[1]);
perror("Failed to open file\n");
printf("errno = %d\n",errno);
printf("err %s\n",strerror(errno));
} else {
printf("fd = %d\n",fd);
}
//ssize_t write(int fd, const void *buf, size_t count);
for(i = 2;i < argc;i++) {
len = write(fd,argv[i],strlen(argv[i]));
if(len != strlen(argv[i])) {
perror("Failed to write file\n");
break;
}
write(fd,"\r\n",2);
}
//off_t lseek(int fd, off_t offset, int whence);
//指定位置写入
lseek(fd,3,SEEK_SET);
write(fd,"666",3);
close(fd);
return 0;
}
2.3 read函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd:文件描述符
buf:指向用于存储读取数据的缓冲区的指针,读出来的数据
count:请求读取的字节数
实例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
/*
argc = 2
agrv[0] = "./open"
agrv[1] = "1.txt"
*/
int main(int argc,char **argv)
{
int fd;
int len;
unsigned char buf[100];
if(argc !=2 )
{
printf("usage %s read <file>\n",argv[0]);
return -1;
}
/*
//int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
flags:O_RDONLY (只读),O_WRONLY (只写),O_RDWR (读写),O_CREAT,O_EXCL,O_TRUNC,O_APPEND
mode_t mode:文件权限赋予
*/
fd = open(argv[1],O_RDONLY);
if (fd < 0) {
printf("can not open %s\n",argv[1]);
perror("Failed to open file\n");
printf("errno = %d\n",errno);
printf("err %s\n",strerror(errno));
} else {
printf("fd = %d\n",fd);
}
//ssize_t read(int fd, void *buf, size_t count);
while(1) {
len = read(fd,buf,sizeof(buf)-1);
if (len < 0) {
perror("read\n");
close(fd);
return -1;
} else if (len == 0) {
break;
} else {
buf[len] = '\0';
printf("%s",buf);
}
}
close(fd);
return 0;
}
2.4 close函数
close
函数用于关闭文件描述符,并释放与该文件描述符关联的资源
成功返回0,失败返回-1;
3.综合实验
我是跟着韦东山那边的老师一步一步学的。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
/*
./005 data.csv result .csv
argc = 3
agrv[0] = "./005"
agrv[1] = "data.csv"
agrv[2] = "result .csv"
*/
#define max_len 1000
static int read_line(int fd,unsigned char *buf)
{
/*循环读入一个字符*/
/*如何判断读完一行?读到回车或者换行符 0x0d 0x0a*/
unsigned char c;
int len;
int i = 0;
int err = 0;
while(1) {
len = read(fd,&c,1);
if (len <= 0) {
err = -1;
break;
} else {
buf[i] = c;
i++;
if(c == '\n') {
/*碰到回车换行*/
err = 0;
break;
}
}
}
buf[i] = '\0';
if (err && (i == 0)) {
/*读到文件尾部,但没有数据*/
return -1;
} else {
return i;
}
}
int process_data(unsigned char *data_buf,unsigned char *result_buf)
{
/* 示例1: data_buf = ",语文,数学,英语,总分,评价"
result_buf = ",语文,数学,英语,总分,评价"
示例2: data_buf = "张三,90,91,92,,"
result_buf = "张三,90,91,92,273,A+"
*/
char name[100];
int scores[3];
int sum;
char *levels[]={"A+","A","B"};
int level;
if(data_buf[0] == ',') {
strcpy(result_buf,data_buf);
} else {
sscanf(data_buf,"%[^,],%d,%d,%d,",name,&scores[0],&scores[1],&scores[2]);
//printf("result: %s,%d,%d,%d\n\r",name,scores[0],scores[1],scores[2]);
//printf("result: %s --->get name--->%s\n\r",data_buf,name);
sum = scores[0]+scores[1]+scores[2];
if(sum >= 270) {
level = 0 ;
} else if(sum >= 240 && sum < 270) {
level = 1;
} else {
level =2;
}
sprintf(result_buf,"%s,%d,%d,%d,%d,%s\n\r",name,scores[0],scores[1],scores[2],sum,levels[level]);
//printf("result: %s",result_buf);
}
}
int main(int argc,char **argv)
{
int fd_data,fd_result;
int len;
int i;
unsigned char data_buf[max_len];
unsigned char result_buf[max_len];
if(argc != 3 )
{
printf("usage %s <data csv file> <result csv file> ...\n",argv[0]);
return -1;
}
/*
//int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
flags:O_RDONLY (只读),O_WRONLY (只写),O_RDWR (读写),O_CREAT,O_EXCL,O_TRUNC,O_APPEND
mode_t mode:文件权限赋予
*/
fd_data = open(argv[1],O_RDONLY);
fd_result = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0777);
if (fd_data < 0) {
printf("can not open file %s\n",argv[1]);
perror("Failed to open file\n");
return -1;
} else {
printf("fd_data = %d\n",fd_data);
}
fd_result = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0777);
if (fd_result < 0) {
printf("can not creat file %s\n",argv[1]);
perror("Failed to result file\n");
return -1;
} else {
printf("fd_result = %d\n",fd_result);
}
while(1) {
/*读取一行*/
len = read_line(fd_data,data_buf);
if(len == -1) {
break;
}
#if 0
if(len != 0) {
printf("line: %s\n\r",data_buf);
}
#endif
/*处理数据*/
//process_data(data_buf,result_buf);
if(len != 0) {
process_data(data_buf,result_buf);
}
/*写入结果文件*/
//write_data(fd_result,result_buf);
write(fd_result,result_buf,strlen(result_buf));
}
close(fd_data);
close(fd_result);
return 0;
}
这边碰到几个坑,就是编码格式的问题,电脑默认csv文件是以ISO-8859格式保存,但是读取是用UTF-8格式,所以会在终端读取乱码,我在保存的时候用notepad++转码为UTF-8格式。
这个实验最终要的是了解IO的这些函数的用法吧,具体的一些处理文件的语法还是基本功问题。
4.文件系统IO内部调用机制
用户空间访问内核系统:
1.APP,调用系统接口(glbc)
2.触发异常,设置原因,调用汇编指令
3.进入liunx内核空间,分辨和处理异常