Unix文件操作(读写操作)
标C文件读写 - FILE* 代表一个打开的文件
Unix/Linux的文件读写函数
Linux系统中 几乎一切都是文件,内存、目录、硬件设备都可以看成文件。比如:
内存 对应目录 /proc/PID/
目录 可以用 vi 查看,也是文件
设备: /dev/tty - 键盘、显示器
/dev/null - 空设备,清空
因此,读写文件函数其实可以读写很多设备,函数包括:
open() - 新建/打开一个文件
read() - 读一个打开的文件/设备
write() - 写一个打开的文件/设备
close() - 关闭一个打开的文件
ioctl() - 其他的一些控制功能
前面4个函数 是标C函数在Unix/Linux系统中 底层的支持(系统调用)。
int open(char* filename,
int flags,...)
...代表0-n个任意类型的参数(可变长参数)
只有新建文件时,需要给出第三个参数,做新文件的权限。
flags是open的标志,主要包括:
O_RDONLY O_WRONLY O_RDWR : 三者必选其一,代表访问权限。文件在硬盘上有文件权限,在打开时有访问权限,访问权限 小于等于 文件权限。
O_CREAT : 代表新建文件,如果文件已存在就打开,有两个辅助项
O_EXCL : 只是新建文件,如果文件已存在,返回-1代表出错。
O_TRUNC: 清空已有文件的内容。
O_APPEND : 以追加方式打开文件
返回文件描述符,出错返回-1。
关于文件描述符
Unix/Linux都是用一个非负整数代表打开的文件,这个非负整数就是 文件描述符。open()函数返回文件描述符,这个文件描述符对应一张 文件表,信息存在文件表中。
每个进程都有一张文件描述符的总表,在总表中存放已经使用的描述符以及描述符和文件表的对应关系。当有新文件打开时,从总表中查找 未使用的最小值返回即可。close()时会把描述符从总表中删除,此时就可以再次使用。
文件描述符从3开始,0、1、2被系统占用,当作 标准输入、标准输出和标准错误。
注:open()新建文件时,文件权限可能被屏蔽。
读写函数:
int read(int fd,void* buf,size_t size)
参数 fd 就是文件描述符,open()返回
buf就是数据存储区的首地址,size是大小
返回值:
正数 - 实际读到的字节数
0 - 读到文件尾(读完了)
-1 - 出错了,可以使用perror()
int write(int fd,void* buf,size_t size)
参数fd就是文件描述符,open()返回
buf是要写的数据的首地址
size不是buf的全部,而是实际要写入的字节数
返回值:
正数 - 实际写入的字节数
0 - 什么都没写
-1 - 出错了,可以使用perror()
读函数和写函数最大的区别在于第三个参数,读函数是buf的大小,而写函数是实际要写的字节数。比如: char buf[];
read(fd,buf,sizeof(buf));
write(fd,buf,strlen(buf));
标C文件读写 - FILE* 代表一个打开的文件
Unix/Linux的文件读写函数
Linux系统中 几乎一切都是文件,内存、目录、硬件设备都可以看成文件。比如:
内存 对应目录 /proc/PID/
目录 可以用 vi 查看,也是文件
设备: /dev/tty - 键盘、显示器
/dev/null - 空设备,清空
因此,读写文件函数其实可以读写很多设备,函数包括:
open() - 新建/打开一个文件
read() - 读一个打开的文件/设备
write() - 写一个打开的文件/设备
close() - 关闭一个打开的文件
ioctl() - 其他的一些控制功能
前面4个函数 是标C函数在Unix/Linux系统中 底层的支持(系统调用)。
int open(char* filename,
int flags,...)
...代表0-n个任意类型的参数(可变长参数)
只有新建文件时,需要给出第三个参数,做新文件的权限。
flags是open的标志,主要包括:
O_RDONLY O_WRONLY O_RDWR : 三者必选其一,代表访问权限。文件在硬盘上有文件权限,在打开时有访问权限,访问权限 小于等于 文件权限。
O_CREAT : 代表新建文件,如果文件已存在就打开,有两个辅助项
O_EXCL : 只是新建文件,如果文件已存在,返回-1代表出错。
O_TRUNC: 清空已有文件的内容。
O_APPEND : 以追加方式打开文件
返回文件描述符,出错返回-1。
关于文件描述符
Unix/Linux都是用一个非负整数代表打开的文件,这个非负整数就是 文件描述符。open()函数返回文件描述符,这个文件描述符对应一张 文件表,信息存在文件表中。
每个进程都有一张文件描述符的总表,在总表中存放已经使用的描述符以及描述符和文件表的对应关系。当有新文件打开时,从总表中查找 未使用的最小值返回即可。close()时会把描述符从总表中删除,此时就可以再次使用。
文件描述符从3开始,0、1、2被系统占用,当作 标准输入、标准输出和标准错误。
注:open()新建文件时,文件权限可能被屏蔽。
读写函数:
int read(int fd,void* buf,size_t size)
参数 fd 就是文件描述符,open()返回
buf就是数据存储区的首地址,size是大小
返回值:
正数 - 实际读到的字节数
0 - 读到文件尾(读完了)
-1 - 出错了,可以使用perror()
int write(int fd,void* buf,size_t size)
参数fd就是文件描述符,open()返回
buf是要写的数据的首地址
size不是buf的全部,而是实际要写入的字节数
返回值:
正数 - 实际写入的字节数
0 - 什么都没写
-1 - 出错了,可以使用perror()
读函数和写函数最大的区别在于第三个参数,读函数是buf的大小,而写函数是实际要写的字节数。比如: char buf[];
read(fd,buf,sizeof(buf));
write(fd,buf,strlen(buf));
vi编辑器如果用q退出,自动加上结束符,cat会换行。
emp.h
#ifndef _EMP_H
#define _EMP_H
typedef struct Emp{
int id;
char name[20];
double sal;
} EMP;
#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include "emp.h"
int main(){
EMP emp;
int fd=open("e.dat",O_RDWR|O_CREAT|O_TRUNC,0666);
if(fd == -1) perror("open"),exit(-1);
printf("请输入员工编号/姓名/薪水\n");
scanf("%d%s%lf",&emp.id,emp.name,&emp.sal);
int res = write(fd,&emp,sizeof(emp));
if(res == -1) perror("write"),exit(-1);
printf("成功写入\n");
close(fd);
}