系统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;
}