7底层文件读写

2018/06/22 23:35
阅读数 8

低级文件库

  低级文件读写与标准文件读写类似。如fgetc,fputs都是调用read,write。

 

文件打开/创建
#include <fcntl.h> //file control
int open(const char *filename, int flag, [mode_t mode])
flag 打开文件的模式
创建文件时,决定新文件的属性 rwx
int close(int fd)
关闭文件

第二参数:
打开文件的模式(flag 参数的值)
读写方式
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
创建方式
O_APPEND 追加方式打开
O_CREAT 文件不存在则创建
O_EXCL 文件存在则打开失败 (创建新文件时,和 O_CREAT 一起用)
O_NDELAY 不阻塞返回, 返回0
O_NONBLOCK 不阻塞返回,读取不到数据返回 -1
O_NOCTTY 程序不作为控制终端
O_TRUNC 文件存在则清空文件

第三参数:
创建文件的模式
S_IRUSR + S_IWUSR + S_IXUSR = S_IRWXU = 0700 (八进制)
S_IRGRP + S_IWGRP + S_IXGRP = S_IRWXG = 0070 (八进制)
S_IROTH + S_IWOTH + S_IXOTH = S_IRWXO = 0007 (八进制)


文件处理
#include<unistd.h>
unlink(char *filename)
删除文件,只是使用临时文件时候,可以先删除再使用
size_t read(int fd, void *buf, size_t size)
读文件
size_t write(int fd, void *buf, size_t size)
写文件
off_t lseek(int fd, off_t offset, int mode)
使用方法同 fseek()
int fsync(int fd)
刷新缓冲区,类似 fflush()
int dup(int fd)
重定向文件描述符 int newFd = dup(STDOUT_FILENO)
newFd 指向 stdout
int dup2(int fd1, int fd2)
重定向文件描述符 dup2(newFd, STDOUT_FILENO)
stdout 指向 newFd

例子:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

void test_open()
{
int fd;
fd=open("1.txt",O_RDONLY,0700);
if(fd<0)
{
perror("fail to open");
return ;
}
char buf[1024];
read(fd,buf,sizeof(buf)); //读取1.txt文件内容
close(fd);
printf("buf:%s",buf); //输出文件内容

read(STDIN_FILENO,buf,strlen(buf)); //读取stdin,等同于scanf()
printf("input:%s\n",buf);

write(STDOUT_FILENO,buf,strlen(buf));//写入stdout,等同于printf()
printf("input:%s\n",buf);
}

void test_dup()
{
int fd;
char buf[1024]="hello world\n";

//此处STDOUT_FILENO与//STDIN_FILENO功能一样
fd=dup(STDOUT_FILENO);
write(fd,buf,strlen(buf)); //等同于printf()

char temp[1024];
read(fd,temp,sizeof(temp)); //等同于scanf()
printf("temp:%s",temp);
}

void main()
{
//test_open();
test_dup();
}

区别;
这是 fopen版本 的标准输出,错误输出和标准输入, 变量类型是 FILE*
stdout
stderr
stdin


这是 open 版本的 标准输出,错误输出,和标准输入,变量类型是 int
STDOUT_FILENO == 1
STDERR_FILENO == 2
STDIN_FILENO == 0

 

文件控制
#include<fcntl.h>
int fcntl(int fd, int cmd)
int fcntl(int fd, int cmd, int arg);
int fcntl(int fd, int cmd, struct flock* lock)

控制命令 cmd
F_DUPFD
fcntl(fd, F_DUPFD, 0) 等价于 dup(fd)
返回大于等于0的最小可用文件描述符
fcntl(fd1, F_DUPFD, fd2)
等价于 dup2(fd1, fd2) close(fd2);
F_GETFD, F_SETFD
获取设置 FD_CLOEXEC 标志 (执行外部程序 fd 是否关闭, 默认为0,不关闭)
flag = fcntl(fd, F_GETFD); fcntl(fd , F_SETFD, ~FD_CLOEXEC)
F_GETFL, F_SETFL
获取设置文件打开方式:支持设置的有 O_APPEND, O_NONBLOCK,
F_GETDOWN, F_SETDOWN 获取设置 接受SIGIO,SIGURG 事件信号
F_GETLK, F_SETLK, F_SETLKW 获取、设置、测试锁

文件锁
读锁(共享锁) 写锁 (互斥锁)
文件可以设置多个读锁,但只能设置一个写锁,读写锁不能同时存在
stcuct flock
{
short l_type //F_RDLCK, F_WRLCK, F_UNLCK (读,写,释放锁)
short l_whence //锁开始位置 SEEK_SET, SEEK_CUR, SEEK_END
long l_start //锁偏移量
long l_len //锁区域大小
short l_pid //拥有锁的pid
}
whence=SEEK_SET, start = len = 0 锁整个文件


struct flock lock={0, SEEK_SEET, 0,0,0};
fcntl(fd, F_GETLK, &lock)
返回值-1表示获取失败
lock.l_type = F_WRLCK或者F_RDLCK或者F_UNLCK 分别表示锁类型
fcntl(fd, F_SETLK, &lock)
lock.l_type = F_WRLCK 或者 F_RDLCK申请锁,失败返回 -1
fcntl(fd, F_SETLKW, &lock)
lock.l_type = F_UNLCK 失败返回 -1。

解析:
多个进程一起操作某个文件 (需要互斥)
每个进程,打开文件前,需要检查文件是否被锁定

进程 A 需要操作文件 某个部分
--先使用GETLK 查看这个部分是否被锁定了 fcntl(fd, F_GETLK, &lock)
1:如果被 写锁锁定了 lock.l_type = F_WRLCK
那么进程 A 不能操作这个文件
2:如果被 读锁锁定了 lock.l_type = F_RDLCK
如果进程 A 需要读这个文件,则再次给文件 加上 读锁, 然后开始读取文件
如果进程 A 需要写这个文件,则等待 (不能写)
3:如果没有被锁定 lock.l_type = F_UNLCK
则 A 给文件加上 锁 (读文件就加读锁,写文件就加写锁) fcntl(fd, F_SETLK, &lock)
--A 使用完成后,如果 A 给文件加锁了,
需要释放锁 fcntl(fd, F_SETLK, &lock) 【lock.l_type=F_UNLCK】

 

目录操作
#include<unistd.h>
char * getcwd(char *path, size_t size)
char * getwd(char *path) //不安全,废弃
获取当前目录绝对路径
chdir(char *path) //可以使用相对路径
设置path为当前工作目录,需要对目录有x权限
fchdir(int fd)
设置fd对应的目录为当前工作目录


#include<sys/stat.h>
int mkdir(const char *path, mode_t mode)
创建目录
int rmdir(char *path)
删除目录


读取目录
#include<dirent.h>
DIR * opendir(const char *path) //FILE* p =…
打开目录
struct dirent *readdir(DIR *pDir) //fread(p, ...)
读取目录(entity)
int close(DIR *pDir)
关闭目录

void seekdir(DIR *pDir, long locate)
类似seek()
void rewinddir(DIR *pDir)
类似rewind()
long telldir(DIR *pDir)
类似ftell()


struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};


读取文件例子:
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>

void DirTree(char *szBasePath,int nDeep)
{
DIR *pDir;
int i;
char *szSubPath;
struct dirent* pDirent;

pDir=opendir(szBasePath); //打开目录
if(pDir==NULL)
{
perror("fail open dir");
return ;
}
while(1)
{
pDirent=readdir(pDir); //读取目录,获取其属性
if(pDirent==NULL)
{
break;
}
//一定要判断,不要后面的递归会出现死循环,不断在本级目录和上级目录
if(!strcmp(pDirent->d_name,".")||!strcmp(pDirent->d_name,".."))
{
continue;
}
for(i=0;i!=nDeep;++i)
{
printf("| ");
}
//目录,递归
if(pDirent->d_type==DT_DIR)
{
printf("|--%s\n",pDirent->d_name);
sprintf(szSubPath,"%s/%s",szBasePath,pDirent->d_name);
DirTree(szSubPath,nDeep+1);
}
//文件
else
{
printf("|--%s\n",pDirent->d_name);

}
}
close(pDir);
}

void main()
{
//char szPath[PATH_MAX];
//getcwd(szPath,PATH_MAX);
char *szPath="/home";
printf("%s\n",szPath);
DirTree(szPath,1);
}

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部