一、文件IO
1.1 close函数(关闭文件)
#include <unistd.h>---所需头文件
int close(int fd);
功能:关闭文件
参数:
fd:文件描述符
返回值:成功返回0,失败返回-1,置位错误码
close使用示例:
#include <my_head.h>
int main(int argc,const char *argv[]){
int fd1,fd2,fd3;
fd1 = open("./a.txt",O_RDONLY);//成功返回文件描述符
fd2 = open("./b.txt",O_RDONLY);//遵循最小分配原则
printf("fd1 = %d fd2 = %d\n",fd1,fd2);//输出3,4
//关闭fd1再打开一个新的文件
close(fd1);
fd3 = open("./c.txt",O_RDONLY);
printf("fd3 = %d\n",fd3);
//文件描述符会重新分配,遵循最小分配原则,
//上面关闭了fd1,原fd1文件描述符位3,fd3文件描述符变为3
int a = 0;
scanf("%d",&a);//正常输入
printf("a = %d\n",a);
//关闭标准输入
close(0);
scanf("%d",&a);//标准输入已经关闭,无法再次输入
printf("a = %d\n",a);
//close(1);
close(stdout->_fileno);//等价于close(1);关闭标准输出
printf("1111111\n");
return 0;
}
运行结果:
1.2 read/write 函数的使用
#include <unistd.h>
ssize_t read(int fd,void *buf,size_t count);
功能:从fd代表的文件中读取count个字节的数据到buf中
参数:
fd:文件描述符
buf:保存读取到的数据的首地址
count:要读取的字节数
返回值:成功返回读取到的字节数,读取到文件结尾返沪0,失败返回1,置位错误码
#include <unistd.h>
ssize_t write(int fd,const void *buf,size_t count);
功能:将buf中的数据写count个字节到1fd代表的文件中
参数:
fd:文件描述符
buf:要写入的数据的首地址
count:要读取的字节数
返回值:成功返回写入的字节数,失败返回-1,置位错误码
read使用示例
#include <my_head.h>
int main(int argc,const char *argv[]){
int fd = open("./a.txt",O_RDONLY);
if(-1 == fd){
PRINT_ERR("open a.txt error");
}
//从文件中读取内容
char read_buf[32] = {0};
int ret = 0;
//期望读取32个字节
ret = read(fd,read_buf,sizeof(read_buf));
printf("1:ret = %d\n",ret);
//实际读取的是7个字节,因为a.txt内容大小只有a字节
//再次读取
ret = read(fd,read_buf,sizeof(read_buf));
printf("2:ret = %d\n",ret);//返回0,到了文件结尾
close(fd);//关闭文件
return 0;
}
运行结果:
wirte函数的使用
#include <my_head.h>
int main(int argc,const char *argv[]){
int fd = open("./b.txt",O_RDWR);//以读写的方式打开文件
if(-1 == fd)
PRINT_ERR("open b.txt error");
//向文件中写入内容,写整数
int var1 = 0x12345678;
int ret = 0;
ret = write(fd,&var1,sizeof(var1));
printf("ret = %d\n",ret);//写入成功返回写入的字节数,失败返回-1
//从文件中读取刚才写入的数据
lseek(fd,0,SEEK_SET);//将光标移动到文件开头
var1 = 0;
read(fd,&var1,sizeof(int));
printf("var1 = %#x\n",var1);
return 0;
}
运行结果:
练习:read/write拷贝一个文件
#include <my_head.h>
int main(int argc,const char *argv[]){
if(3 != argc){
printf("入参错误\n");
printf("使用方式:./a.out srcfile dstfile\n");
return 0;
}
//打开源文件和目标文件
int srcfd,dstfd;
srcfd = open(argv[1],O_RDONLY);
dstfd = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666);
if(-1 == srcfd || -1 == dstfd)
PRINT_ERR("open error");
//循环拷贝
char cp_buf[128] ={0};
int ret = 0;
while((ret = read(srcfd,cp_buf,sizeof(cp_buf)))>0){
write(dstfd,cp_buf,ret);
memset(cp_buf,0,sizeof(cp_buf));
}
close(srcfd);
close(dstfd);
return 0;
}
运行结果:
1.3 lseek函数的使用
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd,off_t offset,int whence);
功能:偏移文件光标
参数:
fd:文件描述符
offset:偏移量
<0:向前偏移
=0:不偏移
>0:向后偏移
whence:偏移的基地址
SEEK_SET:从文件开头开始偏移
SEEK_CUR:从当前位置开始偏移
SEEK_END:从文件结尾开始偏移
返回值:成功返回光标位置,失败返回-1,置位错误码
lseek使用示例
#include <my_head.h>
typedef struct RGB
{
unsigned char b;
unsigned char g;
unsigned char r;
} rgb_t;
int main(int argc, const char *argv[])
{
rgb_t color = {
.b = 0,
.g = 0,
.r = 255,
};
// 1.打开图片文件
int fd = open("./ddm.bmp",O_RDWR);
// 2.首先要将光标偏移到像素数据前,54个字节
int pos = 0;
pos = lseek(fd, 54, SEEK_SET);//返回的就是当前光标的位置
printf("当前光标的位置是%d\n",pos);
// 3.偏移光标到要操作的像素数据前
lseek(fd, ((631 * 1920) + 712) * 3, SEEK_CUR);
// 开始循环写入像素数据,覆盖鼻子
for (int j=0;j<745-631; j++)
{
for (int i = 0; i < (835 - 712); i++)
{
write(fd,&color,sizeof(color));
}//循环结束操作了鼻子所在方框的一行
//每次内循环结束之后,都将光标偏移到鼻子所在方框的第二行
lseek(fd,(1920-(835 - 712))*3,SEEK_CUR);
}
return 0;
}
1.4 stat(获取文件属性)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname,struct stat *statbuf);
功能:获取pathname对应文件的属性信息到statbuf中
参数:
pathname:文件的路径和文件名
statbuf:保存文件属性信息的结构体的首地址
返回值:成功返回0,失败返回-1,置位错误码
struct stat *statbuf结构解析:
struct stat {
dev_t st_dev; /* 文件所在磁盘的设备号 */
ino_t st_ino; /* 文件的inode号 */
mode_t st_mode; /* 文件的类型和权限 */
nlink_t st_nlink; /*文件的硬链接数,对于目录文件,是子目录的个数 */
uid_t st_uid; /* 文件所属用户的uid */
gid_t st_gid; /* 文件所属用户的组id */
dev_t st_rdev; /* 如果是设备文件,设备ID */
off_t st_size; /* 文件的大小 */
blksize_t st_blksize; /* 块儿大小 */
blkcnt_t st_blocks; /* 块的数量*/
struct timespec st_atim; /* 上一次访问文件的时间 */
struct timespec st_mtim; /* 上次修改文件的时间 */
struct timespec st_ctim; /* 上次文件状态改变的时间 */
};
mode_t st_mode;解析:
012xxxx
(文件类型的位掩码)S_IFMT 0170000
st_mode & S_IFMT ------->文件的权限信息
stat(pathname,&sb);
if((sb.st_mode & S_IFMT) == S_IFREG){
}
S_IFSOCK 0140000 套接字文件
S_IFLNK 0120000 链接文件
S_IFREG 0100000 普通文件
S_IFBLK 0040000 目录文件
S_IFCHR 0020000 字符设备文件
S_IFIFO 0010000 管道文件
通过宏定义的方式去判断
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
使用方式
stat(pathname, &sb);
if (S_ISREG(sb.st_mode)) {
/* Handle regular file */
}
0777 & st_mode 获取到的文件的权限
0666 & 0777 == 0666
stat 函数使用示例
#include <my_head.h>
int main(int argc, const char *argv[])
{
if (2 != argc)
{
printf("入参错误\n");
printf("使用方式 ./a/out filename\n");
return -1;
}
// 1.获取文件属性信息
struct stat st;
stat(argv[1], &st);
// 2.打印文件信息
printf("inode号: %ld\n", st.st_ino);
printf("uid: %d\n", st.st_uid);
printf("硬链接个数: %ld\n", st.st_nlink);
printf("上次修改的时间: %ld\n", st.st_mtime);
printf("上次访问的时间: %ld\n", st.st_atime);
printf("上次改变文件状态的时间: %ld\n", st.st_ctime);
switch (st.st_mode & __S_IFMT)
{ //__S_IFMT是文件类型的掩码
case __S_IFSOCK:
printf("%s是套接字文件\n", argv[1]);
break;
case __S_IFLNK:
printf("%s是链接文件\n", argv[1]);
break;
case __S_IFREG:
printf("%s是普通文件\n", argv[1]);
break;
case __S_IFBLK:
printf("%s是块设备文件\n", argv[1]);
break;
case __S_IFDIR:
printf("%s是目录文件\n", argv[1]);
break;
case __S_IFCHR:
printf("%s是字符设备文件\n", argv[1]);
break;
case __S_IFIFO:
printf("%s是管道文件文件\n", argv[1]);
break;
default:
printf("未知的文件类型\n");
break;
}
printf("文件的权限是%#o\n",st.st_mode & 0777);
return 0;
}
运行结果:
1.5 getpwuid 和 getgrgid 函数的使用
1.5.1 函数说明
#include <sys/types.h> --- 所需头文件
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
功能:根据uid获取用户的相关信息
参数:
uid:用户的uid
返回值:指向用户信息结构体的指针
struct passwd{
char *pw_name; ---- 用户名
char *pw_passwd; ---- 用户密码
uid_t pw_uid; ---- 用户id
gid_t pw_gid; ---- 用户的组id
char *pw_gecos; ---- 用户的描述信息
char *pw_dir; ---- 用户的家目录
char *pw_shell; ---- 默认的命令解析器
};
这个结构体中的信息的源头是/etc/passwd文件中的信息
#include <sys/types.h>
#include <grp.h>
struct group *getrgid(gid_t gid);
功能:根据gid获取用户所属组的相关信息
参数:gid
返回值:成功返回指针白村组信息的结构体指针,失败返回NULL,置位错误码
The group structure is defined in <grp.h> as follows:
struct group{
char *gr_name; --- 组名
char *gr_passwd; --- 组密码
gid_t gr_gid; --- 组id
char **gr_mem; --- 组成员
};
获取的是/etc/group中的组信息
getpwuid的使用
#include <my_head.h>
int main(int argc,const char *argv[]){
struct passwd *pw_info;
/*getuid() 函数会返回用户的uid,这个函数总是成功*/
uid_t uid = getuid();
printf("当前用户的uid是%d\n",uid);
pw_info = getpwuid(uid);//根据uid获取用户的信息
if(NULL == pw_info){
PRINT_ERR("getpwuid error");
}
printf("用户名:%s\n",pw_info->pw_name);
printf("家目录:%s\n",pw_info->pw_dir);
printf("用户描述信息:%s\n",pw_info->pw_gecos);
printf("用户组id:%d\n",pw_info->pw_gid);
printf("用户密码:%s\n",pw_info->pw_passwd);
printf("用户的命令解析器:%s\n",pw_info->pw_shell);
printf("用户id:%d\n",pw_info->pw_uid);
return 0;
}
运行结果:
getgrgid的使用
#include <my_head.h>
int main(int argc,const char *argv[]){
//获取当前用户的组id
gid_t gid = getgid();
printf("gid = %d\n",gid);
struct group *gp;
gp = getgrgid(gid);
if(NULL == gp){
PRINT_ERR("getgrgid error");
}
printf("组名是%s\n",gp->gr_name);
printf("组id %d\n",gp->gr_gid);
return 0;
}
运行结果:
二、目录操作
2.1 opendir() 打开目录
#include <sys/type.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开name对应的目录
参数:
name:目录的名字
返回值:成功返回指向的目录的指针,失败返回NULL置位错误码
2.2 closedir() 关闭目录
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭目录
参数:
dirp:使用opendir获取的目录指针
返回值:成功返回0,失败返回-1,置位错误码
2.3 readdir() 读取目录信息
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取目录中的内容
参数:
dirp:使用opendir获取的目录指针
返回值:成功返回一个指针,指针指向的结构体中包含了第一个文件相关的信息,如果想要获取其他文件的信息,需要反复读取
失败或者读到文件结尾,返回NULL
如果由于失败导致返回NULL,错误码会被置位
struct dirent{
ino_t d_ino; -- 文件的inode号
off_t d_off; -- 不太用关注
unsigned short d_reclen; -- 这条记录的长度
unsigned char d_type; -- 文件的类型
DT_BLK 块设备文件
DT_CHR 字符设备文件
DT_DIR 目录文件
DT_FIFO 管道文件
DT_LNK 链接文件
DT_REG 普通文件
DT_SOCK 套接字文件
DT_UNKNOWN 未知的文件类型
char d_name[256]; -- 文件的名字
}
2.4 目录操作的使用用例
#include <my_head.h>
int main(int argc, const char *argv[])
{
if (argc != 2)
{
printf("入参错误\n");
printf("使用方式:./a.out dirname\n");
return -1;
}
// 打开目录
DIR *dir;
struct dirent *FileInDir;
dir = opendir(argv[1]);
if (NULL == dir)
PRINT_ERR("opendir error");
// 读取目录的内容
while ((FileInDir = readdir(dir)) != NULL)
{
printf("读取到的文件名是%s\n", FileInDir->d_name);
printf("文件的inode号 %ld\n", FileInDir->d_ino);
printf("这条记录的长度 %d\n", FileInDir->d_reclen);
switch (FileInDir->d_type)
{
case DT_DIR:
printf("这是目录文件\n");
break;
case DT_BLK:
printf("这是块设备文件\n");
break;
case DT_REG:
printf("是普通文件\n");
break;
default:
printf("位置文件类型\n");
break;
}
printf("---------------------------------------\n");
}
closedir(dir);
return 0;
}
运行结果: