==============================================================
open的文章摘自https://www.cnblogs.com/fnlingnzb-learner/p/7040726.html
下面就对上面的文章进行简化修改
open和fopen的区别
1,fread是带缓冲的,read不带缓冲.
2,fopen是标准c里定义的,open是POSIX中定义的.
3,fread可以读一个结构.read在linux/unix中读二进制与普通文件没有区别.
4,fopen不能指定要创建文件的权限.open可以指定权限.
5,fopen返回文件指针,open返回文件描述符(整数).
open系统调用(linux)
需要包含头文件:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
函数原型:
int open( const char * pathname, int oflags);
int open( const char * pathname,int oflags, mode_t mode);
mode仅当创建新文件时才使用,用于指定文件的访问权限
pathname 是待打开/创建文件的路径名;
oflags用于指定文件的打开/创建模式
O_RDONLY 只读模式
O_WRONLY 只写模式
O_RDWR 读写模式
以上三者是互斥的,即不可以同时使用。
打开/创建文件时,至少得使用上述三个常量中的一个。以下常量选用,选用方式O_RDONLY|O_APPEND
O_APPEND 每次写操作都写入文件的末尾
O_CREAT 如果指定文件不存在,则创建这个文件
O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改 errno 的值,所以要判断文件是否存在,要O_CREAT和O_EXCL一起用
O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode)。
//以下用于同步输入输出
O_DSYNC 等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下,不等待文件属性更新。
O_RSYNC read 等待所有写入同一区域的写操作完成后再进行
O_SYNC 等待物理 I/O 结束后再 write,包括更新文件属性的 I/O
第三个参数mode
这些标志在头文件sys/stat.h中定义,和文件的权限是一样的,可以用数字来代替,比如0777,0是代表8进制
但是填写了第3个参数后,得出来的文件的权限依然不是我们指定的,因为会有一个掩码,这个0777会和掩码取反后进行与的计算
得到实际权限,umask可以显示掩码,umask 数字 可以修改掩码,以下完全可以用数字代替
S_IRUSR: 读权限,文件属主
S_IWUSR: 写权限,文件属主
S_IXUSR: 执行权限,文件属主
S_IRGRP: 读权限,文件所属组
S_IWGRP: 写权限,文件所属组
S_IXGRP: 执行权限,文件所属组
S_IROTH: 读权限,其它用户
S_IWOTH: 写权限,其它用户
S_IXOTH: 执行权限,其它用户
返回值:成功则返回文件描述符,否则返回 -1。 返回文件描述符(整型变量0~255)
错误代码:
EEXIST 参数pathname 所指的文件已存在,却使用了O_CREAT和O_EXCL旗标。
EACCESS 参数pathname所指的文件不符合所要求测试的权限。
EROFS 欲测试写入权限的文件存在于只读文件系统内。
EFAULT 参数pathname指针超出可存取内存空间。
EINVAL 参数mode 不正确。
ENAMETOOLONG 参数pathname太长。
ENOTDIR 参数pathname不是目录。
ENOMEM 核心内存不足。
ELOOP 参数pathname有过多符号连接问题。
EIO I/O 存取错误
write函数
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数:
fd:要进行写操作的文件描述词。
buf:需要输出的缓冲区
count:最大输出字节计数
返回值:成功返回写入的字节数,出错返回-1并设置errno
read函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:
buf:需要读取的缓冲区
count:最大读取字节计数
返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0 。
以下摘自:https://blog.csdn.net/songyang516/article/details/6779950
lseek函数
#include <sys/types.h>
off_t lseek(int filedes, off_t offset, int whence);
返回值:新的偏移量(成功),-1(失败)
所有打开的文件都有一个当前文件偏移量(current file offset),以下简称为 cfo。cfo 通常是一个非负整数
参数 offset 的含义取决于参数 whence:
1. 如果 whence 是 SEEK_SET,文件偏移量将被设置为 offset。
2. 如果 whence 是 SEEK_CUR,文件偏移量将被设置为 cfo 加上 offset,
offset 可以为正也可以为负。
3. 如果 whence 是 SEEK_END,文件偏移量将被设置为文件长度加上 offset,
offset 可以为正也可以为负。
SEEK_SET、SEEK_CUR 和 SEEK_END 使用之前是 0、1 和 2。
lseek 的以下用法返回当前的偏移量:
off_t currpos;
currpos = lseek(fd, 0, SEEK_CUR);
lseek还有一个作用,就是文件的扩展,但是文件扩展需要对文件最后进行一次写的操作
lseek(fd, 2000, SEEK_END);
write(fd,"a",1);
以下摘自:https://www.cnblogs.com/sylar5/p/6491033.html
stat函数
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *file_name, struct stat *buf);
函数说明: 通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值: 执行成功则返回0,失败返回-1,错误代码存于errno
错误代码
ENOENT 参数file_name指定的文件不存在
ENOTDIR 路径中的目录存在但却非真正的目录
ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接
EFAULT 参数buf为无效指针,指向无法存在的内存空间
EACCESS 存取文件时被拒绝
ENOMEM 核心内存不足
ENAMETOOLONG 参数file_name的路径名称太长
stat的使用
1 #include <sys/stat.h> 2 #include <unistd.h> 3 #include <stdio.h> 4 5 int main() { 6 struct stat buf; 7 stat("/etc/hosts", &buf); 8 printf("/etc/hosts file size = %d\n", buf.st_size); 9 } 10 11 /*************************************************************************/ 12 struct stat { 13 dev_t st_dev; //文件的设备编号 14 ino_t st_ino; //节点 15 mode_t st_mode; //文件的类型和存取的权限 16 nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1 17 uid_t st_uid; //用户ID 18 gid_t st_gid; //组ID 19 dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号 20 off_t st_size; //文件字节数(文件大小) 21 unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小) 22 unsigned long st_blocks; //块数 23 time_t st_atime; //最后一次访问时间 24 time_t st_mtime; //最后一次修改时间 25 time_t st_ctime; //最后一次改变时间(指属性) 26 };
lstat函数类似于stat,但是当命名的文件是一个符号连接时,lstat返回该符号连接的有关信息,而不是由该符号连接引用的文件的信息
摘自:https://blog.csdn.net/tigerjibo/article/details/11712039
access函数
#include <stdio.h>
#include <unistd.h>
int access(const char * pathname, int mode);
pathname:需要检测的文件路劲名
mode:需要测试的操作模式
成功执行时,返回0。失败返回-1,errno被设为以下的某个值
EINVAL: 模式值无效
EACCES: 文件或路径名中包含的目录不可访问
ELOOP : 解释路径名过程中存在太多的符号连接
ENAMETOOLONG:路径名太长
ENOENT:路径名中的目录不存在或是无效的符号连接
ENOTDIR: 路径名中当作目录的组件并非目录
EROFS: 文件系统只读
EFAULT: 路径名指向可访问的空间外
EIO:输入输出错误
ENOMEM: 不能获取足够的内核内存
ETXTBSY:对程序写入出错
mode说明
R_OK 测试读许可权
W_OK 测试写许可权
X_OK 测试执行许可权
F_OK 测试文件是否存在
摘自:https://blog.csdn.net/cy_cai/article/details/21599147
truncate函数
#include <unistd.h>
int truncate(const char *path, off_t length);
truncate("/aaa",500);
函数说明:truncate()会将指定的文件大小改为参数length指定的大小.如果原来的文件大小比参数length大,则超过的部分会被删除
unlink函数
#include <unistd.h>
int unlink(const char *oldpath)
oldpath:源文件路径名
返回值:
成功返回0;失败返回-1,其错误存在全局变量errno中,可用perror查看
函数说明:
如果文件是一个符号链接,那么删除符号链接,如果是硬链接,硬链接数-1,当减为0的时候,直接删除文件(当然必须有写的权限)
如果硬链接数为0,且已经打开这个文件,那么只有当这个文件关闭了,且没有其他用户操作这个文件的时候才会去删除
所以可以利用这个特性去创建一个临时文件
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<sys/types.h> 4 #include<unistd.h> 5 #include<fcntl.h> 6 7 int main() 8 { 9 int fd=open("tempfile",O_CREAT | O_RDWR,0644);//打开并创建一个文件(文件不存在的情况下) 10 if(fd==-1) 11 { 12 perror("open"); //perror会打印出错误的信息 13 exit(1); 14 } 15 16 int ret=unlink("tempfile"); //删除临时文件,等文件操作完才会删除 17 18 write(fd,"hello\n",6); 19 20 lseek(fd,0,SEEK_SET); 21 22 char buf[24]={0}; 23 24 int len=read(fd,buf,sizeof(buf)); 25 26 write(1,buf,len);//将内容写到屏幕上,1是out,也就是屏幕 27 close(fd); 28 }
目录操作函数
#include <unistd.h>
int chdir(const char*path);
说明:chdir函数用于改变当前工作目录。调用参数是指向目录的指针,调用进程需要有搜索整个目录的权限
改变的是程序中改变的那个路径,而不是我们终端界面的
char *getcwd(char *buf, size size)
说明:获取当前程序所在进程的目标,buf是存放的目标的字符数组,size就是要存放多少长度
int mkdir(const char *pathname, mode_t mode)
说明:创建一个目录,mode是模式,可以用数字代替,比如0777
include< dirent.h>
DIR *opendir(const char *dirpath);
说明:打开一个目标,返回DIR结构指针,这个结构保存所打开的目录信息
struct dirent* readdir(DIR* dir_handle);
说明: 参数传入opendir的返回值,返回一个结构,可以用closedir关闭
struct dirent { long d_ino; /* inode number 索引节点号 */ off_t d_off; /* offset to this dirent 在目录文件中的偏移 */ unsigned short d_reclen;/* length of this d_name 文件名长 */ unsigned char d_type; /* the type of d_name 文件类型 */ char d_name [NAME_MAX+1];/* file name (null-terminated) 文件名,最长255字符 */ }
d_type的类型,可以通过这个判断文件的类型
=
递归的例子
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <dirent.h> 5 #include <string.h> 6 7 int getFilename(char *root) 8 { 9 //打开目录 10 DIR *dir = NULL; 11 int total = 0; 12 if (dir == NULL) 13 { 14 perror("opendir"); 15 exit(1); 16 } 17 18 char mypath[1024] = { 0 }; 19 dir = opendir(root); 20 struct dirent* ptr = NULL; 21 while ((ptr = readdir(dir)) != NULL) //判断是否目录为空 22 { 23 //过滤.和.. 24 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..")==0) 25 { 26 continue; 27 } 28 29 //如果是目录 30 if (ptr->d_type==DT_DIR) 31 { 32 //递归读取目录 33 sprintf(mypath, "%s/%s", root, ptr->d_name); 34 //计算读取了多少个目录 35 total = total+getFilename(mypath); 36 } 37 //如果是普通文件,计算 38 if (ptr->d_type == DT_REG) 39 { 40 total++; 41 } 42 } 43 44 closedir(dir); 45 return total; 46 } 47 48 int main(int argc,char*argv[]) 49 { 50 if (argc < 2) 51 { 52 printf("a.out. dir\n"); 53 exit(1); 54 } 55 int total = getFilename(argv[1]); 56 printf("%d\n", total); 57 return 0; 58 }
摘自:https://www.cnblogs.com/sherlockhomles/archive/2013/05/20/3089212.html
dup&dup2函数
dup函数的作用:复制一个现有的句柄,产生一个与“源句柄特性”完全一样的新句柄(也即生成一个新的句柄号,并关联到同一个设备)
dup2函数的作用:复制一个现有的句柄到另一个句柄上,目标句柄的特性与“源句柄特性”完全一样
(也即首先关闭目标句柄,与设备断连,接着从源句柄完全拷贝复制到目标句柄)
fcntl函数
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
函数说明: 现阶段只使用第二种和第一种,
cmd先阶段只需要了解2个状态
F_GETFL 取得fd的文件状态标志,如同下面的描述一样(arg被忽略) 这是第一种,只获取
F_SETFL 设置给arg描述符状态标志,可以更改的几个标志是:O_APPEND, O_NONBLOCK,O_SYNC和O_ASYNC。
这是第二种,改变文件的状态,状态填写在第三个参数