系统I/O函数

系统I/O

1、打开文件

#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:打开文件的标记

mode:指定创建的文件的权限,当第二个参数中存在“O_CREAT”,必须指定创建文件的权限

返回值:
成功打开一个文件,返回打开的文件的文件描述符,失败返回-1。

 

2、读文件

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);        

fd:你要从哪一个文件中读取

buf:指针,指向一段可用的空间,表示你要把文件的内容读到哪里去

count:表示你要读取多少个字节

返回值:
返回实际读取到的字节的数量
>0  实际读取到的字节的数量(<=count)
=0  表示读到文件的末尾了
-1  表示读取失败,同时errno被设置

 

3、写文件

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

fd:你要写到哪一个文件中去

buf:你要写入的内容存储在哪一个位置

count:你要写入的字节数

返回值:
返回实际写入到的字节的数量
>0  实际写入的字节的数量(<=count)
=0  表示什么也没有写入
-1  表示写入失败,同时errno被设置

 

4、定位光标

#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);        

fd:文件描述符,表示你要对哪一个文件定位

offset:偏移量,具体的新位置和第三个参数结合使用

whence:定位方式有三种:
SEEK_SET   基于文件开头定位
新光标位置=文件开头+offset(>0)
SEEK_CUR   基于光标当前位置定位
新光标位置=文件当前光标位置+offset(可正可负)
SEEK_END   基于文件末尾定位
新光标位置=文件末尾+offset(可正可负)    
负:往前面偏移
正:往后面偏移“留空洞”

返回值:

成功返回新光标离文件开头的字节数,失败返回-1,同时errno被设置

 

5、关闭文件

#include <unistd.h>

int close(int fd);

没什么好说的,fd就是要关闭的文件描述符。

 

6、设置文件的创建掩码

#include <sys/types.h>
#include <sys/stat.h>

umask中权限为1的bit位,在创建文件的时候不能被指定(屏蔽掉)
umask命令输出当前的文件掩码
umask
0022->000 010 010
在创建文件的时候,不能指定掩码中为1的权限位(mode = mode & (~mask))
000 010 010        (mask)
111 101 101         (~mask)     
& 110 110 100      (mode):0664
= 110 100 100                

 mode_t umask(mode_t mask);
mask:你要指定的文件的掩码
 返回值:
 返回上一次的文件掩码

 

7、获取当前的工作目录

#include <unistd.h>
把获取到的当前工作目录的绝对路径名称保存到buf指向的内存地址(必须可用)
char *getwd(char *buf);
buf:用来保存获取到的工作路径的“字符串”
返回值:
成功返回当前工作路径的首地址(buf)
失败返回NULL,同时errno被设置
getwd有一个很大的BUG,可能会造成内存越界,如果buf指向的空间不够大(当前的工作目录字符串长度超过了buf指向的空间的长度)
getwd就有可能会访问buf后面的内存空间,有可能会造成内存的非法访问,为了解决这个bug就有了getcwd

char *getcwd(char *buf, size_t size);

buf:用来保存获取到的工作路径的“字符串”
size:用来说明buf指向的空间的最大可用长度,如果当前工作路径字符串长度大于size-1,
这个函数就会报错,并且把错误码设置为:ERANGE
返回值:
成功返回当前工作路径的首地址(buf)
失败返回NULL,同时errno被设置   

char *get_current_dir_name(void);
也是用来获取当前进程的工作路径的,只不过,这个函数不需要你给定内存空间,会自动的malloc足够长的空间来保存当前进程的工作路径,并且把malloc的首地址返回,为了防止内存泄漏,调用者使用完后,应该free这个空间
返回值:成功返回当前工作路径的首地址(malloc的空间的地址)
            失败返回NULL,同时errno被设置

 

8、修改当前的工作目录

#include <unistd.h>

int chdir(const char *path);
path:要切换的工作路径的目录字符串

int fchdir(int fd);    
fd:文件描述符,切换前要先打开这个文件

返回值:
成功返回0
失败返回-1,同时errno被设置

 

9、文件截短

int truncate(const char *path, off_t length);

path:要截短的文件的路径名
length:截短后的文件的内容的长度

int ftruncate(int fd, off_t length);

fd:要截短的文件,先使用open打开
length:截短后的文件的内容的长度
    
length < 原来的长度,截短
length > 原来的长度,“留空洞”(lseek)
返回值:
成功返回0
失败返回-1,同时errno被设置    

 

10、删除一个文件

unlink  删除一个普通文件
rmdir   删除一个空目录

remove 用来删除一个普通文件或者一个空目录
remove 用来删除一个普通文件  --->unlink
remove 用来删除一个空目录      --->rmdir

#include <unistd.h>

int unlink(const char *pathname);
pathname:要删除的文件的路径名
返回值:
成功返回0
失败返回-1,同时errno被设置
unlink(删除一个文件),仅仅是把要删除的文件对应的inode删除(仅仅是做了一个标记,表示这个inode未被使用)======>删除一个文件仅仅是把文件对应的inode中的硬连接数减一,当硬连接数量为0的时候,表示inode未被使用。

硬链接(ln):原理是多个名字对应一个inode
软连接(ln -s):软连接有单独的文件名,软连接的文件内容是被连接的文件的文件名

 

#include <unistd.h>
int rmdir(const char *pathname);

#include <stdio.h>
int remove(const char *pathname);

 

11、创建一个文件或目录

文件:create/open
目录:mkdir

 

12、获取文件属性

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
stat是用来获取pathname指定的文件的属性信息的,把获取到的属性保存到buf指向的结构体中(buf必须指向一个可以的空间)
pathname:要获取属性的文件路径名
statbuf:指向的结构体用来保存获取到的信息

返回值
成功返回0
失败返回-1,同时errno被设置

stat这个函数获取属性只需要提供文件名,不需要打开文件
fstat这个函数获取文件的信息,需要的是文件的文件描述符,所以需要事先打开这个文件
lstat的功能与stat类似,只不过,当pathname是一个符号连接的时候,lstat获取的是符号连接本身的属性信息,而stat是获取符号链接指向的那个文件的属性信息

struct stat {
       dev_t     st_dev;         /* ID of device containing file */
            //容纳该文件的设备的设备号,文件存储在哪一个设备上面
       ino_t     st_ino;         /* Inode number */
            //该文件的inode编号
       mode_t    st_mode;        /* File type and mode */
            //该文件的类型和权限信息
            st_mode 包含了文件的类型和权限信息,使用位域实现,可以使用下面的宏取解析它:
                S_ISREG(st.st_mode)  is it a regular file?
                    为真则表示该文件为普通文件  -
                S_ISDIR(st.st_mode)  directory?
                    为真则表示该文件为目录文件  d
                S_ISCHR(st.st_mode)  character device?
                    为真则表示该文件为字符设备文件  c
                S_ISBLK(st.st_mode)  block device?
                    为真则表示该文件为块设备文件    b
                S_ISFIFO(st.st_mode) FIFO (named pipe)?
                    为真则表示该文件为管道文件        p
                S_ISLNK(st.st_mode)  symbolic link?  (Not in POSIX.1-1996.)
                    为真则表示该文件为符号链接文件    l
                S_ISSOCK(st.st_mode) socket?  (Not in POSIX.1-1996.)
                    为真则表示该文件为socket文件  s
             
                可以使用下面的实例代码去解析权限信息:
                if(st.st_mode & S_IRUSR)
                {
                    //user 有read的权限
                }else
                {
                    //user 没有有read的权限
                }
                S_ISUID     04000   set-user-ID bit
                S_ISGID     02000   set-group-ID bit (see below)
                S_ISVTX     01000   sticky bit (see below)
                
                S_IRWXU     00700   owner has read, write, and execute permission
                S_IRUSR     00400   owner has read permission
                S_IWUSR     00200   owner has write permission
                S_IXUSR     00100   owner has execute permission

                S_IRWXG     00070   group has read, write, and execute permission
                S_IRGRP     00040   group has read permission
                S_IWGRP     00020   group has write permission
                S_IXGRP     00010   group has execute permission

                S_IRWXO     00007   others (not in group) have read,  write,  and
                               execute permission
                S_IROTH     00004   others have read permission
                S_IWOTH     00002   others have write permission
                S_IXOTH     00001   others have execute permission
       nlink_t   st_nlink;       /* Number of hard links */
            //该文件的硬链接数量
       uid_t     st_uid;         /* User ID of owner */
            //文件的所有者ID
       gid_t     st_gid;         /* Group ID of owner */
            //文件的组ID
       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;      /* Numbe    r of 512B blocks allocated */
            //该文件占用多少块(512字节为一块)
       /* Since Linux 2.6, the kernel supports nanosecond
          precision for the following timestamp fields.
          For the details before Linux 2.6, see NOTES. */        
        struct timespec st_atim;  /* Time of last access */
                最后访问时间
        struct timespec st_mtim;  /* Time of last modification */
                最后修改时间(文件内容)
        struct timespec st_ctim;  /* Time of last status change */
                最后修改时间(文件的属性--inode)
                
        #define st_atime st_atim.tv_sec      /* Backward compatibility */
        #define st_mtime st_mtim.tv_sec
        #define st_ctime st_ctim.tv_sec
   };

 

13、打开目录

 #include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *name);
name:你要打开的目录的路径名
DIR *fdopendir(int fd);    
fd:要打开的目录的文件描述符,在调用fopendir前,先使用open打开目录

返回值:
成功返回一个指向打开的目录的指针
失败返回NULL,同时errno被设置

 

14、读目录项

#include <dirent.h>
readdir是用来从dirp指向的目录中,返回一个“目录项(struct dirent)”的指针
有多少个子文件和子文件夹就有多少目录项,每一次调用readdir就会返回下一个目录项的指针,直到返回NULL就表示读完了

struct dirent *readdir(DIR *dirp);    
dirp:指针,指向你要读的目录的指针

返回值:
成功返回一个指向目录项的指针
如果读到了最后会返回NULL,errno不会被设置
失败失败返回NULL,errno被设置

 struct dirent {
           ino_t          d_ino;       /* 读取到的目录项的inode编号*/
           off_t          d_off;       /* 目录项的偏移,读到了哪一个目录项*/
           unsigned short d_reclen;    /* 目录项的长度 */
           unsigned char  d_type;      /* 读取到的目录项指向的文件的类型,不是所有文件系统都支持的*/
           char           d_name[256]; /* 该目录项指向的文件名 */
};        
该结构体的成员,只有d_ino和d_name是所有linux系统都支持的

 

15、关闭目录

#include <sys/types.h>
#include <dirent.h>
用来关闭一个已经打开的目录

int closedir(DIR *dirp);
dirp:指针,指向一个已经打开的目录,一般是opendir的返回值

返回值:
成功返回0
失败返回-1,errno被设置

 

Code:

(打印一个目录下所有文件的路径名)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<dirent.h>

typedef struct node{
	char FileName[256];
	struct node *next,*prev;
}Node;

typedef struct head{
	struct node *first,*last;
	int sum;
}Head;

int sum = 0;
Head *h = NULL;

void print(Head *h){
	Node *t = h->first;
	while(t){
		printf("%s\n",t->FileName);
		t = t->next;
	}
	return ;
}

void Insert(char *s,Head *h){
	Node *p = (Node *)malloc(sizeof(*p));
	strcpy(p->FileName,s);
	p->next = p->prev = NULL;
	if(!h->first){
		h->first = h->last = p;
	}
	else{
		h->last->next = p;
		p->prev = h->last;
		h->last = p;
	}
	h->sum++;
	return ;
}

void Visit_dir(DIR *dp,char *s){
	struct dirent *dirp = NULL;
	struct stat st;
	char f[512] = {0};
	while(dirp = readdir(dp)){
		sprintf(f,"%s/%s",s,dirp->d_name);
		printf("%s\n",f);
		if(lstat(f,&st) < 0){
			perror("lstat error:");
			continue;
		}
		if(S_ISREG(st.st_mode)){
			sum += st.st_size;
			int len = strlen(f);
			char t[10];
			strcpy(t,f+len-3);
			if(!strcmp(t,"jpg") || !strcmp(t,"bmp")){
				Insert(f,h);
			}
		}
		if(S_ISDIR(st.st_mode)){
			if(f[strlen(f)-1] != '.'){
				DIR *dp1 = opendir(f);
				if(!dp1){
					perror("open dir error:");
					return ;
				}
				Visit_dir(dp1,f);
				closedir(dp1);
			}
		}
	}
}

int main(int argc,char **argv){

	h = (Head *)malloc(sizeof(*h));
	h->first = h->last = NULL;
	h->sum = 0;
	DIR *dp = opendir(argv[1]);
	if(!dp){
		perror("open dir error:");
		return -1;
	}
	Visit_dir(dp,argv[1]);
	closedir(dp);
	printf("size of all the reg:%d\n",sum);
	print(h);
	return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值