文件的写入
//文件写入所需的头文件
#include <unistd.h>
write() 文件写入函数
//write()函数原型
ssize_t write(int fd, const void *buf, size_t count);
返回值: 返回实际写入数据的大小,如果count 的值远远大于buf的大小,返回的只有buf的 大小值。
说明: 写入 count个字节的 buf给 fd描述符指向的文件。
用法: 把open打开或创建的文件的描述符传给 write的 fd,并且定义一个指针传给 buf,count为buf的大小,可以用strlen()函数计算buf的大小。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd;
char *buf="this is my VMware Workstation!";
fd=open("./file",O_RDWR);
// ssize_t write(int fd, const void *buf, size_t count);
int n_write=write(fd,buf,strlen(buf));
if(n_write!=-1){
printf("write %d byte to file\n",n_write);
}
return 0;
}
可以看到这里count通过strlen(buf)写入32个字节,当count的值刚好等于buf的大小时。
运行结果:
打开文件:
当count大小不等于buf 的大小时
int n_write=write(fd,buf,100);//上面第14行,count由strlen(buf)变为100
当count的值超过buf的大小时,则会出现以下乱码
int n_write=write(fd,buf,10);//上面第14行,count由strlen(buf)变为10
当count的值小于buf的大小时,则会写入不全。
read() 文件读取函数
//read()函数原型
ssize_t read(int fd, void *buf, size_t count);
返回值: 返回读取 fd 指向文件的 count个字节
说明: 读取fd指向的文件的count个字节的内容,存入buf
用法: 把open的返回值(即fd文件描述符)传递给read的fd,定义一个指针来存放buf的内容,count赋值大小。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd;
char *buf = "Sam Liu is a wonderful FAE!\n";
fd = open("./file",O_RDWR);
printf("open succeess:%d\n",fd);
// ssize_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,buf,strlen(buf));//先写入内容
close(fd);//先关闭文件
fd = open("./file1",O_RDWR);//再打开文件
char *readBuf;
readBuf = (char*)malloc(sizeof(char)*n_write);//使用malloc分配空间给指针
// ssize_t read(int fd, void *buf, size_t count);
int n_read = read(fd,readBuf,n_write);//读取内容
printf("read %d byte,context:%s",n_read,readBuf);
close(fd);
return 0;
}
在以上程序中可以看到,我们在write之后并没有直接read,那是因为read需要文件内的光标在我们所要读取的内容之前(这里为文件的头部),而write后的光标总是在文件的尾部,所以直接在write之后读取的话,不会读取到内容,返回值为0。
但是先关闭文件(close)再打开文件(open)后,光标就在文件的头部,这样才能正确的读取。但是这个操作光标的方法不仅土得掉渣,还不灵活,这就需要光标操作函数lseek()
输出结果:
lseek() 光标操作函数
//lseek()函数原型
off_t lseek(int fd, off_t offset, int whence);
<参数说明>
返回值: 返回一个相对于文件头的偏移值
fd : 需要操作光标的文件的描述符(非负整数);
offset | 负数 | 正数 |
---|---|---|
相对于whence的偏移值 | 往前偏移 | 往后偏移 |
whence | SEEK_SET | SEEK_END | SEEK_COUNT |
---|---|---|---|
光标的位置设定 | 文件头部 | 文件尾部 | 当前位置 |
用法: 在fd指向的文件中,光标从whence的位置,往前或者往后偏移offset个字节。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd;
char *buf = "Sam Liu is a wonderful FAE!\n";
fd = open("./file",O_RDWR);
printf("open succeess:%d\n",fd);
// ssize_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,buf,strlen(buf));//先写入内容
// off_t lseek(int fd, off_t offset, int whence);
lseek(fd,-28,SEEK_END);//从尾部向前偏移28个字节
//又或者 lseek(fd,0,SEEK_SET);//光标从头部开始,偏移0个字节
char *readBuf;
readBuf = (char*)malloc(sizeof(char)*n_write);//使用malloc分配空间给指针
// ssize_t read(int fd, void *buf, size_t count);
int n_read = read(fd,readBuf,n_write);//读取内容
printf("read %d byte,context:%s",n_read,readBuf);
close(fd);
return 0;
}
输出结果:
也可以利用lseek函数来计算文件的大小,这么用:
int n_offset=0;
n_offset=lseek(fd,0,SEEK_END);
因为lseek()的返回值是相对于文件头部的偏移值,所以lseek从头部到尾部的偏移值就算出来了。
close() 关闭文件函数
//close()函数原型
int close(int fd)
说明: 关闭 fd(文件描述符) 指向的文件;
当我们从open到write/read,后一定要用close来关闭文件,这样才完成操作文件的基本流程,也防止程序出错及文件丢失。至于为什么,这涉及到文件操作的原理。
文件的操作原理
文件描述符
0 | 1 | 2 |
---|---|---|
标志输入 | 标准输出 | 标准错误 |
- 文件描述符是一个非负整数,当打开一个现存的文件或创建一个新文件时,内核会向进程返回一个文件描述符,当读写一个文件时,用open()或者creat返回的文件描述符标识该文件,作为参数传递给write和read。
- 在UNIX Shell中,文件描述符有3个已经定义的宏,它们分别替代了0、1、2:
STDIN_FILENO: 替代了 0 :为标准输入文件,传递给read的时候,可以获取键盘的输入,作用相当于scanf;
STDOUT_FILENO: 替代了 1:为标准输出文件,传递给write 可以打印输出,相当于printf;
STDRR_FILENE: 替代了 2 :为标准错误文件,以后可以用来作错误提示。
这就解释了为什么我们在创建文件的时候,文件描述符总是先从3开始。 - 文件描述符的作用域是当前的进程,出了这个进程后,这个文件描述符就没有意义了,也就是说这个文件描述符不起作用了。
静态文件及动态文件
静态文件
静态文件存于磁盘当中,比如我们电脑桌面的文件夹,就属于静态文件。
动态文件
当我们open一个静态文件之后,Linux内核会产生一个结构体来描述这个文件,结构体当中的文件名,文件大小、文件内容等元素;而其中的文件内容就是我们在使用 write 或者 read 所操作的文件,就是动态文件。它在close(关闭文件 )之前会存放在内存当中,直到执行close之后,才会存放在磁盘当中,变成静态文件。这就是为什么我们在write/read之后要close的原因。