IO进程线程3
目录
一、文件IO
1.1 文件IO的概念
1.2 什么是文件描述符
1.3 特殊的文件描述符
1.4 文件IO函数
1.4.1 open
open代码示例
1.4.2 umask
1.4.3 close
1.4.4 write
write代码示例
1.4.5 read
read代码示例
1.4.6 lseek
lseek的代码示例
二、获取文件信息
2.1 stat
2.2 获取文件所属用户 getpwuid
2.3 获取文件所属组名getgrgid
2.4 获取文件类型和权限
三、目录相关函数
3.1 opendir
3.2 closedir
3.3 readdir
opendir| closedir|readdir代码示例
四、练习
4.1 使用文件IO读取图片 文件大小、文件偏移量,宽度,高度
4.2 向一个程序中输入文件名,判断指定目录下是否有这个文件,如果有这个文件,将这个文件的属性信息输出。如果不存在输出不存在即可。
一、文件IO
1.1 文件IO的概念
文件IO:指程序和文件系统之间的数据交互
特点:
1.不存在缓冲区,访问速度慢
2.不可以移植,依赖于操作系统
3.可以访问不同的文件类型(软连接,块设备等)
4.文件IO属于系统调用
5.文件IO在操作文件时使用文件描述符
1.2 什么是文件描述符
当操作一个文件的时候,则需要创建并打开一个文件,系统就会给文件分配一个编号,这个编号就是文件描述符
文件描述符本质就是数组的下表,标准IO是对文件IO的二次封装,所以FILE结构体里面存在文件描述符int _fileno;
1.文件描述符:文件描述符的本质就是数组的下表,默认共有1024个文件描述符,范围[0-1023]
ulimit -a 查看文件描述符的总个数
修改文件描述符的个数(修改只对当前终端有效)
ulimit -n 个数 ---》ulimit -n 2048
2.文件描述符的申请规则:分配从小到大,未申请的文件描述符
举例:申请4个文件,则文件描述符 3 4 5 6,关闭4文件描述符,重新申请则文件描述符是最小的编号4
3.因为文件描述符的个数有限,所以在不适用的情况下,需要关闭
4.查看中的文件描述符的个数函数
功能:查看文件描述符的总个数
格式:
#include <unistd.h>
int getdtablesize(void);
返回值:
返回文件描述符的总个数
1.3 特殊的文件描述符
stdin--->0
stdout--->1
stderr--->2
1.4 文件IO函数
open close write read lseek
1.4.1 open
功能:打开文件
格式: #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);
函数格式:
int open(const char *pathname, int flags, ...);
参数:
pathname:指定打开文件的路径以及文件名
flags:
必须包含以下三个之一
O_RDONLY 只读
O_WRONLY, 只写
O_RDWR 读写
——————————————————————
此外,还可以添加以下选项,注意需要使用安位或链接
O_APPEND 追加
O_CREAT 创建
O_TRUNC 清空
————————————————————————————————
eg: 表示标准IO中的w权限
"w": ----> O_WRONLY | O_CREAT| O_TRUNC
#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000
_________________________________
00001101 ---->保留所有权限
mode:可有可无
mode是由 flags中的O_CREAT 决定的
如果flags指定O_CREAT,则mode不可以忽略,需要写创建文件权限 eg:0664 0777
如果flags没有指定O_CREAT,则mode可以忽略
如果flags指定O_CREAT,并且文件已经创建,则mode不起效果
mode指定权限,但是实际的权限是(mode & ~umask)
返回值:
成功返回新的文件描述符
失败返回-1,跟新errno
_______________________________
eg: 使用文件io函数以w的方式打开
open("./one.txt",O_WRONLY | O_CREAT| O_TRUNC,0777)
open("./one.txt",O_RDONLY )
open代码示例
1.4.2 umask
1.什么是umask
umask是文件权掩码
2.查看文件权限掩码umask
umask
3.修改文件权限掩码
1.shell指令(只对当前终端有效)
umask 修改的值 ---->umask 0
2.使用函数实现修改文件权限掩码(只对当前终端有效)
#include <sys/stat.h>
mode_t umask(mode_t cmask);
功能:修改文件权限掩码
参数:cmask 修改权限掩码的值
返回值:
返回上一个权限掩码值,如果是第一次修改则返回0
eg:
umask(0)
1.4.3 close
格式
#include <unistd.h>
int close(int fd);
功能:通过文件描述符关闭文件
参数:
int fd: open函数打开的文件描述符
返回值:
成功返回0,失败返回-1,跟新errno
1.4.4 write
功能:把数据转换为二进制文件,写入到文件中,在文件中以字符的形式展示
格式:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
int fd: 文件描述符
void *buf: 写入内容的首地址
count: 写入的字节大小
返回值:
成功返回写入的字节数,失败返回-1,跟新errno
write代码示例
1.4.5 read
功能:根据文件描述符实现文件读取
格式:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
fd: 文件描述符
buf:存储读取的内容
count: 读取的字节大小
返回值:
成功返回读取的字符
读取到文件结尾,则返回0
如果读取失败返回-1,跟新errno
read代码示例
1.4.6 lseek
功能:文件指针的偏移(修改光标所在位置)
格式:
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数:
fd: 文件描述符
offset: 指针的偏移量,
如果offset>0 ,指针向后偏移
如果offset<0 指针向前偏移
offset=0 指针不偏移
whence:
SEEK_SET 把光标设置在起始位置
SEEK_CUR 把光标设置在当前位置
SEEK_END 把光标设置在结尾位置
整个光标的位置 offset+whence
返回值:
成功返回起始到当前位置的偏移量
失败返回-1,跟新errno
——————————————————————————————————————————————————————
eg:把文件IO的光标偏移到文件的起始位置
lseek(fd,0,SEEK_SET) 返回值0
lseek(fd,10,SEEK_SET) 返回值10 起始位置到当前偏移后的指针的字节大小
eg:计算文件大小
lseek(fd,0,SEEK_END) 起始位置到结尾的字节大小(文件大小 )
lseek的代码示例
二、获取文件信息
2.1 stat
功能:获取文件信息(文件类型 文件权限 硬链接数, 用户名 文件所属组, 时间)
不可以获取软链接文件信息,可以使用lstat函数
格式:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
参数:
pathname:查看文件对应的路径以及文件名
struct stat statbuf: 文件的所有信息
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 */ 文件类型和权限
nlink_t st_nlink; /* Number of hard links */ 硬链接数
uid_t st_uid; /* User ID of owner */ uid用户id
gid_t st_gid; /* Group ID of owner */ gid组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; /* Number of 512B blocks allocated */
/* 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 */ 最后一次状态修改的之间
#define st_atime st_atim.tv_sec 最后一次访问的时间(秒)
#define st_mtime st_mtim.tv_sec 最后一次修改的时间(秒)
#define st_ctime st_ctim.tv_sec 最后一次状态修改的时间(秒)
};
返回值:
成功返回0,失败返回-1 跟新errno
2.2 获取文件所属用户 getpwuid
功能:根据用户id获取用户对应的信息
格式:
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
参数:
uid 用户id
返回值:
struct passwd {
char *pw_name; /* username */ 用户名
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
成功返回strutc passwd类型的指针,存储用户的相关信息
失败返回NULL 跟新errno
2.3 获取文件所属组名getgrgid
功能:根据组id,获取组对应的信息
格式:
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
参数:
gid: 组id
返回值
成功返回指向组对应信息的结构体指针
失败返回NULL,跟新errno
struct group {
char *gr_name; /* group name */ 组名
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
2.4 获取文件类型和权限
文件类型是由st_mode的高4位决定
权限是由st_mode的第9位决定的
man 7 inode
———————————————————————文件类型—————————————————————————
方式1:
switch(st.st_mode& S_IFMT)
{
case S_IFSOCK:printf("socket");break;
case S_IFLNK:printf("symbolic");break;
case S_IFREG:printf("regular");break;
case S_IFBLK:printf("block");break;
case S_IFDIR:printf("directory");break;
case S_IFCHR:printf("character");break;
case S_IFIFO:printf("FIFO");break;
}
方式2:
if( S_ISREG(st.st_mode))
printf("regular");
else if( S_ISDIR(st.st_mode))
printf("directory?");
else if( S_ISCHR(st.st_mode))
printf("character");
else if( S_ISBLK(st.st_mode))
printf("block");
else if( S_ISFIFO(st.st_mode))
printf("FIFO");
else if( S_ISLNK(st.st_mode))
printf("symbolic");
else if( S_ISSOCK(st.st_mode))
printf("socket");
————————————————————————文件权限—————————————————————————
/获取文件权限
printf("mode=%#o\n",st.st_mode&0777);
三、目录相关函数
3.1 opendir
功能:打开指定路径下目录
格式:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
参数:
name: 打开的目录以及路径
返回值:
成功返回目录的流指针,失败返回NULL,跟新errno
3.2 closedir
功能:关闭目录流指针
格式
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
参数:
dirp: 目录流指针 就只opendir返回的指针
返回值:
成功返回0 失败返回-1 跟新errno
3.3 readdir
功能:读取目录对应的信息
格式:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
参数:
dirp: 目录流指针 就只opendir返回的指针
返回值:
struct dirent {
ino_t d_ino; /* Inode number */ inode号
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */ 结构体的大小会睡着d_name的实际长度改变而改变
unsigned char d_type; /* Type of file; not supported 类型
by all filesystem types */
char d_name[256]; /* Null-terminated filename */ 名字
};
如果成功,则返回一个struct dirent类型的结构体,结构体中存储目录的相关信息
如果遇到文件结尾,返回NULL,不更新errno
如果读取失败,则返回NULL,跟新errno
opendir| closedir|readdir代码示例
四、练习
4.1 使用文件IO读取图片 文件大小、文件偏移量,宽度,高度
1.bmp文件头(bmp file header):提供文件的格式、大小等信息 (14字节)
2 位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息(40字节)
3.位图数据(bitmap data):就是图像数据啦
#include "head.h"
int main(int argc, const char *argv[])
{
int fd=open("./xiaoxin.bmp",O_RDONLY);
lseek(fd,2,SEEK_SET);
int size;
read(fd,&size,4);
printf("大小:%dB\n",size);
lseek(fd,10,SEEK_SET);
int offset;
read(fd,&offset,4);
printf("偏移量:%d\n",offset);
lseek(fd,18,SEEK_SET);
int width;
read(fd,&width,4);
printf("宽度:%d\n",width);
lseek(fd,22,SEEK_SET);
int high;
read(fd,&high,4);
printf("高度:%d\n",high);
close(fd);
return 0;
}
4.2 向一个程序中输入文件名,判断指定目录下是否有这个文件,如果有这个文件,将这个文件的属性信息输出。如果不存在输出不存在即可。
./a.out 目录名 查询的文件名
argv[1] argv[2]
#include "head.h"
int main(int argc, const char *argv[])
{
// 检查文件是否存在
DIR *dp=opendir(argv[1]);
if(dp==NULL)
{
printf("目录不存在\n");
return 0;
}
struct dirent *f=NULL;
while( f=readdir(dp) )
{
if(strcmp(f->d_name,argv[2])==0)
break;
}
if(f==NULL)
{
printf("文件不存在");
return 0;
}
closedir(dp);
// 打印文件相关信息
// 获取文件相对路径
char file[128];
sprintf(file,"%s/%s",argv[1],argv[2]);
struct stat st;
if(stat(file,&st)==-1)
PRINTF_ERROR("stat error");
// 获取文件权限
// 获取文件类型
mode_t mode=st.st_mode;
switch(mode&0170000)
{
case 0010000:
printf("p");
break;
case 002000:
printf("c");
break;
case 0040000:
printf("d");
break;
case 0060000:
printf("b");
break;
case 0100000:
printf("-");
break;
case 0120000:
printf("l");
break;
case 0140000:
printf("s");
break;
default:
printf("error\n");
break;
}
int chown=mode&0777;
printf("%#o ",chown);
// 获取硬链接数
int num=st.st_nlink;
printf("%d ",num);
// 获取用户id
int id=st.st_uid;
// 获取用户名
struct passwd *p=getpwuid(id);
printf("%s ",p->pw_name);
// 获取组id
gid_t gid=st.st_gid;
// 获取组名
struct group *gr=getgrgid(gid);
printf("%s ",gr->gr_name);
// 获取文件大小
off_t size=st.st_size;
printf("%ld ",size);
// 获取文件id
ino_t fid=st.st_ino;
// 获取最后一次访问的时间转换为年月日时分秒
struct tm *t=localtime(&st.st_atim.tv_sec);
printf("%d-%d-%d %02d:%02d:%02d ",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
// 输出文件名
printf("%s\n",argv[2]);
return 0;
}