Linux系统编程
man man帮助手册
man 2 fopen()
注意:
-
指针类型的返回值,主调函数需要释放内存
- 系统调用返回值不实现功能,只用来处理报错
- 指针类型的参数,主调函数开辟空间把地址做参数传递
文件
文件类型:
- 普通文件
- 目录文件
- 软链接
- 字符设备文件 鼠标
- 块设备文件 磁盘
- 管道文件 通信
- socket 网络
全局变量 errno ->perror();
fopen(path,mode)
库函数
FILE* fp = fopen(argv[1],”a+”);
mode:
"a" 只写追加-》默认从文件结尾写入
"a+" 读写追加 打开时ptr处于文件开始base,写入时处于文件结尾
日志系统
追加模式打开文件:
fread(buf,1,1024,fp);
puts(buf);
fseek(fp,0,SEEK_SET);//fp.ptr移到开头
printf("loc=%ld",ftell(fp));//打印fp.ptr指向位置
fwrite("hello",1,1024,fp);//追加模式,ptr还是处于末尾写入
chmod(path,mode_t)
修改目录权限
#include <func.h>
int main(int argc,char* argv[])
{
//.chmod dir1 777
ARGS_CHECK(argc,3);
mode_t mode;
sprintf(argv[2],"%o",&mode);
int ret = chmod(argv[1],mode);
ERROR_CHECK(ret,-1,"chmod");
}
getcwd(buf,size)
获取当前工作目录
-
buf不为空,返回buf
-
如果buf是空指针,size=0,自动申请堆空间返回
char buf[1024]={0};
char* ret = getcwd(buf,sizeof(buf));
printf("getcwd=%s ",getcwd(NULL,0));
chdir(path)
修改工作目录
- cwd是进程属性,shell父进程,getcwd子进程,chdir修改的子进程工作目录
./chdir dir1
ARGS_CHECK(argc,2);
int ret = chdir(argv[1]);
ERROR_CHECK(ret,-1,"chdir");
mkdir(path,mode_t)
创建目录
./mkdir dir1 777
ARGC_CHECK(argc,3);
mode_t mode;
sprintf(argv[2],"%o",&mode);
int ret = mkdir(argv[1],mode);
ERROR_CHECK(ret,-1,"mkdir");
rmdir(path)
删除目录
./rmdir dir1
ARGC_CHECK(argc,2);
int ret = rmdir(argv[1]);
ERROR_CHECK(ret,-1,"rmdir");
目录流
- 是目录文件在内存中的缓冲区
opendir(path)
打开目录流
DIR* dirp = opendir(argv[1]);
ERROR_CHECK(dirp,NULL,"opendir");
readdir(dirp)
读取目录流
-
返回值结点指针struct dirent*
-
d_type
struct dirent* pdirent = readdir(dirp);
遍历目录ls
// ./ls dir
ARGC_CHECK(argc,2);
DIR* dirp = opendir(argv[1]);
ERROR_CHECK(dirp,NULL,"opendir");
errno = 0;
struct dirent* pdirent;
while((pdirent = readdir(dirp)) != NULL){
printf("ino = %ld reclen=%d type=%d name=%s\n",
pdirent->d_ino,pdirent->d_reclen,pdirent->d_type,pdirent->d_name);
}
if(errno){
perror("readdir");
exit(1);
}
closedir(dirp);
telldir(dirp)
- readdir(dirp)后,ptr指向结点的下一个结点
获取ptr的位置
long loc = telldir(dirp);
seekdir(dirp,long)
把ptr定位到loc位置
seekdir(dirp,loc);
rewinddir(dirp)
把ptr回到开始位置
rewinddir(dirp)
stat(path,statbuf)
stat函数:取得指定文件的文件属性,文件属性存储在结构体stat里
-
struct stat* statbuf
-
st_mode
- getpwuid()获取用户id
-
getgrgid()获取组id
- ctime() gmtime() localtime() 获取时间
//实现./ls -al dir
#include <func.h>
int main(int argc,char *argv[]){
ARGC_CHECK(argc,3);
DIR* pdir = opendir(argv[2]);
ERROR_CHECK(pdir,NULL,"opendir");
char str[11]={0};
memset(str,'-',sizeof(str)-1);
//文件类型
if(S_ISREG(sbuf.st_mode)) str[0] = '-';
if(S_ISDIR(sbuf.st_mode)) str[0] = 'd';
if(S_ISCHR(sbuf.st_mode)) str[0] = 'c';
if(S_ISBLK(sbuf.st_mode)) str[0] = 'b';
if(S_ISFIFO(sbuf.st_mode)) str[0] = 'p';
if(S_ISLNK(sbuf.st_mode)) str[0] = 'l';
if(S_ISSOCK(sbuf.st_mode)) str[0] = 's';
//本用户的文件权限
if(sbuf.st_mode & S_IRUSR) str[1] = 'r';
if(sbuf.st_mode & S_IWUSR) str[2] = 'w';
if(sbuf.st_mode & S_IXUSR) str[3] = 'x';
//本用户的组的文件权限
if(sbuf.st_mode & S_IRGRP) str[4] = 'r';
if(sbuf.st_mode & S_IWGRP) str[5] = 'w';
if(sbuf.st_mode & S_IXGRP) str[6] = 'x';
//其他用户的文件权限
if(sbuf.st_mode & S_IROTH) str[7] = 'r';
if(sbuf.st_mode & S_IWOTH) str[8] = 'w';
if(sbuf.st_mode & S_IXOTH) str[9] = 'x';
struct dirent* pdirent;
struct stat sbuf;
while((pdirent = readdir(pdir))!=NULL)
{
char* name[] = pdirent->d_name;
stat(name,&sbuf);
//取得日期和时间
char time[20] = {0};
struct tm* tm = localtime(&sbuf.st_atim.tv_sec);
sprintf(time, "%2d月 %2d %02d:%02d", tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour + 1,tm->tm_sec);
//drwxrwxr-x 2 liyf liyf 4096 6月 13 12:22 dir
printf("%s %ld %s %s %ld %s %s\n",str, sbuf.st_nlink, getpwuid(sbuf.st_uid)->pw_name,
getgrgid(sbuf.st_gid)->gr_name, sbuf.st_size,time ,name);
}
if(errno){
perror("readdir");
exit(1);
}
close(pdir);
}
实现tree命令
int directories = 0,files = 0;
void dfs_print(char* path,int width){
DIR* pdir = opendir(path);
ERROR_CHECK(pdir,NULL,"opendir");
errno = 0;
struct dirent* pdirent;
while((pdirent = readdir(pdir))!=NULL){
char* name = pdirent->d_name;
//if(strcmp(name,".")==0||strcmp(name,"..")==0){
// continue;
//}
if(name[0]=='.'){
contiune;
}
//缩进
for(int i =0 ;i<width;i++){
if(i<width-4)
printf(" ");
else
printf("-");
}
puts(name);
if(pdirent->d_type == DT_DIR){
directories++;
char director[512];
sprintf(director,"%s/%s",path,name);
dfs_print(director,width+4);
}
else{
files++;
}
}
if(errno){
perror("readdir");
exit(1);
}
closedir(pdir);
}
./tree dir
int main(int argc,char* argv[]){
ARGC_CHECK(argc,2);
puts(argv[1]);
dfs_print(argv[1],4);
printf("directories=%d,files=%d\n",directories,files);
return 0;
}
strlen()读到第一个为零位置结束
read 磁盘文件 读到字节<=count,每次read,pos后移,若缓冲区无数据,返回0读完,
read 设备文件 若缓冲区无数据,进程陷入阻塞,ctrl+d文件终止,阻塞不占用cpu
读写二进制文件
fread/fwrite对比read/write
文件映射 mmap
lseek
FILE和文件对象
重定向
重定向stdout,更改1号fd引用的文件对象
dup复制文件描述符 选择最小可用文件描述符
有名管道
mkfifo 1.pipe 创建管道 文件大小永远是0
一读一写,两端都执行,只执行一端会阻塞
open会引发阻塞,等到对端也被open了,才会恢复就绪