引言:
本文章介绍了在linux 系统中如何利用库函数来编写C语言程序,实现文件的创建,面向小白,及其通俗易懂!!!
必备知识:
1.open()函数
功能描述:用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。
所需头文件:#include <sys/types.h>,#include <sys/stat.h>,#include <fcntl.h>(有时候你只包含 <fcntl.h>,程序通常也能正常编译和运行,但是,从严格的标准和可移植性角度出发,正确的做法是包含所有三个头文件。部分符号常量和结构体包含在<sys/stat.h>中,open 函数的第三个参数 mode_t mode 是一个特殊的数据类型,用于表示文件权限,这些数据类型的定义通常在 <sys/types.h> 中。)
函数原型(正确格式):int open(const char *pathname,int flags,int perms)
参数:pathname:被打开的文件名(可包括路径名如"dev/ttyS0")
flags:文件打开方式(标志,可设置)该实验要求可读可写,我们用到以下三种标志:
O_RDONLY:以只读方式打开文件
O_WRONLY:以只写方式打开文件
O_RDWR:以读写方式打开文件
O_CREAT:文件如果没有就创建
perms:被打开文件的存取权限,可以用两种方法表示,可以用一组宏定义:S_I(R/W/X)(USR/GRP/OTH),其中R/W/X表示读写执行权限,
USR/GRP/OTH分别表示文件的所有者/文件所属组/其他用户,如S_IRUUR|S_IWUUR|S_IXUUR,(-rex------),也可用四位2进制表示同样的权限(个人习惯用四位2进制)
返回值:成功返回文件描述符 ,失败返回-1。
2.close()函数
功能描述:用于关闭一个被打开的的文件(不关闭可能导致资源泄露)
所需头文件: #include <unistd.h>
函数原型:int close(int fd)
参数:fd文件描述符
函数返回值:0成功,-1出错
3. exit()函数
功能描述:用于立即终止当前正在运行的进程。它会关闭该进程打开的所有文件描述符,释放所有占用的资源,并将控制权返回给操作系统。exit() 执行后,进程中 exit() 之后的代码将不会被执行。
所需头文件:#include <stdlib.h>
函数原型:void exit(int status);
参数:status:这是一个整型参数,用于向父进程传递进程的终止状态。为了提高代码的可读性和可移植性,建议使用 <stdlib.h> 中定义的标准宏:EXIT_SUCCESS:通常被定义为 0,表示成功。EXIT_FAILURE:通常被定义为 1,表示失败。
函数返回值:exit() 函数没有返回值。因为它会终止进程,所以它永远不会返回到调用它的地方。
4. creat()函数
功能描述:用于创建一个新文件并以只写方式打开。如果该文件已经存在,则会将其内容清空(截断为 0 长度)。creat() 函数相当于调用 open(pathname, O_WRONLY | O_CREAT | O_TRUNC, mode)。
所需头文件:#include <fcntl.h>
函数原型:int creat(const char *pathname, mode_t mode);
参数:pathname:一个字符串指针,指向要创建或打开的文件路径名(可以是相对路径或绝对路径)
mode:与open一致
函数返回值:成功时:返回一个非负整数,即新打开文件的文件描述符(file descriptor)。失败时:返回 -1,并设置全局变量 errno 来指示具体的错误原因(例如,EEXIST 表示文件已存在,EACCES 表示权限不足等)。
代码实现:
本文用到的两个最重要的函数是creat函数和open函数,还有主函数和调用函数两种方法。方法核心原理大差不差,使用主函数行数少一点,但作为一个新手,我认为只要有多尝试不同的方法才能理解本质,清楚的知道creat函数和open函数的本质区别。从功能上来讲,两者功能相同,但open函数相比于creat函数更为现代和灵活,但原因是什么呢通过这四个代码还有在用主函数和调用函数的时候我发现了并且知道了更多的注意事项,这点会在后面总结
方法1:用creat函数+主函数
#include<stdio.h>
#include<fcntl.h>//open函数
#include<unistd.h>//close函数
#include<stdlib.h>//exit函数
int main()
{
const char *filename="text1.txt";//设定创建文件的名字
int fd=creat(filename,0666);//给该操作返回值命名方便判断
if(fd==-1)
{
perror("Error creating file");
}
else
{
printf("File '%s' created successfully\n",filename);
}
close(fd);//退出程序
return 0;
}
小结:这里刚开始我在创建失败那里插了一个exit(1),但这是不可取的,exit(1) 会立即终止整个进程。这意味着,file_creat 函数中 exit(1) 之后的所有代码都不会被执行。在这种情况下,close(fd); 这行代码永远不会被触及。如果不关闭程序,这是极其危险的,会造成内存泄露问题!!!此外我还发现创建成功并且查看权限发现并不是预想中的-rw-rw-rw

方法2:用creat函数+调用函数
#include<stdio.h>
#include<sys/types.h> // 显式包含必要头文件(提升可移植性)
#include<sys/stat.h> // 显式包含必要头文件
#include<fcntl.h> // open函数
#include<unistd.h> // close函数
#include<stdlib.h> // exit函数、EXIT_FAILURE/EXIT_SUCCESS
int file_creat(const char *filename)
{
int fd=creat(filename,0666);//给该操作返回值命名方便判断
if(fd==-1)
{
perror("Error creating file\n");
return -1;
}
printf("File '%s' created successfully\n",filename);
if(close(fd)==-1)//检查是否关闭
{
perror("Error closing file");//这里perror 会自动换行,加上 \n 会产生空行
return -1;
}
return 0;//操作成功
}
int main()
{
const char *filename="text2.txt";//设定创建文件的名字
if( file_creat(filename)==-1)//判断是否正常
{
exit(EXIT_FAILURE);//如果异常此时主函数只负责退出程序
}
printf("Create completed successfully.\n");
return 0;
}
小结:在本次代码中我发现了要避免在深层函数中调用 exit,那么不能用exit来结束程序怎么办呢,我们在 file_creat 中,用 return -1; 来表示失败,用 return 0; 来表示成功。main 函数负责全局控制它调用其他函数,检查它们的执行结果,并在必要时(例如,关键文件创建失败)决定终止程序。并且两次用creat都没有出现理想结果

方法3:用open函数+调用函数
#include<stdio.h>
#include<sys/types.h> // 显式包含必要头文件(提升可移植性)
#include<sys/stat.h> // 显式包含必要头文件
#include<fcntl.h> // open函数
#include<unistd.h> // close函数
#include<stdlib.h> // exit函数、EXIT_FAILURE/EXIT_SUCCESS
int file_open(const char *filename)
{
int fd=open(filename,O_RDWR | O_CREAT,0666);//给该操作返回值命名方便判断,如果文件不存在则被创建
if(fd==-1)
{
perror("Error opening file\n");
return -1;
}
printf("File '%s' opened successfully\n",filename);
if(close(fd)==-1)//检查是否关闭
{
perror("Error openning file");//这里perror 会自动换行,加上 \n 会产生空行
return -1;
}
return 0;//操作成功
}
int main()
{
const char *filename="text3.txt";//设定创建文件的名字
if( file_open(filename)==-1)//判断是否正常
{
exit(EXIT_FAILURE);//如果异常此时主函数只负责退出程序
}
printf("Open completed successfully.\n");
return 0;
}
小结:相比与creat函数open函数可以设置以什么方式打开,并且功能也相较更多,确实体现了其现代化,不同的标志有不同的影响,权限还是没有出现理想情况

方法4:用open函数+主函数
#include<stdio.h>
#include<sys/types.h> // 显式包含必要头文件(提升可移植性)
#include<sys/stat.h> // 显式包含必要头文件
#include<fcntl.h> // open函数
#include<unistd.h> // close函数
#include<stdlib.h> // exit函数、EXIT_FAILURE/EXIT_SUCCESS
int main()
{
const char *filename="text4.txt";//设定创建文件的名字
int fd=open(filename,O_RDWR | O_CREAT,0666);
if(fd==-1)
{
perror("Error opening file\n");
}
printf("File '%s' opened successfully\n",filename);
close(fd);
return 0;
}
小结:情况同前四种

总结:
1.creat 函数是一个比较古老的函数,它的功能非常单一:创建一个新文件并以只写方式打开。如果文件已存在,则会清空文件内容。所以在现代的 C 编程中,更推荐使用功能更强大、更灵活的 open 函数来完成这个任务。
2始终检查系统调用(如 open, close, write, read 等)的返回值,并用 perror 打印错误信息,这对于调试至关重要,并且不用加换行符,会自动换行。
3.在 exit 时,使用 EXIT_SUCCESS (0) 和 EXIT_FAILURE (1) 比直接使用 0 和 1 更具可读性。
4.函数exit用于立即终止当前正在运行的进程。它会关闭该进程打开的所有文件描述符,释放所有占用的资源,并将控制权返回给操作系统。所以要避免在使用调用函数时在深层函数里面用,那样可能会导致后资源泄露,一般在深层函数中用返回值来判定是否执行成功
5.检查 close 的返回值也是一个好习惯,成功检查 close 的返回值,尤其是在写入文件之后,是一种防御性编程的实践,虽然在某些简单的、一次性的脚本中,忽略它可能不会有什么严重后果,但在任何正式的、生产环境的软件中,都应该严格遵守这一原则
6.在本次实现中我观察到四次都没出现理想情况-rw-rw-rw,这是一个重要的现象。这是因为 umask 在起作用。umask 是Linux系统的"权限掩码",它会影响新创建文件的最终权限,实际权限 = 你设置的权限 & ~umask。实际权限:0666 & ~0002 = 0664 (rw-rw-r--)。那么这个究竟是什么呢,有什么用呢?答案是为了安全!防止意外创建:所有人可写的文件(安全风险)所有人可执行的文件(更大的安全风险)总之umask的存在是为了系统安全。
2307

被折叠的 条评论
为什么被折叠?



