Linux文件IO操作

Linux文件IO操作

文件与目录

​ 文件除了文件内容外,还有一个名字和一些属性,即:“管理信息”,以便于进行管理。文件的属性被保存在文件的索引节点(inode)中。在Unix/Linux文件系统中Inode是文件系统中的一个特殊的数据块,用于保存文件的属性信息,这些属性信息包括:文件使用的设备号、索引节点号、文件访问权限和文件类型、文件的硬链接数、UIDGID、设备文件的设备号、文件大小、包含该文件的磁盘的块大小、文件占用的磁盘块的数、最后访问时间、最后修改时间、文件状态最后改变时间。

​ 目录目录的内容主要由:文件名和索引节点号组成。目录中每一对文件名和索引节点号称为一个“连接”。在删除目录中文件时,实质为删除该目录和文件的硬链接数。

输入输出

通过程序读写文件之前,必须先建立程序和文件之间的连接,即打开文件,Linux中有两种方式建立连接:文件描述符

文件描述符:int类型的对象,应用文件描述符的函数多为系统调用,它们提供底层的输入输出操作接口,主要用于对特定的设备进行操作。【STDIN_FILENO(标准输入)、STDOUT_FILENO(标准输出)、STDERR_FILENO(标准错误输出)】

流:建立在文件描述符之上。流操作函数都是C的标准库函数,任何运行ANSI C的系统上均支持流。

System系统调用

<函数调用时应加载头文件stdlib.h>,调用fork()产生子进程,子进程调用/bin/sh -c string来执行字符串中的命令。执行完后返回原进程。

int system(char *cmdstr);

采用以上的命令格式,cmdstr为命令行下的命令字符。

#include<stdio.h>
#include<stdlib.h>//加载system头文件
int main(){
    int newset;
    newset = system("ls -al .");//调用ls -al .命令
    return 0;
}

system执行成功则返回shell命令后的返回值,调用/bin/sh失败则返回127;其他原因失败则返回-1;参数string为空(NULL)则返回非零值。

文件权限

int chmod (char *path , mode_t mode);

包含头文件<sys/types.h>和<sys/stat.h>,修改path指定文件的权限。权限修改成功返回0,失败返回-1。错误原因存在errno

#include<sys/types.h>
#include<sys/stat.h>
int main(){
    chmod("/etc/passwd",S_IRUSR | S_IRGRP | S_IROTH);//修改文件权限
    return 0;
}

mode为一个32位无符号整数,多个mode权限通过或连接添加。以下是mode的权限。

取值权限
S_IRUSR所有者读权限
S_IWUSR所有者写权限
S_IXUSR所有者执行权限
S_IRGRP组成员读权限
S_IWGRP组成员写权限
S_IXGRP组成员执行权限
S_IROTH其他人读权限
S_IWOTH其他人写权限
S_IXOTH其他人执行权限

USR为user所有者,GRP为group组,OTH为other其他用户,R为读,W为写,X为执行。

mode_t umask(mode_t cmask);

修改当前进程环境的权限掩码为cmask:八进制值。返回修改之前的掩码。

使用所需头文件同chmod函数。rwx-分别对应4210,权限相加为所得对象的权限。相较于掩码mask,对于文件来说建立文件的真正权限为0666-mask,对于文件夹来说建立文件夹的真正权限为0777-mask。

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
int main(){
    mode_t new_umask,old_umask;
    new_umask = 0666;//八进制
    old_umask = umask(new_umask);//返回修改前的掩码
    system("touch liu1");//liu1权限:0000;
    new_umask = 0444;
    old_umask = umask(new_nmask);
    system("touch liu2");//liu2权限:0222;
    return 0;
}

其他属性

int fstat(int fd,struct stat* buf);

获取指定文件描述符文件的属性信息,并填充到buf

int stat(const char *path,struct stat *buf);

int lstat(const char *path,struct stat *buf);

获取指定文件文件的属性信息,并填充到buf。区别在于,若文件为符号链接,stat返回的是该链接指向的文件的信息,而lstat返回的是符号链接的属性信息。成功返回0,失败返回-1.

struct stat结构变量:

变量信息
mode_t st_mode文件类型和权限信息
ino_t st_ino文件结点号
dev_t st_dev文件所在设备的文件系统标识号
dev_t st_rdev文件所表示的特殊设备文件的设备标识
nlink_t st_nlink硬链接数
uid_t st_uid文件用户标识 用户ID
gid_t st_gid文件用户组标识 组ID
off_t st_size总大小,字节为单位
time_t st_atime文件内容最后访问的时间
time_t st_mtime文件内容最后修改时间
time_t st_ctime文件结构最后状态改变时间
blksize_t st_blksize文件系统的块大小
blkcnt_t st_blocks文件所占块的数量

类型判断宏

#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main(){
    struct stat buf;
    char filename[20] = "file.c";
    if(stat(filename,&buf)<0)//运行成功为0,失败为-1
        printf("%s\n",filename);
    if(S_ISLNK(buf.st_mod)) printf("l");//是否为符号链接文件
    else if(S_ISREG(buf.st_mod)) printf("-");//是否为常规文件
    else if(S_ISDIR(buf.st.mod)) printf("d");//是否为目录文件
    else if(S_ISCHR(buf.st_mod)) printf("c");//是否为字符设备
    else if(S_ISBLK(buf.st_mod)) printf("b");//是否为块设备
    else if(S_ISFIFO(buf.st_mod)) printf("f");//是否为命名管道
    else if(S_ISSOCK(buf.st_mod)) printf("s");//是否为套接字
    if(buf.st_mod&S_IRUSR) printf("r");//检验是否有所有者读权限
    else printf("-");
    return 0;
}

不带缓存的文件IO操作——系统调用

所需头文件:fcntl.h

文件创建

int creat(char *pathname,mod_t mode);

pathname:待创建文件路径; mode_t:新建文件的初始权限

成功返回一个最小可用的文件描述符,否则返回-1.

文件打开与关闭

int open(char *pathname, int flags[, mode_t mode])

flags:打开方式

O_RDONLY(只读打开)、O_WRONLY(写入打开)、O_RDWR(读写打开)、O_APPEND(在文件尾写入)、O_TRUNC(清空原有内容)、O_CREAT:同时通过mode指定权限、O_EXCL与CREATE一起使用,若新建文件存在则打开失败。

int close(int fd)

关闭文件,fd:文件描述符,头文件:unistd.h

文件读写

ssize_t read(int fd, void *buf, size_t count)

从fd中读取count个字节到缓存buf中,返回实际读取的字节数,出错返回-1。

ssize_t write(int fd, void *buf, size_t count)

将buf中count个字节写入到fd指向的文件中;返回实际写入的字节数,出错返回-1。

lseek(int fd, off_t offset, int whence)

定位指针,whence:SEEK_SET(从距文件开头offset位移量为新的读写位置)、

SEEK_CUR(以目前的读写位置往后增加offset个位移量)、

SEEK_END(从文件尾增加offset个位移量).

#include<stdio.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int main(){
    int fsrc,fdes,nbytes,wr;
    int flag = O_CREAT | O_TRUNC | O_WRONLY;
    int buff[1048];
    fsrc = open("/etc/passwd",O_RDONLY);//打开文件,返回文件描述符
    if(fsrc<0){
        printf("打开源文件错误.\n");
        exit(1);
    }
    if((fdes = open("./pass",flag,0644))<0){//打开目标文件,方式+权限
        printf("打开目的文件错误.\n");
        exit(1);
    }
    while((nbytes=read(fsrc,buff,1024))>0){//文件复制
        wr = write(fdes,buff,nbytes);
        if(wr<0)
            printf("写入文件错误\n");
    }
    close(fsrc);//关闭文件
    close(fdes);
    return 0;
}

强制锁

#include<unistd.h>

#include<fcntl.h>

int fcntl(int fd, int cmd[, flags|lockType]);

cmd:操作命令。F_GETFL:获取指定描述符的状态标识;F_SETFL:重设文件状态标识:O_APPEND、O_NONBLOCK、O_ASYNC。

lockType: 一个struct flock 类型变量

flags = fcntl(fd,F_GETFL,0);//获取文件的flags,即open的第二个参数
flags|=O_NONBLOCK;
fcntl(fd,F_SETFL,flags);//设置为非阻塞
flags&=~O_NONBLOCK;
fcntl(fd,F_SETFL,flags);//取消非阻塞状态->阻塞

在这里插入图片描述

文件默认以阻塞方式打开;非阻塞方式在打开文件时,在flags中添加O_NONBLOCK即可。

以非阻塞方式操作时,若不能读写,则读写函数立即返回-1,并置errno为EWOULDBLOCK。

建议锁——flock

建议性锁,不具备强制性。一个进程使用flock将文件锁住,另一个进程可以直接操作正在被锁的文件,修改文件中的数据,原因在于flock只是用于检测文件是否被加锁,针对文件已经被加锁,另一个进程写入数据的情况,内核不会阻止这个进程的写入操作,也就是建议性锁的内核处理策略。

进程使用flock尝试锁文件时,如果文件已经被其他进程锁住,此时有两种工作模式:阻塞直到锁被释放;非阻塞反回错误,errno为EWOULDBLOCK。

#include<sys/file.h>

int flock(int fd, int operation);//成功返回0,失败返回-1.

operation:锁类型

LOCK_SH:共享锁;多个进程可同时对同一个文件建立共享锁;
LOCK_EX:互斥锁;一个文件只能有一个互斥锁。
LOCK_UN:解锁。
LOCK_NB:指示若无法建立锁则立即返回进程;通常与LOCK_SH和LOCK_EX同时使用

struct flock
{
	shot l_type;	//锁类型:F_WRLCK(互斥锁)、F_RDLCK(共享锁)、F_UNLCK
	shot l_whence;  //l_start计算方式
	off_t l_start;	//加锁起始点:SEEK_SET、SEEK_CUR、SEEK_END
	off_t l_len;	//加锁长度,0:表示整个文件
	pid_t l_pid;	//加锁进程号,由内核设置
}

带缓存的文件流操作

又称为标准I/O操作,符合ANSI C标准,是在内存中开辟一个“缓存区”,为程序中的每个文件使用。

函数:fopen、fclose、fgetc、fputc、fgets、fputs、fread、fwrite、fseek、rewind、ftell

特殊流:stdin、stdout、stderr

特殊文件操作

目录操作

#include<dirent.h>
int mkdir(char *path,mode_t mode);//创建目录
DIR opendir(char *name);//打开目录
struct dirent* readdir(DIR *dir);//返回下一个文件的入口,到达末尾或出现错误则返回NULL
int closedir(DIR *dir);//关闭目录

目录相关的结构体

struct dirent{
	Ino_t	d_ino;	//此目录的i节点号
	ff_t	d_off;	//开始目录至此目录的偏移量
	unsigned short int  d_reclen;	//文件名长度
	unsigned char d_type; 		//文件类型
	char d_name [NAME_MAX+1];	//文件名
}

DIR 同 FILE 为内部结构体,不需了解内部成员。

创建链接

int symlink(char *oldpath, char *newpath) //符号链接

符号链接:类似于windows中的“快捷方式”。符号链接是一个独立的文件,有自己的i节点,内容保存的是指向真实文件的路径。可以跨越文件系统,创建时原文件可以不存在

int link(char *oldpath, char *newpath) //硬链接

硬链接:与原文件共享同一个i节点,相当于原文件的一个别名;硬链接不可以跨越文件系统,创建时原文件必须存在,不能给目录创建目录链接。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(){
        system("mkdir bin");
        system("cp -r /bin/ls ./bin/");
        symlink("/bin/ls","ls1");
        link("./bin/ls","ls2");
        system("ls -l ls1");
        system("ls -l ls2");
        system("ls -l /bin/ls");
        return 0;
}
```c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(){
        system("mkdir bin");
        system("cp -r /bin/ls ./bin/");
        symlink("/bin/ls","ls1");
        link("./bin/ls","ls2");
        system("ls -l ls1");
        system("ls -l ls2");
        system("ls -l /bin/ls");
        return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

registor11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值