文件的打开及创建(open和creat)
open函数的头文件、函数原型
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
pathname:待打开/创建文件的POSIX路径名(如/home/user/a.cpp)省略则代表当前路径。
flags:用于指定文件的打开/创建模式。
O_RDONLY 只读模式
O_WRONLY 只写模式
O_RDWR 读写模式
打开/创建文件时,至少得使用上述三个常量中的一个。以下常量是选用的:
O_APPEND 每次写操作都写入文件的末尾
O_CREAT 如果指定文件不存在,则创建这个文件
O_EXCL 如果同时指定了OCREAT 而文件已经存在,则打开文件失败(返回值为-1)。
O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容(即将其长度截短为0)
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
O_NONBLOCK 如果路径名指向FIFO/块文件/字符文件,则把文件的打开和后继I/O
mode:仅当创建新文件时(即用了 O_CREAT 时)才使用,用于指定文件的访问权限位。
是权限来的,我们可以通过 ls -l 指令查看文件 -rwx ,-(普通文件)、r(可读)、w(可写)、x(可执行)。
fd = open("./文件名",o_RDWR|O_CREAT,0600);
0600中的 6 是 4+2(可读可写)
creat函数的头文件、函数原型
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
pathname:待打开/创建文件的POSIX路径名(如/home/user/a.cpp)省略则代表当前路径。
mode:
宏表示 数字
S_IRUSR 4 可读
S_IWUSR 2 可写
S_IXUSR 1 可执行
S_IRWXU 7 可读、可写、可执行
open函数返回值
成功:新打开的文件描述符
失败:-1
open返回的文件描述符一定是最小的而且没有被使用的
creat函数返回值
成功:返回新的文件描述符号。fd=creat();
失败:返回-1, 并把错误代码设给errno.
open函数打开文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
fd=open("./file",O_RDWR);
printf("fd=%d\n",fd);
if(fd>0)
{
printf("open file successfully!\n");
}
else
{
printf("fail to open file!\n");
}
return 0;
}
open函数打开文件配合O_CREAT创建文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
fd=open("./file",O_RDWR);
if(fd==-1)
{
printf("No such file\n");
fd=open("./file",O_RDWR|O_CREAT,0600);
if(fd>0)
{
printf("File created successfully\n");
}
}
return 0;
}
open函数打开文件配合O_EXCL同时指定了OCREAT,而文件已经存在,则打开文件失败(返回值为-1)。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
fd=open("./file",O_RDWR|O_CREAT|O_EXCL,0600);
if(fd==-1)
{
printf("File already exist\n");
}
return 0;
}
运行结果:
文件不存在,则创建文件
文件存在,则打开文件失败(返回值为fd=-1)
O_APPEND每次写时都加到文件的尾端
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd=0;
char* buf="chenlichen hen shuai!";
fd=open("./file",O_RDWR|O_APPEND);
if(fd==-1)
{
printf("No such file\n");
fd=open("./file",O_RDWR|O_CREAT,0600);
if(fd>0)
{
printf("File created successfully\n");
printf("fd=%d\n",fd);
}
}
write(fd,buf,strlen(buf));
close(fd);
return 0;
}
运行结果:
原文件
将 chenlichen hen shuai! 加至文件末尾,另起一行。
如果没有O_APPEDN 则写入内容会按位覆盖原本有的部分内容。
O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或者只写成功打开,则将其长度截短为0(清零!)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd=0;
char* buf="Yinyuer is a pretty girl!";
fd=open("./file",O_RDWR|O_TRUNC);
if(fd==-1)
{
printf("No such file\n");
fd=open("./file",O_RDWR|O_CREAT,0600);
if(fd>0)
{
printf("File created successfully\n");
printf("fd=%d\n",fd);
}
}
write(fd,buf,strlen(buf));
close(fd);
return 0;
}
运行结果:
运行前 file 文件内容
运行后 file 文件内容
creat函数创建文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
fd=creat("/home/yinyuer/file",S_IRWXU);
return 0;
}
运行结果:
运行前,工作目录 /home/yinyuer/ 下的全部文件
运行后,工作目录 /home/yinyuer/ 下的全部文件,以及 file 权限,可读可写可执行。
文件的写入(write)
write函数的头文件、函数原型
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd:文件描述符;
buf:指定的缓冲区,即指针,指向一段内存单元;
count:要写入文件指定的字节数;
write函数的返回值
成功:写入文档的字节数
失败:-1
write函数把buf中count写入文件描述符handle所指的文档,成功时返回写的字节数,错误时返回-1
write函数写入文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd=0;
char* buf="chenlichen hen shuai!";
fd=open("./file",O_RDWR);
if(fd==-1)
{
printf("No such file\n");
fd=open("./file",O_RDWR|O_CREAT,0600);
if(fd>0)
{
printf("File created successfully\n");
printf("fd=%d\n",fd);
}
}
write(fd,buf,strlen(buf));
close(fd);
return 0;
}
注意
计算buf中字符个数时,用strlen()函数
运行结果:
文件的读取(read)
read函数的头文件、函数原型
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd:文件描述符;
buf:指定的缓冲区,即指针,指向一段内存单元;
count:要写入文件指定的字节数;
read函数的返回值
成功:返回读取的字节数
出错:返回-1并设置errno
如果在调read之前已到达文件末尾,则这次read返回0。
read函数读取文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd=0;
char* buf="chenlichen hen shuai!";
fd=open("./file",O_RDWR);
if(fd==-1)
{
printf("No such file\n");
fd=open("./file",O_RDWR|O_CREAT,0600);
if(fd>0)
{
printf("File created successfully\n");
printf("fd=%d\n",fd);
}
}
int n_write=write(fd,buf,strlen(buf));
if(n_write!=-1)
{
printf("Writed %d bytes to file\n",n_write);
}
close(fd);
fd=open("./file",O_RDWR);
char* readBuf=NULL;
readBuf=(char*)malloc(sizeof(char)*n_write);
int n_read=read(fd,readBuf,n_write);
if(n_read!=-1)
{
printf("read %d bytes from file:%s\n",n_read,readBuf);
}
close(fd);
return 0;
}
注意
我们对文件打开之后并且写入内容,当我们读取文件内容时,有两种方法:
-
先关闭文件 close(fd),再重新打开文件 open(“./file”,O_RDWR) 读取文件。因为如果你不关闭文件,光标是在文件末端,是读取不到数据的。
-
使用 lseek() 函数,lseek(fd,0,SEEK_SET) 把光标重新拉回文件头。
运行结果:
文件光标的移动就、计算文件大小(lseek)
lseek函数的头文件、函数原型
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
fd:文件描述符;
offset:向后的偏移值,整数往后,负数往前
whence:
SEEK_SET 参数 offset 即为新的读写位置.
SEEK_CUR 以目前的读写位置往后增加 offset 个位移量.
SEEK_END 将读写位置指向文件尾后再增加 offset 个位移量.当 whence 值为 SEEK_CUR 或 SEEK_END 时, 参数 offet 允许负值的出现.
下列是教特别的使用方式:
-
欲将读写位置移到文件开头时:lseek(int fildes,0, SEEK_SET);
-
欲将读写位置移到文件尾时:lseek(int fildes,0, SEEK_END);
-
想要取得目前文件位置时:lseek(int fildes,0, SEEK_CUR);
lseek函数的返回值
成功:返回目前的读写位置, 也就是距离文件开头多少个字节.
失败:则返回-1, errno 会存放错误代码.
lseek函数将光标拉回文件开头
我们之前打开文件并且写入内容,我们不用关闭再打开文件再读取,我们直接用lseek让光标移到头就可以了。
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd=0;
char* buf="chenlichen hen shuai!";
fd=open("./file",O_RDWR);
if(fd==-1)
{
printf("No such file\n");
fd=open("./file",O_RDWR|O_CREAT,0600);
if(fd>0)
{
printf("File created successfully\n");
printf("fd=%d\n",fd);
}
}
int n_write=write(fd,buf,strlen(buf));
if(n_write!=-1)
{
printf("Writed %d bytes to file\n",n_write);
}
// close(fd);
// fd=open("./file",O_RDWR);
lseek(fd,0,SEEK_SET);
char* readBuf=NULL;
readBuf=(char*)malloc(sizeof(char)*n_write);
int n_read=read(fd,readBuf,n_write);
if(n_read!=-1)
{
printf("read %d bytes from file:%s\n",n_read,readBuf);
}
close(fd);
return 0;
}
lseek函数计算文件的大小
通过 lseek 的返回值来计算内容大小。
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd=0;
char* buf="chenlichen hen shuai!";
fd=open("./file",O_RDWR);
int fileSize=lseek(fd,0,SEEK_END);
printf("file 's size is %d\n",fileSize);
close(fd);
return 0;
}
运行结果:
用lseek构建空洞文件
-
空洞文件就是这个文件中有一段是空的。
-
普通文件中间是不能有空的,因为我们write时文件指针是依次从前到后去移动的,不可能绕过前面直接到后面。
-
我们打开一个文件后,用lseek往后跳过一段,再write写入一段,就会构成一个空洞文件。
-
空洞文件方法对多线程共同操作文件是及其有用的。有时候我们创建一个很大的文件,如果从头开始依次构建时间很长。有一种思路就是将文件分为多段,然后多线程来操作每个线程负责其中一段的写入。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/*
* ./lseek_2 1.txt
* argc = 2
* argv[0] = "./lseek_2"
* argv[1] = "1.txt"
* ...
*/
int main(int argc,char **argv)
{
int i = 0;
int fd = 0;
int len = 0;
char *read_Buf = "hello_word!";
if(argc < 2)
{
printf("Usage:%s <file> <message> ...\n",argv[0]);
return -1;
}
fd = open(argv[1],O_RDWR | O_CREAT, 0666);
if(fd < 0)
{
printf("Can not open %s!\n",argv[1]);
printf("errno = %d\n",errno);
printf("%s\n",strerror(errno));
return -1;
}
lseek(fd,10,SEEK_SET);
write(fd,read_Buf,strlen(read_Buf));
close(fd);
return 0;
}
运行结果:
偏移值 : 10 + hello_word! : 11 = 21