系统方面对文件的操作
- 1. 系统方面打开文件的函数
- 2. 系统方面对文件的写入
- 3. 系统方面对文件的读取
- 4. 关闭文件close
1. 系统方面打开文件的函数
open函数得到一个指定文件的文件描述符,如果出现错误则返回-1。open函数需要传入一个文件路径和操作模式,调用会返回一个整型的文件描述符。
在Linux系统中,open函数主要作用就是打开和创建文件,可以根据参数来定制需要的文件的属性和用户权限等各种参数。flag参数相当于是宏,并且是可选的,用于设置打开文件的模式。flag参数的取值如下:
O_RDONLY: 只读模式
O_WRONLY: 只写模式
O_RDWR : 读写模式
O_NONBLOCK: 非阻塞模式
O_APPEND: 追加模式
O_CREAT: 创建并打开一个新文件
O_TRUNC: 打开一个文件并截断它的长度为零(必须有写权限)
O_EXCL: 如果指定的文件存在,返回错误
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("log.txt", O_WRONLY);//只写入
printf("fd: %d, errror: %d, errstring: %s\n", fd, errno, strerror(errno));//打印文件描述符,错误码,错误信息
close(fd);
return 0;
}
因为没有创建文件,没有log.txt文件,所以打开文件失败,文件描述符为-1。
然后将上面这句代码进行改动:int fd = open(“log.txt”, O_CREAT | O_WRONLY); 进行创建和写入。
可以看到文件描述符为3(open成功),但是log.txt这个文件的权限是乱的,可以用chmod 0XXX log.txt 进行修改,也可以用open修改。
在Linux系统中,umask是一个用于设置文件和目录默认权限的命令。每个文件和目录都有一组权限,包括读、写和执行权限。umask值是由三个八进制数字表示的。第一个数字表示所有者的权限,第二个数字表示组的权限,第三个数字表示其他人的权限。每个数字都可以是0到7之间的任何数字。所以在test.c文件中,可以将umask设为0,系统下的umask和用户设定的umask,程序用哪个采用就近原则。
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
umask(0);
int fd = open("log.txt",O_CREAT | O_WRONLY, 0666);
printf("fd: %d, errror: %d, errstring: %s\n", fd, errno, strerror(errno));
close(fd);
return 0;
}
2. 系统方面对文件的写入
write函数是基于Linux系统中的一项函数调用,主要用于在打开/创建的文件中写入数据。 write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。 write函数包含的头文件为 #include <unistd.h>。
write()函数的三个参数分别为:文件描述符fd,缓冲区buf和写入字节数count。 当有错误发生时则返回-1,错误代码存入errno中。
要想在文件中写数据,write()函数需要3个参数,fd,count易得,还需要一个缓冲区buf,这个缓冲区里面有给文件中写入的数据,给缓冲区中写入数据,需用到snprintf()函数。
snprintf()是一个C语言标准库函数,它的三个参数分别为:缓冲区buf,缓冲区大小size和格式化字符串format。 如果格式化后的字符串长度超过了size,则会截断超出部分。用于格式化输出字符串,并将结果写入到指定的缓冲区。与sprintf()不同的是,snprintf()会限制输出的字符数,避免缓冲区溢出。
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
umask(0);
int fd = open("log.txt",O_CREAT | O_WRONLY, 0666);
printf("fd: %d, errror: %d, errstring: %s\n", fd, errno, strerror(errno));
//写入
const char *msg = "hello";
int cnt = 3;
while (cnt)
{
char buf[128];
snprintf(buf, sizeof(buf), "%s, %d\n", msg, cnt);
write(fd, buf, strlen(buf) + 1);
--cnt;
}
close(fd);
return 0;
}
这里有一个小细解,strlen求的是‘\0’之前字符串的长度,众所周知,c语言规定‘\0’用于判断字符串的结尾,而打印的时候需不需要带上‘\0’?上述代码是带上’\0’的,写入结果如下所示:
可以看到文件中有^@符号,这些是文件对‘\0’ 的处理,所以对文件进行写入字符串时,不需要带‘\0’,因为’\0’是c语言规定的,不是文件规定的。
当再次向文件中写入,会出现预料之外的结果(如下),这是因为上述代码open函数中的flag参数的原因,O_CREAT | O_WRONLY只是进行创建并打开一个新文件和只写模式,还需要O_TRUNC,如果是追加则需要O_APPEND。
flag参数的取值如下:
O_RDONLY: 只读模式
O_WRONLY: 只写模式
O_RDWR : 读写模式
O_NONBLOCK: 非阻塞模式
O_APPEND: 追加模式
O_CREAT: 创建并打开一个新文件
O_TRUNC: 打开一个文件并截断它的长度为零(必须有写权限)
O_EXCL: 如果指定的文件存在,返回错误
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
umask(0);
int fd = open("log.txt",O_CREAT | O_WRONLY | O_TRUNC, 0666);
printf("fd: %d, errror: %d, errstring: %s\n", fd, errno, strerror(errno));
const char *msg = "hello";
int cnt = 3;
while (cnt)
{
char buf[128];
snprintf(buf, sizeof(buf), "%s, %d\n", msg, cnt);
write(fd, buf, strlen(buf));
--cnt;
}
close(fd);
return 0;
}
3. 系统方面对文件的读取
read()函数是基于Linux系统中的一项函数调用,主要用于从文件描述符fd所指的文件中读取count个字节到缓冲区buf中。 read()函数包含的头文件为 #include <unistd.h>。
read()函数的三个参数分别为:文件描述符fd,缓冲区buf和读取字节数count。 当有错误发生时则返回-1,错误代码存入errno中。
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("log.txt", O_RDONLY); //只读模式
char buf[1024];
size_t n = read(fd, buf, sizeof(buf) - 1);
if (n > 0)
{
buf[n] = '\0';
printf("%s\n",buf);
}
close(fd);
return 0;
对于文件的读写,系统和c语言分别对‘\0’的处理是不一样的,所以在进行字符串到文件的写入或者是从文件中读取数据到c语言中,‘\0’就需要自己处理。如上,在读取字符串的时候,读取的字节数的大小减1,这个位置就准备用来放‘\0’。并且从文件中读取数据,不能进行按行读取,只能进行整体读取(或者是按字节数读取),而c语言按行读取时c语言内部进行了特殊处理。 读取结果如下:
所以c标准库里的fopen,fclose,fwrite,fread等函数都是将系统中的open,close,write,read等函数进行封装,fopen,fclose,fwrite,fread调用的就是系统中的open,close,write,read等函数。
open()函数是一个系统调用,返回的是文件句柄,文件的句柄是文件在文件描述副表里的索引。而fopen()是C的库函数,返回的是一个指向文件结构的指针。这两个函数的区别主要在于:
- open()函数可以打开任何类型的文件,而fopen()函数只能打开文本文件。
- open()函数返回一个文件描述符,而fopen()函数返回一个指向文件结构的指针。
- open()函数不需要stdio.h头文件,而fopen()函数需要stdio.h头文件。
close()函数和fclose()函数都是用于关闭文件的函数,它们之间的区别:
- close()函数是一个系统调用,而fclose()函数是C的库函数。
- close()函数需要一个文件描述符作为参数,而fclose()函数需要一个指向文件结构的指针作为参数。
- close()函数不会刷新缓冲区,而fclose()函数会刷新缓冲区。
- close()函数不会返回任何值,而fclose()函数会返回一个整数值。
4. 关闭文件close
在Linux中,close()函数是一个系统调用,用于关闭文件描述符,以便它不再引用任何文件并可以被重用。如果文件描述符是与记录锁定相关联的,则会删除这些锁定。如果文件描述符是与打开的文件相关联的,则会释放该文件所占用的资源。如果成功执行,则返回0,否则返回-1,并将失败原因记录在errno中。
close()函数的语法如下:
#include <unistd.h>
int close(int fd);
c语言对文件的打开和读写