文章目录
1、系统Api
\08_Li命基\08d03(-IO)\3-视频12
linux/src/print_where.c
fd文件操作描述符,启动一个进程后,linux系统在进程的进程控制块PCB中,默认开启3个操作,stdin stdout stderr 。对应的文件的文件描述符表(一共1024个数字)的前三个数字012,open函数操作对应的文件描述符表中的最小的可用的那个,下文代码close(1)把文件描述符表的第二个关了,所以open函数返回的fd对应的文件描述符表中的文件描述符就是1,
后边printf()函数调用write(1,“hello”,0644);写在了缓冲区中,如果灭有fflush()函数,此段代码只能生成可执行文件a.out,执行a.out后只能生成一个空的1.log文件,因为需要刷新缓冲区才能把刚才print()写的内容写进刚才open()函数打开的文件中
#include<stdio.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
int main()
{
close(1);
int fd=open("1.log",O_CREAT|O_TRUNC|O_WRONLY,0644);
printf("hello world\n");
fflush(stdout);
// close(stdout); // 不能这么写,只能用上面的语句刷新
close(fd);
return 0;
}
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);
2、文件IO
open
查看 man 2 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_APPEND 追加
- O_CREAT 创建文件
- O_EXCL 与O_CREAT 一起使用,如果文件存在则报错
mode权限位(mode & ~umask) umask0002补码755 再和mode与一下的出该文件的权限
- O_EXCL 与O_CREAT 一起使用,如果文件存在则报错
- O_NONBLOCK 非阻塞
- 必选项
- 返回值,成功返回打开的描述符表中的对应的文件描述符,失败返回-1
close
头文件 #include <unistd.h>
int close(int fd);
成功返回0;失败返回-1 并设置err number
选项就是一个位符,对应的位置如果是,就设置为1,不然就是0,
- 1 esc下 gg=G调整代码规范
- 2 对应函数open 选中 按下2 再按下大K,跳到函数原型,把头文件粘贴回来
example 用open和close实现touch (权限是664),所以open给的权限应该是0666,
#include<unistd.h> //close的头文件
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char *argv[] )
{
if(argc!=2) // argc代表参数个数,至少有两个,第一个是路径,第二个是名字,
{
printf("./out filename\n");
}
int fd=open(argv[1],O_RDONLY|O_CREAT,0666); // 第一个参数取出来名字,用来创建
close(fd);
return 0;
}
3、read,write
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
-
fd 文件描述符
-
buf 缓冲区
-
count 缓冲区大小
-
返回值
- -1 失败
- 0 读到文件末尾
- 非零正数,读到的文件大小字节数
- 非阻塞状态返回-1,此时需要判断errno的值
写
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count); -
返回值
- -1 失败
- 0 啥也没做
- 非0正数 写了多少字节数
用读写实现cat
STDOUT是file *类型的,fd是int类型的,虽然指向同一个,但类型不同
#include<stdio.h>
#include<sys/typesh>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
if(argc!=2){
printf("./a.out filename\n");
return -1;
}
int fd=open(argv[1],O_RDONLY); // 第一个参数要打开读的文件名
//read ,put to screen
char buf[1024];
int ret=read(fd,buf,sizeof(buf)); // 第一个参数文件描述符,返回读出的字节数
write(STDOUT_FILENO,buf,ret); // 输出到屏幕,第一个参数可以写 1
//write(1,buf,ret); // 一样
close(fd);
return 0;
}
执行此代码:
gcc myCat.c // 生成可执行文件 a.out
./a.out myCat.c // 把.c文件读到屏幕上
练习2、
需求,打开一个文件,写入“hello world " 在输出到屏幕
自己写了一个:但是没有输出到屏幕
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
if(argc!=2){
printf("./a.out filename");
return -1;
}
close(1); // 把标准输出(输出到屏幕这个给关了)
int fd=open(argv[1],O_RDWR|O_CREAT,0666); // 打开的这个文件占用标准输出的文件符
printf("hello world\n"); // 输出hello world 其实是写入到fd 那个文件的过程中,现在还在缓冲区
fflush(stdout); // 把缓冲区的hello world 写入到 fd的那个文件
//read ,put to screen
char buf[1024];
int ret=read(fd,buf,sizeof(buf)); // 读那个文件
//write(STDOUT_FILENO,buf,ret);
write(1,buf,ret); //
close(fd);
return 0;
}
因为读写位置更改了,要用lseek()函数来调回去 读写位置
函数:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
- fd 文件描述符
- offset 偏移量 一般设置成0
- whence
- SEEK_SET 文件开始位置
- SEEK_CUR 当前位置
- SEEK_END 结尾位置
- 返回值
- 成功 从当前位置到文件开始位置的字节数
- 失败 -1 并设置err no
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
if(argc!=2){
printf("./a.out filename\n");
return -1;
}
int fd=open(argv[1],O_RDWR|O_CREAT,0666);
write(fd,"hello world\n",12); // 直接写world hello到打开的那个文件
// 此时文件读写位置已经在文件末尾了
//需要把文件读写位置移动到文件开始
lseek(fd,0,SEEK_SET); // 把读写位置回到最初的位置,为输出到屏幕做准备,不然已经读到文件末尾了,输出到屏幕就没有内容了
//read ,put to screen
char buf[1024]={0};
int ret=read(fd,buf,sizeof(buf));
//write(STDOUT_FILENO,buf,ret);
write(STDOUT_FILENO,buf,ret);
close(fd);
return 0;
}
lseek()函数
作用:
1、调整文件读写位置
2、获取文件大小,(返回值)
3、扩展文件
作用2
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
if(argc!=2){
printf("./a.out filename\n");
return -1;
}
int fd=open(argv[1],O_RDONLY);
int ret=lseek(fd,0,SEEK_END);
printf("file size if %d\n",ret);
close(fd);
return 0;
}
作用3
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
if(argc!=2){
printf("./a.out filename\n");
return -1;
}
int fd=open(argv[1],O_WRONLY|O_CREAT,0666);
int ret=lseek(fd,1024,SEEK_END);
//需要至少写一次才能生效
write(fd,"h",1);
printf("file size if %d\n",ret);
close(fd);
return 0;
}
read函数的阻塞等待
在读设备时候会期待读的东西,如果设备没有输入,就会阻塞等待
open函数的第一个参数:文件名,可以是双引号之间的路径,如下例子
之前的open函数的第一个参数是argv[1],由命令行输入文件名
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
int fd=open("/dev/tty",O_RDWR); //
//int fd=open("/dev/tty",O_RDWR|O_NONBLOCK); // 设置打开之后非阻塞状态
char buf[256]={0};
int res=0;
while(1){
res=read(fd,buf,sizeof(buf)); // zu se
if(res<0){
perror("read err:");// 输出错误信息
printf("res is %d\n",res);
}
if(res){
printf("buf is %s\n",buf);
}
printf("hahahah");
sleep(2); // 当非阻塞状态时候,while循环,睡一下,不然一直滚动了
}
close(fd);
return 0;
}
fcntl()函数
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
int main(int argc,char * argv[])
{
//int fd=open("/dev/tty",O_RDWR|O_NONBLOCK);
int fd=open("/dev/tty",O_RDWR);
//角色函数,设置非阻塞
int flags=fcntl(fd,F_GETFL);
flags |=O_NONBLOCK;
fcntl(fd,F_SETFL,flags);
char buf[256]={0};
int res=0;
while(1){
res=read(fd,buf,sizeof(buf)); // zu se
if(res<0){
perror("\nread err:");
printf("res is %d\n",res);
}
if(res){
printf("buf is %s\n",buf);
}
printf("hahahah");
sleep(10);
}
close(fd);
return 0;
}
二、文件目录API接口
1、掌握stat/lstat函数的使用
2、了解文件属性相关函数使用
3、了解目录操作相关函数使用
4、掌握目录遍历相关函数的使用
5、掌握dup,dup2函数的使用
6、掌握fcntl函数的使用
进程的虚拟地址空间:
2.2 查看打开的最大的文件个数
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
int num=3;
char filename[128]= {0};
while(1)
{
sprintf(filename,"tem_%4d",num++);
if(open(filename,O_RDONLY|O_CREAT,0666)<0)
{
perror("open err");
break;
}
close(num);
}
printf("num is %d\n",num);
return 0;
}
2.3.stat函数
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf); // 获取文件信息
结构体信息:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */ //节点号
mode_t st_mode; /* File type and mode */ // 文件类型和权限
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
节点信息:
还可以 vim ./
//来显示当前目录下的文件,再点一下才进入相应目录
mode_t st_mode; //文件权限
时间结构体:
grep -rn "struct timespec {" /usr/ //查看这个结构体,带个{更快查找
vim +10 /usr/include/linux/time.h //在这个文件里边找到了,就把它打开
struct timespec {
__kernel_time_t tv_sec; /* seconds */ // 目前时间到1970年一月一日,0:0:0的秒数
long tv_nsec; /* nanoseconds */ // 纳秒,(微秒,毫秒)
};
stat函数使用
* pathname:文件名
* struct stat 类型的 *statbuf // 传出参数 先定义struct stat sb,&sb
* 返回值
* 成功返回0,失败-1,设置errno
写一个使用的简单例子
#include<stdio.h>
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc,char * argv[])
{
if(argc!=2)
{
printf("err pathname\n");
return -1;
}
struct stat sb;
stat(argv[1],&sb);
return 0;
}
写makefile文件
SrcFiles=$(wildcard *.c)
TargetFiles=$(patsubst %.c,%,$(SrcFiles))
all:$(TargetFiles)
%:%.c
gcc -o $@ $^ -g
clean:
rm -f $(TargetFiles)
在命令行使用gdb调试
gdb stat001 //gdb 那个生成的可执行文件
#在gdb环境中:
(gdb) b main // 查看主函数
(gdb) run test.cpp // 指定执行查看这个test.cpp文件
(gdb) n // 一行一行的执行
(gdb) p sb // 打印sb这个结构体
(gdb) q //退出
stat命令使用:
stat xxx.c
#得出信息,其中
最近访问:2019-12-22 17:53:13.853779014 -0800 // 访问
最近更改:2019-09-01 21:15:45.973579598 -0700 //更改内容 追加时候不改动访问时间
最近改动:2019-09-01 21:15:45.973579598 -0700 // 改动权限
实现一个ls hello显示信息:
E:\baidupan\08_Linux基础\08d04)\007
注意:
stat()函数会通过软链接,追溯到源文件显示大小,穿透!!!
而lstat()函数只会显示当前文件大小,
int lstat(const char *pathname, struct stat *statbuf); // 获取文件信息
2.4 access函数
返回当前用户对文件的权限,和是否存在
#inlude <unistd.h>
int access(const char *pathname, int mode);
- pathname 文件名
- mode 具体权限
- R_OK
- W_OK
- X_OK
- F_OK
- 返回值
- 如果有权限或者文件存在返回0,否则返回-1,设置errno
查看函数:
- 如果有权限或者文件存在返回0,否则返回-1,设置errno
#include<stdio.h>
#include <unistd.h>
int main(int argc,char * argv[])
{
if(argc!=2)
{
printf("./a.out pathname\n");
return -1;
}
if(access(argv[1],R_OK)==0) printf("%s,read ok\n!",argv[1]);
if(access(argv[1],W_OK)==0) printf("%s,write ok\n!",argv[1]);
if(access(argv[1],X_OK)==0) printf("%s,exe ok!\n",argv[1]);
if(access(argv[1],F_OK)==0) printf("%s,file is exists!\n",argv[1]);
return 0;
}
/*# 执行结果
txdy827@ubuntu:~/test$ ./a.out test.cpp
test.cpp,read ok
!test.cpp,write ok
!test.cpp,file is exists!
/*
2.5truncate截断文件
如果第二个参数大于原文件大小,就扩展变大,如果原文件小于第二个参数指定的大小就截断了
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
如下截断:
#include<stdio.h>
#include <unistd.h>
#include<sys/types.h>
int main(int argc,char * argv[])
{
if(argc!=2)
{
printf("./a.out pathname\n");
return -1;
}
truncate(argv[1],3);
return 0;
}