我要成为嵌入式高手之2月19日Linux高编第四天!!
______________________________________________________
练习
练习1:利用read和write实现文件内容的拷贝(将src.jpg中的内容拷贝到dst.jpg文件中)
#ifndef _HEAD_H
#define _HEAD_H
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#endif
#include "head.h"
int main(int argc, const char *argv[])
{
int src = 0;
int dst = 0;
char tmpbuff[4096] = {0};
ssize_t nret = 0;
if (argc != 3)
{
fprintf(stderr,"Usage: ./a.out srcfilename dstfilename\n");
return -1;
}
src = open(argv[1], O_RDONLY);
if (src == -1)
{
perror("fail to open src");
return -1;
}
dst = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (dst == -1)
{
perror("fail to open dest");
return -1;
}
while(1)
{
nret = read(src, tmpbuff, sizeof(tmpbuff));
if (nret == 0)
{
break;
}
write(dst, tmpbuff, nret);
}
close(src);
close(dst);
return 0;
}
新知识点:主函数传参,在编译之后运行的时候将参数传入主函数
int main (int argc, const char *argv[ ])
参数:
argc:要传的参数个数
argv:要传的参数的首地址(char* 型)
cahr *argv[ ]:存放要操作的文件的地址的数组(指针数组)
练习2:1028 人口普查 - PAT (Basic Level) Practice (中文) (pintia.cn)
#include "head.h"
typedef struct person
{
char name[8];
char birthday[12];
}person_t;
int main(void)
{
person_t a[100000];
int n = 0;
int i = 0;
int cnt = 0;
char maxvalue[12] = {"2014/09/06"};
char minvalue[12] = {"1814/09/06"};
int curmax = 0;
int curmin = 0;
scanf("%d",&n);
for (i = 0; i < n; ++i)
{
scanf("%s%s",a[i].name,a[i].birthday);
}
for (i = 0; i < n; ++i)
{
if (strcmp(a[i].birthday,maxvalue) <= 0 && strcmp(a[i].birthday,minvalue) >= 0)
{
cnt++;
if (cnt == 1)
{
curmin = curmax = i;
}
if (strcmp(a[i].birthday,a[curmax].birthday) > 0)
{
curmax = i;
}
if (strcmp(a[i].birthday,a[curmin].birthday) < 0)
{
curmin = i;
}
}
}
printf("%d %s %s\n",cnt,a[curmin].name,a[curmax].name);
return 0;
}
学习笔记
一、文件IO
lseek
off_t lseek(int fd, off_t offset, int whence);
功能:重新设定文件描述符的偏移量
参数:
fd:文件描述符
offset:偏移量
whence:开始偏移的位置
SEEK_SET 文件开头
SEEK_CUR 文件当前位置
SEEK_END 文件末尾
返回值:成功返回当前偏移量,失败返回-1;
#include "head.h"
int main(void)
{
int fd = 0;
off_t len = 0;
char ch = 0;
fd = open("a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (-1 == fd)
{
perror("fail to open");
return -1;
}
len = lseek(fd, 10, SEEK_SET);
printf("len = %ld\n",len);
ch = 'A';
write(fd, &ch, 1);
len = lseek(fd, -5, SEEK_CUR);
printf("len = %ld\n",len);
ch = 'B';
write(fd, &ch, 1);
len = lseek(fd, 0, SEEK_SET);
printf("len = %ld\n",len);
ch = 'C';
write(fd, &ch, 1);
close(fd);
return 0;
}
二、目录IO
1、mkdir
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
功能:创建目录文件
参数:
pathname:文件路径
mode:文件的权限
rwx rwx rwx:x目录是否能进入 w目录是否能新建文件 r目录是否能查看文件
111 111 111
0 7 7 7
返回值:成功返回0,失败返回-1:
#include "head.h"
int main(void)
{
mkdir("dir11",0777);
return 0;
}
2、rmdir
#include <unistd.h>
int rmdir(const char *pathname);
功能:删除空目录文件
返回值:成功返回0,失败返回-1
3、opendir
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name); (DIR * 目录流指针)
功能:打开目录,获得目录流指针
参数:
name:目录文件的路径
返回值:成功返回目录流指针,失败返回空
4、closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭目录流指针
5、readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:从目录流中读取下一个目录项的结构体信息
参数:dirp 目录流指针
返回值:
成功返回包含目录项信息的空间首地址
失败或者读到文件末尾返回NULL
struct dirent {
ino_t d_ino; /* Inode number */(标号)
off_t d_off; /* Not an offset; see below */(偏移量)
unsigned short d_reclen; /* Length of this record */(大小)
unsigned char d_type; /* Type of file; not supported(文件类型)
by all filesystem types */
char d_name[256]; /* Null-terminated filename */(包含了一个 \ 0 的文件名)
};
3、4、5使用:
#include "head.h"
int main(void)
{
DIR *dp = NULL;
struct dirent *pp = NULL;
dp = opendir("dir");
if (dp == NULL)
{
perror("fail to opendir");
return -1;
}
while (1)
{
pp = readdir(dp);
if (pp == NULL)
{
break;
}
if (*pp->d_name == '.')
{
continue;
}
printf("%s\n",pp->d_name);
}
closedir(dp);
return 0;
}
6、chdir
#include <unistd.h>
int chdir(const char *path);
功能:切换到path目录工作路径(改变路径)
7、getcwd
#include <unistd.h>
char *getcwd(char *buf, size_t size);
功能:获得当前目录的绝对路径
6、7使用
#include "head.h"
int main(void)
{
char tmpbuff[4096] = {0};
getcwd(tmpbuff,sizeof(tmpbuff));
printf("tmpbuff = %s\n",tmpbuff);
chdir("..");
getcwd(tmpbuff,sizeof(tmpbuff));
printf("tmpbuff = %s\n",tmpbuff);
return 0;
}
练习1(难):
递归遍历
#include "head.h"
int ListDir(const char *pdirname)//遍历pdirname目录下所有文件的信息
{
DIR *dp = NULL;//接收opendir返回的一个dir型指针
struct dirent *pp = NULL;//接收readdir返回的结构体
char tmpbuff[4096] = {0};
dp = opendir(pdirname);
if (NULL == dp)
{
perror("fail to opendir");
return -1;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == *pp->d_name)
{
continue;
}
sprintf(tmpbuff, "%s/%s", pdirname, pp->d_name);
//要读的文件夹的名字和该文件夹下所有文件的名字,组合而成就是路径,将该路径存入tmpbuff中
printf("%s\n",tmpbuff);
if (pp->d_type == DT_DIR)//D_TYPE文件类型,文件类型为DT_DIR(文件夹类型)时,再次调用函数
{
ListDir(tmpbuff);//递归调用
}
}
closedir(dp);
return 0;
}
int main(int argc, const char *argv[])
{
if (argc != 2)
{
fprintf(stderr,"Usage: ./a.out dirname\n");
return -1;
}
ListDir(argv[1]);
return 0;
}
6、accsee
#include <unistd.h>
int access(const char *pathname, int mode);
功能:检测调用函数的程序对文件是否拥有指定权限
参数:
pathname:文件路径
mode:
R_OK 是否拥有读权限
W_OK 是否拥有写权限
X_OK 是否拥有执行权限
F_OK 是否存在
返回值:有该权限返回0,没有返回-1;
#include "head.h"
int main(int argc,const char *argv[])
{
int ret = 0;
if (argc != 2)
{
fprintf(stderr,"Usage: ./a.out filename\n");
return -1;
}
ret = access(argv[1],F_OK);
if (ret == 0)
{
printf("该文件存在!\n");
}else
{
printf("该文件不存在!\n");
}
return 0;
}
练习2(难):
编写一个程序,分两次执行,第一次执行后,再次执行时打印出两个执行过程中间,指定目录下新增的文件及删除的文件
#include "head.h"
#define RECORD_PATH "record.bk"
int ListDir(const char *pdirname,FILE *file)//每次递归调用仍然传的是流指针,流指针具有偏移量,会随着写入自动向后增加
{
DIR *dp = NULL;
struct dirent *pp = NULL;
char tmpbuff[1024] = {0};
dp = opendir(pdirname);
if (NULL == dp)
{
perror("fail to opendir");
return -1;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == *pp->d_name)
{
continue;
}
sprintf(tmpbuff,"%s/%s", pdirname, pp->d_name);
fprintf(file, "%s\n", tmpbuff);
if (DT_DIR == pp->d_type)//判断文件类型若为文件夹类型
{
ListDir(tmpbuff, file);//递归调用
}
}
closedir(dp);
return 0;
}
int ListDirToRecord(const char *pdirname)//第一次执行
{
FILE *fp = NULL;
fp = fopen(RECORD_PATH,"w");
if (fp == NULL)
{
perror("fail to fopen");
return -1;
}
ListDir(pdirname, fp);//遍历到的结果写入流中
fclose(fp);
return 0;
}
int ShowDeleteFiles(void)
{
FILE *fp = NULL;
char tmpbuff[4096] = {0};
char *pret = NULL;
fp = fopen(RECORD_PATH, "r");//打开dk文件检查是否存在
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (1)//判断读取到的全部文件是否存在,直到文件末尾
{
pret = fgets(tmpbuff, sizeof(tmpbuff), fp);//每次读取一行
if (NULL == pret)//文件末尾
{
break;
}
tmpbuff[strlen(tmpbuff)-1] = '\0';//fgets读到\n停止,但是文件名里没有\n,故应该去掉\n
//tmpbuff[strlen(tmpbuff)] \0的位置
if (access(tmpbuff, F_OK) != 0)//判断读取到的文件是否存在
{
printf("%s\n",tmpbuff);//打印不存在的文件
}
}
fclose(fp);
return 0;
}
int IsNewFile(char *pfilepath)//判断新的文件pfliepath在dk列表里是否出现过
{
FILE *fp = NULL;
char tmpbuff[4096] = {0};
char *pret = NULL;
fp = fopen(RECORD_PATH, "r");
if (NULL == fp)
{
perror("fail to fopen");
return -1;
}
while (1)//判断文件的每一行与pfilepath是否相同
{
//读一行,置成\0,判断相不相同,相同则不是新文件,直到文件末尾也不相同,就是新文件
pret = fgets(tmpbuff, sizeof(tmpbuff), fp);
if (pret == NULL)//读到文件末尾
{
break;
}
tmpbuff[strlen(tmpbuff)-1] = '\0';//读到的有换行,需要将换行置成\0
if (strcmp(tmpbuff, pfilepath) == 0)
{
fclose(fp);
return 0;
}
}
fclose(fp);
return 1;//没有return0 确实是新文件,return1
}
int ListDir2(const char *pdirname)//不需要写入,只需要查找
{
DIR *dp = NULL;
struct dirent *pp = NULL;
char tmpbuff[1024] = {0};
dp = opendir(pdirname);
if (NULL == dp)
{
perror("fail to opendir");
return -1;
}
while (1)
{
pp = readdir(dp);
if (NULL == pp)
{
break;
}
if ('.' == *pp->d_name)
{
continue;
}
sprintf(tmpbuff,"%s/%s", pdirname, pp->d_name);
if (IsNewFile(tmpbuff))//判断是不是新的文件
{
printf("%s\n",tmpbuff);//若为新的文件,就进行打印
}
if (DT_DIR == pp->d_type)//判断文件类型若为文件夹类型
{
ListDir2(tmpbuff);//递归调用
}
}
closedir(dp);
return 0;
}
int ShowNewFiles(const char *pdirname)
{
ListDir2(pdirname);
return 0;
}
int main(void)
{
int ret = 0;
ret = access(RECORD_PATH, F_OK);
if (ret == 0)
{
printf("删除的文件:\n");
ShowDeleteFiles();
printf("新增的文件:\n");
ShowNewFiles(".");
}else
{
ListDirToRecord(".");
}
}