Linux文件操作

Linux下的文件操作

文件读写

1
2
3
4
#include<stdio.h>
size_t fread(void *ptr,size_t size,size_t nmemb,FILE *steam);
size_t fwrite(void *ptr,size_t size,size_t nmemb,FILE *stream)
//数据块读写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<stdip.h>
//格式化读写
int printf(const char *format,...);
int scanf(const char *format,...);
int fprintf(FILE *stream,const char *format,...);
int fscanf(FILE *stream,const char *format,...);
int sprintf(char *str,const char *format,...);
int sscanf(char *str,const char *format,...);
//单个字符读写
int fgetc(FILE *stream);
int fputc(int c,FILE *stream);
int getc(FILE *stream) //等同于fgetc
int putc(int c,FILE *stream); //等同于fputc
int getchar(void) //等同于fgetc(stdin)
int putchar(int c); //等同于fputc(int c,stdout);
//字符串读写
char *fgets(char *s,int size,FILE *stream);
int fputs(const char *s,FILE *stream);
int puts(const char *s);
char *gets(char *s); //等同于fgets(const char *s,int size,stdin)
//文件定位
int feof(FILE *stream); //通常用法为while(!feof(fp))
int fseek(FILE *stream,long offset,int whence);//设置当前读写点到偏移whence长度为offset处
//whence可以是: SEEK_SET(文件开头 *0) SEEK_CUR(文件当前位置 *1) SEEK_END(文件末尾 *2)
long ftell(FILE *stream); //用来获取文件流当前的读取位置
void rewind(FILE *stream); //把文件流的读写位置移动至文件开头

目录操作

修改目录或文件的访问权限

1
2
#include<sys/stat.h>
int chmod(const char *path,mode_mod mode);//mode 形如:0777

获取、改变当前目录

1
2
3
#include<unistd.h>
char *getcwd(char *buf,size_t size);//获取当前目录
int chdir(const char *path);//修改当前目录

创建和删除目录

1
2
3
4
5
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
int mkdir(const char *pathname,mode_t mode);//创建目录,mode是目录权限
int rmdir(const char *pathname); //删除目录

获取目录信息

1
2
3
4
5
6
7
8
#include<sys/types.h>
#include<dirent.h>
DIR *opendir(const char *name); //打开一个目录
struct dirent *readdir(DIR *dir); //读取目录的一项信息,并返回该项信息的结构体指针
void rewinddir(DIR *dir);//重新定位到目录文件的头部
void seekdir(DIR *dir,off_T offset);//用来设置目录流的当前的读取位置
off_t telldir(DIR *dir); //返回目录流当前的读取位置
int closedir(DIR *dir); //关闭目录文件

获取文件状态

1
2
3
4
#include<sys/types.h>
#include<dirent.h>
#include<unistd.h>
int stat(const char *pathname,struct stat *buf);

读取目录信息的步骤:

  1. 用opendir函数打开目录;
  2. 使用readdir函数迭代读取目录的内容,如果已经读取的目录末尾。
  3. 用closedir函数关闭目录 #### dirent函数体:
    1
    2
    3
    4
    5
    6
    7
    8
    struct dirent
    {
    ino_t d_ino; //inode number
    off_t d_off; //offset to the next dirent
    unsigned shor d_reclen; //length of this record
    unsigned char d_type; //type of file
    char d_name[256]; //filename
    };
    #### stat函数体:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    struct stat {
    mode_t st_mode; //文件对应的模式,文件,目录等
    ino_t st_ino; //inode节点号
    dev_t st_dev; //设备号码
    dev_t st_rdev; //特殊设备号码
    nlink_t st_nlink; //文件的连接数
    uid_t st_uid; //文件所有者
    gid_t st_gid; //文件所有者对应的组
    off_t st_size; //普通文件,对应的文件字节数
    time_t st_atime; //文件最后被访问的时间
    time_t st_mtime; //文件内容最后被修改的时间
    time_t st_ctime; //文件状态改变时间
    blksize_t st_blksize; //文件内容对应的块大小
    blkcnt_t st_blocks; //伟建内容对应的块数量
    };
    ## 标准输入/输出流 stdin stdout stderror

打开、创建和关闭文件

1
2
3
4
5
6
7
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int open(const char *pathname,int flags); //文件名 打开方式
int open(const chat *pathname,int flags,mode_t mode);//文件名 打开方式 权限
int create(const char *pathname,mode_t mode);//文件名权限,现在已经不常用
//open出错返回值为-1

flag可选项:

掩码 含义
O_RDONLY 以只读的方式打开
O_WRONLY 以只写的方式打开
O_RDWR 以读写的方式打开
O_CREAT 如果文件不存在,则创建文件
O_EXCL 仅与O_CREAT连用,如果文件存在,则强制open失败
O_TRUNC 如果文件存在,将文件截至0
O_APPEND 以追加的方式打开文件,每次调用write时,文件指针自动移到文件尾,用于多进程写同一文件的情况
O_NONBLOCK 非阻塞方式打开,无论有误数据读取或者等待,都会立即返回到进程之中
O_NODELAY 非阻塞方式打开
O_SYNC 同步打开文件,只有数据被真正吸入物理设备后才返回

mode可选项

选项 含义
S_IREADS,S_IRUSR 00400权限,代表该文件所有者具有可读取权限
S_IWUSR,S_IWRITE 00200权限
S_IXUSR,S_IEXEC 00100权限
S_IRWXG 00070权限
S_IRGRP 00040权限
S_IWGRP 00020权限
S_IXGRP 00010权限
S_IRWXO 00007权限
S_IROTH 00004权限
S_IWOTH 00002权限
S_IXOTH 00001权限

通常使用直接赋值的形式 eg:0775 Linux对于一个不存在的文件,不能通过O_WRONLY的方式打开,必须加上O_CREAT选项。

读取文件

1
2
3
4
#include<unistd.h>
ssize_t read(int fd,void *buf,size_t count); //文件描述词 缓冲区 长度
ssize_t write(int fd,const void *buf,size_t count);
//read write出错返回-1,其他情况返回读取个数

改变文件大小

1
2
3
4
5
#include<unistd.h>
int ftruncate(int fd,off_t length);
//ftruncate会将文件改为length指定大小,如果小于源文件会截断文件
//文件必须以写入模式打开
//success:1 fail:-1

文件定位

1
2
3
4
#include<sys/types.h>
#include<unistd.h>
off_t lseek(int fd,off_t offset,int whence);
//whence可以是: SEEK_SET(文件开头 *0) SEEK_CUR(文件当前位置 *1) SEEK_END(文件末尾 *2)

获取文件信息

1
2
3
4
5
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
int stat(const char *file_name,struct stat *buf); //文件名 stat结构体指针
int fstat(int fd,struct stat *buf); //文档描述词 stat结构体指针

对于st_mode,以下宏可以对文件类型进行判断 | 宏 | 描述 | | -------------- | -------------------- | | S_ISLNK(mode) | 判断是否为符号链接 | | S_ISREG(mode) | 判断是否为普通文件 | | S_ISDIR(mode) | 判断是否为目录 | | S_ISCHR(mode) | 判断是否为字符型设备 | | S_IDBLK(mode) | 判断是否为块文件 | | S_ISFIFO(mode) | 判断是否为明明管道 | | S_ISSOCK(mode) | 判断是否为套接字 |

文件描述符的复制

1
2
3
4
#include<unistd.h>
int dup(int oldfd);
int dup2(int oldfd,int newfd);
//文件描述符的复制是指用另外一个文件描述符指向同一个打开的文件,他完全不同于直接给文件描述符变量赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//实现重定向
#include"func.h"

int main()
{
int fd = open("a.txt",O_WRONLY|O_CREAT,0644);
int fde=open("error.txt",O_WRONLY|O_CREAT,0644);
if(-1==fd)
{
perror("open error");
}
printf("\n"); //必须做
//close(1);
int fd1=dup2(fd,1); //标准输出重定位到a.txt
int fd2=dup2(fde,2);//标准错误输出重定位到error.txt
close(fd);
printf("hello world\n");
perror("error row\n");
close(fd1);
close(fd2);
return 0;
}

I/O多路转接模型

1
2
3
4
#include<sys/select.h>
#include<sys/time.h>
int select(int maxfd,fd_set *readset,fd_set *writeset,fd_set *exceptionset,struct timeval *timeout);
//返回:就绪描述字的正数目,0:超市,-1:出错
参数 解释
maxfd 最大的文件描述符(其值应该为最大的文件描述符字+1)
readset 内核读操作的操作符字集合
writeset 内核写操作的描述符字集合
exceptionset 内核异常操作的描述符字集合
timeout 等待描述符就绪需要的时间
1
2
3
4
5
//fd_set相关操作
void FD_ZERO(fd_set *fdset); //将所有的fd清零
void FD_SET(int fd,fd_set *fdset);//增加一个fd
void FD_CLR(int fd,fd_set *fdset); //删除一个fd
int FD_ISSET(int fd,fd_set *fdset); //判断一个fd是否有设置
1
2
3
4
5
6
//struct timeval 类型
struct timeval
{
long tv_sec; //second
long tv_usec; //microsecond
}

MMAP文件映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<sys/mman.h>
void * mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
int munmap(void*start,size_t lenght);
/*start:映射区的开始地址,设置为0时表示由系统决定映射区的起始地址
length:映射区长度,长度单位是以字节为单位,不足内存一页按一内存页处理
prot:期望的内存保护标志,不能与文件的打开模式冲突
PROT_EXEC:页内容可以被执行
PROT_READ:页内容可以被读取
PROT_WRITE:页可以被写入
PROT_NONE:页不可访问
flag:指定映射对象的类型,映射选项和映射是否可以共享。它的值可以使一个或者多个一下位的组合体
MAX_FIXED:使用指定的映射其实地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的地址不可用,操作将会失败。并且初始地址必须落在页的边界上。
MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
MAP_DENYWRITE //这个标志被忽略。
MAP_EXECUTABLE //同上
MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。
MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
MAP_FILE //兼容标志,被忽略。
MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。
fd:有效的文件描述词。一般是由open()函数返回,其值也可以设置为-1,此时需要指定flags参数中的MAP_ANON,表明进行的是匿名映射。
off_toffset:被映射对象内容的起点。*/

例子:

1
2
3
4
5
6
7
8
9
#include"func.h"
int main()
{
int fd=open("hello.txt",O_RDWR);
char *p=mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
memcpy(p,"world",5);
munmap(p,1024);
return 0;
}