昨天遗留的问题:
33 32 31 30 6f 0a
3 2 1 0 o \n
前4个字节变了,因为程序中int*p=(int *)handle;,只改了int 型个字节,int是4个字节
p[0]=0x30313233;
int p 一次访问4个字节
p[0]=0x30313233
int arr[3]
int *p=arr
arr[0]=p[0]
作业:写一个程序,判断计算机是大端还是小端
一、 文件夹内容的读取:
文件夹内容是文件夹里的文件
怎么去获取文件夹的内容?
打开文件夹:opendir
opendir (3) 3说明不是系统调用,是库函数
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开name指定的文件夹
参数: name:文件夹路径
返回值:
NULL:打开失败,errno被设置
关闭文件夹:closedir
closedir (3)
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
参数: dirp:opendir的返回值
读取文件夹的内容:readdir
readdir(3)
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取dirp指向的文件夹的内容。调用一次,只能读取一个文件夹
参数: dirp: opendir的返回值
返回值:
NULL:到达文件夹内容的末尾(即最后一个文件)或发生了错误
如果是EBAD错误发生,说明读取文件夹内容的时候,发生了错误。否则就是到达了文件内容的最后。
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
举例:遍历文件夹目录 dir.c
1#include<stdio.h>
2#include<sys/types.h>
3#include<dirent.h>
4int main(int argc,char *argv[]){
5 DIR *dirp;
6 struct dirent *dir;
7 //打开argv[1]文件夹
8 dirp=opendir(argv[1]);
9 if(dirp==NULL){
10 perror("opendir");
11 return 1;
12 }
13 //读取文件夹的内容
14 while(dir=readdir(dirp))
15 printf("filename ... %s\n",dir->d_name);
16 //关闭文件夹
17 closedir(dirp);
18 return 0;
19 }
tarena@tarena-virtual-machine:~/day27$./a.out .
filename ... a.out
filename ... dir.c
filename ... ..
filename ... .
Myls.c !!!!!!
1#include<stdio.h>
2#include<sys/types.h>
3#include<dirent.h>
4#include<sys/stat.h>
5#include<unistd.h>
6int main(int argc,char *argv[]){
7 DIR *dirp;
8 struct dirent *dir;
9 struct stat sb;
10 //打开argv[1]文件夹
11 dirp=opendir(argv[1]);
12 if(dirp==NULL){
13 perror("opendir");
14 return 1;
15 }
16 //读取文件夹的内容
17 while(dir=readdir(dirp)){
18 printf("%s\t",dir->d_name);
19 stat(dir->d_name,&sb);
20 printf("%lld\n",(long long)sb.st_size);
21 }
22 //关闭文件夹
23 closedir(dirp);
24 return 0;
25 }
二、 软连接和硬链接文件
硬链接是两个文件的inode相同
软连接是两个文件的inode不同
举例:为a.txt创立一个硬链接文件b.txt
tarena@tarena-virtual-machine:~/day27$ vi a.txt
tarena@tarena-virtual-machine:~/day27$ ln a.txt b.txt
tarena@tarena-virtual-machine:~/day27$ ls -l
总用量 20
-rw-rw-r-- 2 tarena tarena 6 9月 2 11:16 a.txt
-rw-rw-r-- 2 tarena tarena 6 9月 2 11:16 b.txt
tarena@tarena-virtual-machine:~/day27$ cat a.txt
hello
tarena@tarena-virtual-machine:~/day27$ cat b.txt
hello
tarena@tarena-virtual-machine:~/day27$ rm a.txt
tarena@tarena-virtual-machine:~/day27$ ls –l b.txt
-rw-rw-r-- 1 tarena tarena 6 9月 2 11:16 b.txt
为b.txt建立一个软连接c.txt
tarena@tarena-virtual-machine:~/day27$ ln -s b.txt c.txt
tarena@tarena-virtual-machine:~/day27$ ls -al
总用量 24
-rw-rw-r-- 1 tarenatarena 6 9月 2 11:16 b.txt
lrwxrwxrwx 1 tarenatarena 5 9月 2 11:22 c.txt -> b.txt
tarena@tarena-virtual-machine:~/day27$ stat b.txt
文件:"b.txt"
大小:6 块:8 IO 块:4096 普通文件
设备:801h/2049d Inode:1199677 硬链接:1
权限:(0664/-rw-rw-r--) Uid:( 1000/ tarena) Gid:( 1000/ tarena)
最近访问:2016-09-02 11:22:31.865751119+0800
最近更改:2016-09-02 11:16:15.429761019+0800
最近改动:2016-09-02 11:20:41.193755859+0800
创建时间:-
tarena@tarena-virtual-machine:~/day27$ ^C
tarena@tarena-virtual-machine:~/day27$ stat c.txt
文件:"c.txt" ->"b.txt"
大小:5 块:0 IO 块:4096 符号链接
设备:801h/2049d Inode:1199674 硬链接:1
权限:(0777/lrwxrwxrwx) Uid:( 1000/ tarena) Gid:( 1000/ tarena)
最近访问:2016-09-02 11:22:57.941748959+0800
最近更改:2016-09-02 11:22:19.705750124+0800
最近改动:2016-09-02 11:22:19.705750124+0800
创建时间:-
tarena@tarena-virtual-machine:~/day27$ cat c.txt
hello
tarena@tarena-virtual-machine:~/day27$ rm b.txt
tarena@tarena-virtual-machine:~/day27$ cat c.txt
cat: c.txt: 没有那个文件或目录
结论:软连接是windows下的快捷方式,硬链接是同一个文件,不同的inode
硬链接不能跨分区(因为同一个inode只能在一个文件系统里),软连接可以跨分区。
(用a.txt建立硬链接b.txt,删了其中一个,另外一个都存在
用b.txt建立软连接c.txt,若删了c.txt,b.txt仍然存在,但删了b.txt,c.txt内容就没了,因为b.txt的inode里的内容是c.txt的文件名)
link (2)2是系统调用函数
NAME
link - makea new name for a file
SYNOPSIS
#include <unistd.h>
int link(const char *oldpath, const char*newpath);
举例: 建立硬链接:hardlink.c
1#include<stdio.h>
2#include<unistd.h>
3int main(int argc,char *argv[]){
4 int ret;
5 ret=link(argv[1],argv[2]);
6 if(ret==-1){
7 perror("link");
8 return 1;
9 }
10 printf("har link sucessful...\n");
11 return 0;
12 }
tarena@tarena-virtual-machine:~/day27$ via.txt
tarena@tarena-virtual-machine:~/day27$ cata.txt
hello
tarena@tarena-virtual-machine:~/day27$./a.out a.txt b.txt
hardlink sucessful...
tarena@tarena-virtual-machine:~/day27$ ls-l
总用量 24
-rwxrwxr-x 1 tarena tarena 7232 9月 2 11:36 a.out
-rw-rw-r-- 2 tarena tarena 6 9月 2 11:37 a.txt
-rw-rw-r-- 2 tarena tarena 6 9月 2 11:37 b.txt
-rw-rw-r-- 1 tarena tarena 234 9月 2 11:36 hardlink.c
三、 fctl文件锁的操作(死锁)
多个进程对同一个文件的同一个区域的访问只能同时读,其它的读写访问操作都不能同时进行。(能同时读,但不能一个读其它写,也不能多个进程同时写)
通过加锁的方法来解决资源互斥的问题。
锁分为建议锁 / 强制锁两种
建议锁:系统提供了这个功能,大家可用可不用
按照对资源的访问方式又分为两种:读锁(共享锁)/ 写锁(互斥锁)
临界资源:多个进程需要同时进行访问的资源
同步:事情A和事情B,先完成一个,然后再去完成另一个,称为同步。(有顺序)
异步:多个事情可以无序执行。(无顺序)
fcntl (2) fd control 对文件描述符的控制
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
功能:操作处理文件描述符
参数:
fd:要操作的文件描述符
cmd:对文件描述符的操作指令
…. :可变参数。根据cmd判断是否需要参数,需要什么样的参数
返回值:
0:成功
-1:代表失败,errno被设置
Advisory locking
F_GETLK:获取锁信息(看看要操作的文件是不是有锁,是否已被别的进行占用)
F_SETLK:设置锁信息
F_SETLKW:设置锁信息,但是是阻塞设置。等待互斥锁释放
struct flock{
short l_type; F_RDLCK,F_WRLCK, F_UNLCK 类型
short l_whence; SEEK_SET, SEEK_CUR, SEEK_END:
off_t l_start; /* Starting offset for lock */ 偏移
off_t l_len; /* Number of bytes to lock */ 被锁的字节数
pid_t l_pid; /* PIDof process blocking our lock 进程号
(F_GETLKonly) */
...
};
注意:
1、不能在同一个进程里加多个锁
2、锁的类型和文件的打开方式要一致
3、进程结束后,添加的锁全部消失
基于上述信息,实验代码参见processA.c processB.c
processA.c
1#include<stdio.h>
2#include<sys/stat.h>
3#include<sys/types.h>
4#include<fcntl.h>
5#include<unistd.h>
6int main(){
7 int fd;
8 //以只读的方式打开文件
9 fd=open("a.txt",O_RDONLY);
10 if(fd==-1){
11 perror("open");
12 return 1;
13 }
14 //声明一个锁变量,并初始化变量
15 struct flock lock;
16 lock.l_type=F_RDLCK;//读锁
17 lock.l_whence=SEEK_SET;
18 lock.l_start=0;
19 lock.l_len=0;
20 //为文件描述符fd添加一把读锁
21 if(fcntl(fd,F_SETLK,&lock)==-1){//若添加失败
22 perror("fcntl");
23 return 2;
24 }
25 //若成功
26 printf("添加读锁成功...\n");
27 sleep(20);
28 close(fd);
29 }
processB.c
1#include<stdio.h>
2#include<sys/stat.h>
3#include<sys/types.h>
4#include<fcntl.h>
5#include<unistd.h>
6int main(){
7 int fd;
8 //以写的方式打开文件
9 fd=open("a.txt",O_RDWR|O_CREAT,0644);
10 if(fd==-1){
11 perror("open");
12 return 1;
13 }
14 //声明一个锁变量,并初始化变量
15 struct flock lock;
16 lock.l_type=F_WRLCK;//写锁
17 lock.l_whence=SEEK_SET;
18 lock.l_start=0;
19 lock.l_len=0;
20 //为文件描述符fd添加一把写锁,如果文件有其他锁,则等到文件锁释放再加锁
21 if(fcntl(fd,F_SETLKW,&lock)==-1){//若添加失败
22 perror("fcntl");
23 return 2;
24 }
25 //若成功
26 printf("添加写锁成功...\n");
27 sleep(20);
28 close(fd);
29 }
tarena@tarena-virtual-machine:~/day27$ gccprocessA.c -o pa
tarena@tarena-virtual-machine:~/day27$ gccprocessB.c -o pb
在第一个终端里输入指令:
tarena@tarena-virtual-machine:~/day27$ ./pa
在第二个终端里输入指令:
tarena@tarena-virtual-machine:~/day27$ ./pb
pa对文件a.txt加了文件读锁,pb等着给文件a.txt加写锁,20秒后,进程pa结束,读锁释放,则pb对a.txt加写锁。
若processB.c中改成
21 if(fcntl(fd,F_SETLK,&lock)==-1)
则processA.c加过读锁后,processB加锁失败
tarena@tarena-virtual-machine:~/day27$ ./pb
fcntl: Resource temporarily unavailable 因为去掉了SETLKW中的W,waiting,就不等待
processC.c
1#include<stdio.h>
2#include<sys/stat.h>
3#include<sys/types.h>
4#include<fcntl.h>
5#include<unistd.h>
6int main(){
7 int fd;
8 //以只读的方式打开文件
9 fd=open("a.txt",O_RDONLY);
10 if(fd= = -1){
11 perror("open");
12 return 1;
13 }
14 //声明一个锁变量,并初始化变量
15 struct flock lock;
16 lock.l_type=F_RDLCK;//读锁
17 lock.l_whence=SEEK_SET;
18 lock.l_start=0;
19 lock.l_len=0;
20 //为文件描述符fd添加一把读锁
21 if(fcntl(fd,F_SETLK,&lock)==-1){//若添加失败
22 perror("fcntl");
23 return 2;
24 }
25 //若成功
26 printf("添加读锁成功...\n");
27 // sleep(20); 去掉
28 close(fd);
29 }
结果是processA.c对a.txt加读锁在等待20秒的时候,processC.c对文件直接加了读锁
说明,可以同时对文件加读锁
四、知识杂项
access (2) 系统调用
NAME
access - check real user's permissionsfor a file
SYNOPSIS
#include <unistd.h>
int access(const char *pathname, intmode);
功能:测试一个进程对文件的操作权限
参数:pathname:文件路径
mode :文件权限
返回值:
0:代表成功
-1:失败,error被设置
vi access.c
1 #include<stdio.h>
2 #include<sys/stat.h>
3 #include<sys/types.h>
4 #include<unistd.h>
5 int main(int argc,char *argv[]){
6 if(access(argv[1],F_OK)==0)
7 printf("file ok...\n");
8 if(access(argv[1],W_OK)==0)
9 printf("file write...\n");
10 if(access(argv[1],R_OK)==0)
11 printf("file read...\n");
12 if(access(argv[1],X_OK)==0)
13 printf("file exetive...\n");
14 return 0;
15 }
tarena@tarena-virtual-machine:~/day27$gcc access.c -o access
tarena@tarena-virtual-machine:~/day27$./access a.txt
file ok...
file write...
file read...
tarena@tarena-virtual-machine:~/day27$ls -l a.txt
-rw-rw-r-- 2tarena tarena 6 9月 2 11:37 a.txt
!!!!
Mycp.c
1 #include<stdio.h>
2 #include<sys/stat.h>
3 #include<sys/types.h>
4 #include<unistd.h>
5 #include<strings.h>
6 #include<fcntl.h>
7 long int fcp(int sfd,int dfd);
8 int main(int argc,char *argv[]){
9 int sfd,dfd;
10 int ret;
11 int flags=O_RDWR|O_CREAT|O_TRUNC;
12 sfd=open(argv[1],O_RDONLY);
13 dfd=open(argv[2],flags,0644);
14 if(sfd==-1||dfd==-1){ //要传的这些参数要在函数外面做检测
15 perror("open");
16 }
17 ret=fcp(sfd,dfd);
18 if(ret==-1){
19 printf("文件复制失败\n");
20 return 1;
21 }
22 close(sfd);
23 close(dfd);
24 return 0;
25 }
26 /*
27 功能:复制sfd文件的内容到dfd中
28 sfd:源文件
29 dfd:目标文件
30 返回值:
31 文件的大小
32 -1:代表出错
33 */
34 long int fcp(int sfd,int dfd){
35 char buf[1024]={0};
36 int r_cnt,w_cnt;
37 long sum=0;
38 char *tmp;
39 /* r_cnt=read(sfd,buf,1024);
40 1024是想读的,r_cnt是真实读到的
41 w_cnt=write(dfd,buf,r_cnt);
42 r_cnt是想写的,w_cnt是真实写入的 */
43 while((r_cnt=read(sfd,buf,1024))!=0){
44 tmp=buf;
45 while((w_cnt=write(dfd,tmp,r_cnt))!=0){
46 r_cnt=r_cnt-w_cnt;
47 tmp+=w_cnt;
48 sum+=w_cnt;
49 }
50 bzero(buf,1024);
51 }
52 return sum;
53 }
tarena@tarena-virtual-machine:~/day27$gcc mycp.c -o mycp
tarena@tarena-virtual-machine:~/day27$./mycp mycp.c mycp.2 成功复制文件
自己练习:
unlink
rename
symlink 软链接
chdir
mkdir
rmdir