------------文件IO(input/output)概览------------------------------------------
标准IO 系统IO(文件IO)
fopen() open()
fread() read()
fwrite() write()
fclose() close()
fflush() lseek()
fseek()
ftell
rewind()
fgets() gets()
fputs() puts()
getchar() putchar()
getc() putc()
目录相关
opendir()
readdir()
closedir()
目录中opendir并没有改变当前的环境变量,要想改变进入下一级目录要使用chdir()才可以。
文件的打开 open() 普通文件- open()
字符设备c open()
块设备 b open()
套接字 s socket() //用于网络
管道 p open()
软链接 l open()
目录 d opendir()
#include "ishead.h" // 默认在当前路径下找该头文件 自己在学习中积累的头文件弄成自己的头文件
int main()
{
// 定义变量存放文件的文件描述符
int fd;
// 打开一个文件
fd=open("./1.txt",O_RDWR);//可读可写
if(fd==-1)
{
perror("open 1.txt failed!\n");
return -1;
}
printf("1.txt的文件描述符是:%d\n",fd);
return 0;
}
intopen(const char *pathname, int flags);
intopen(const char *pathname, int flags, mode_t mode);//权限
返回值:成功 返回新的文件描述符
表示该文件在进程状态信息task_struct中用于存放文件信息的那个数组中的下标
形参:pathname ---》你要打开那个文件/设备的路径
flags ---》O_RDONLY, O_WRONLY, or O_RDWR.
O_CREAT, 以新建的方式打开文件
O_EXCL 跟O_CREAT配合,表示如果新建的文件存在,直接退出
O_NOCTTY 跟硬件终端有关的
O_TRUNC 跟O_CREAT配合,表示如果新建的文件存在,覆盖清空原文件
O_APPEND 追加
O_ASYNC 异步IO读写
O_SYNC 同步IO读写
mode ---》S_IRWXU 很有规律的
在linux中一切都是文件
使用man手册我们发现第二本介绍说存放的是系统调用(内核提供的函数)
第三本介绍说存放的是库调用
系统调用它是操作系统本身自带的一些函数
库调用---》大部分是将系统提供的函数做了二次封装
linux认为所有的硬件设备都可以抽象表示为一个个设备节点文件(驱动中的概念)
在嵌入式开发中我们编写代码无非就是对一些硬件设备,文件,普通数据进行计算操作---》linux中这些东西全部都以文件的形式存在
比如: 液晶屏 ----》 /dev/fb0
触摸屏 ----》 /dev/event0
#define SIZE 1000
int main(int argc, char const *argv[])
{
int fb1 = open(argv[1],O_RDONLY);//打开一个文件,只读
int fb2 = open(argv[2],O_RDWR|O_CREAT,644);打开一个文件如没有则创建该文件,可读可写,644,如文件被新建指定其权限为mode 即语句中的644
if(fb1 == -1||fb2 == -1)
{
perror("open() error");
}
char buf[SIZE];
while(1)
{
int numRead = read(fb1,buf,SIZE);//读取指定文件数据,语句中为读取文件描述符fb1文件的数据 buf为存放读取到的数据的缓冲区 ,SIZE,想要读取的字节数
if(numRead == -1)
{
perror("read() error");
}
if(numRead == 0)
{
printf("copy ok\n");
break;
}
write(fb2,buf,numRead);//把读取到存放在buf的数据写进fb2中 字节数位numRead.
}
close(fb1);
close(fb2);//虽然程序运行完会自行关闭 但是还是要自己关闭,养成好的习惯。
return 0;
}
off_t lseek(int fildes, off_t offset, int whence);
返回值:文件当前读写位置距离文件开头的字节数
形参:fildes---》 你要设置读写偏移的那个文件的文件描述符
offset ---》偏移量,你打算偏移多少字节
whence ---》参考标准,文件开头 SEEK_SET
文件当前位置 SEEK_CUR
文件末尾 SEEK_END
注意: 每一次关闭,然后重新打开文件,文件的读写偏移都是从起始位置开始
int main(int argc, char const *argv[])
{
int fd = open(argv[1],O_RDONLY|O_CREAT,644);
if(fd == -1)
{
printf("error\n");
perror("open() error");
}
int fd1 = 0;
// fd1 = lseek(fd,5,SEEK_SET);
// printf("%d\n",fd1);
// fd1 = lseek(fd,-5,SEEK_SET);//返回-1 错误
// printf("%d\n",fd1);
// fd1 = lseek(fd,5,SEEK_CUR);//从当前位置偏移右移五个偏移量
// printf("%d\n",fd1);
// fd1 = lseek(fd,-5,SEEK_CUR);//从当前位置偏移左移五个偏移量,如果超出文件头字节位置 报错
// printf("%d\n",fd1);
fd1 = lseek(fd,5,SEEK_END);//文件总字节数加5
printf("%d\n",fd1);
// fd1 = lseek(fd,-5,SEEK_END);//文件总字节数减5
// printf("%d\n",fd1);
close(fd);
return 0;
}
stat()和fstat()
#include<sys/stat.h>
intstat(const char *restrict path, struct stat *restrictbuf);
intfstat(int fildes, struct stat *buf);
唯一的区别是fstat要求传递的是文件描述符
返回值:成功 0 失败 -1
形参:path---》你要获取属性的那个文件的路径
buf ---》用于存放你获取到的文件的属性信息
主要成员介绍:
st_mode; --》文件的模式位
st_size; --》保存文件的大小
S_ISDIR(mode) if(S_ISDIR(buf.st_mode)) //条件为真输出 。printf("这是一个目录")
S_ISCHR(mode) 判断是否是字符设备
S_ISBLK(mode) 判断是否是块设备
S_ISLNK(mode) 判断是否是软链接
S_ISREG(mode) 判断是否是普通文件
S_ISFIFO(mode) 判断是否是管道
S_ISSOCK(mode) 判断是否是套接字
判断文件的权限
if((S_IRWXU&(buf.st_mode))==S_IRUSR) 判断当前用户是否只读
if((S_IRWXU&(buf.st_mode))==(S_IRUSR|S_IWUSR)) 判断当前用户是否可读写
if((S_IRWXU&(buf.st_mode))==(S_IRUSR|S_IWUSR|S_IXUSR)) 判断当前用户是否可读可写可执行
#define SIZE 100
int main(int argc, char const *argv[])
{
int fd1;
int fd2;
struct stat buf;
stat(argv[1],buf);
if(S_ISDIR(buf.st_mode))
printf("目录\n");
if(S_ISCHR(buf.st_mode))
printf("字符设备\n");
if(S_ISBLK(buf.st_mode))
printf("块设备\n");
if(S_ISLNK(buf.st_mode))
printf("软链接\n");
if(S_ISFIFO(buf.st_mode))
printf("管道\n");
if(S_ISSOCK(buf.st_mode))
printf("套接字\n");
//目录
if(S_ISREG(buf.st_mode))
{
//文件是普通文件
fd1 = open(argv[1],O_RDONLY);
stat(argv[2],buf);
if(S_ISREG(buf.st_mode))
{
fd2 = (argv[2],O_RDWR|O_TRUNC);//判断文件存在则以读写方式打开,且删除文件中原有的数据
}
else
{
fd2 = (argv[2],O_RDWR|O_CREAT,644);//文件不存在则新建文件
}
}
char buf1[SIZE];
while(1)
{
int nread = read(fd1,buf1,SIZE);
if(nread == -1)
{
perror("read() faile!");
break;
}
if(nread == 0)
{
break;
printf("read write is ok!\n");
}
int nwrite = write(fd2,buf1,nread);
if(nwrite == -1)
{
perror("write() faile!");
}
}
return 0;
}
-----------------------重定向函数----------------------------------------
1. int dup(int fildes)
返回值:系统重新分配得到的新文件描述符
形参:fildes---》旧的文件描述符
2. int dup2(int fildes, int fildes2);返回值:你指定的新文件描述符
形参:fildes 旧的文件描述符
fildes2 你指定的新文件描述符,跟返回值一样
//重定向把错误标志打印在error.log中
#include "myhead.h"
int main(int argc, char **argv)
{
int error_fd;
int fd;
error_fd = open("error.log", O_CREAT|O_RDWR, 0777);
//结尾往后移动5个字节,避免之前打印的错误标志被覆盖
lseek(error_fd, 5, SEEK_END);
//将错误标准输出重定向给error_fd,在error.log里打印错误信息
dup2(error_fd, 2);
fd = open(argv[1], O_RDWR);
if(fd == -1)
{
perror("文件打开失败");
}
//将错误标准输出重定向给fd,在error.log里打印错误信息
#include "ishead.h"
int main(int argc, char const *argv[])
{
int fd;
fd = open("error.log",O_RDWR);
dup2(fd,2);//将错误标准输出重定向给fd,在error.log里打印错误信息
int fd1;
fd1 = open("1.txt",O_RDWR);
if(fd1 == -1)
{
lseek(fd,0,SEEK_END);
perror("open() error\n");
}
return 0;
}
//把系统时间重定向到时间.txt中
#include "ishead.h"
// #define szie
int main(int argc, char const *argv[])
{
int time_fd;
time_fd = open("time.txt", O_CREAT|O_RDWR|O_APPEND, 0777);
dup2(time_fd,1);
// lseek(time_fd,0, SEEK_END);
while(1)
{
time_t temp;
temp = time(NULL);
char *buf=ctime(&temp);
buf=ctime(&temp);
printf("此时系统的时间是:%s\n",ctime(&temp));
// write(time_fd,ctime(&temp),strlen(ctime(&temp)));
sleep(1);
}
return 0;
}