【图书推荐】《Linux C与C++一线开发实践(第2版)》_linux c与c++一线开发实践pdf-CSDN博客
LinuxC\C++编程技术_夏天又到了的博客-CSDN博客
《Linux C与C++一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书
I/O就是输入/输出,它是主存和外部设备(比如硬盘、U盘)之间复制数据的过程,其中数据从设备到内存的过程称为输入,数据从内存到设备的过程称为输出。I/O可以分为低级I/O和高级I/O。低级I/O通常也称为不带缓冲的I/O,它是Linux提供的系统调用,如函数open、read、write等。高级I/O通常也称为带缓冲的I/O,比如ANSI C提供的标准I/O库中的fopen、fread、fwrite等函数就是这种高级I/O的例子。带缓冲的I/O在系统调用前会采用一定的策略,因此速度会比较慢,但它比不带缓冲的I/O安全。
对于Linux而言,所有对设备或文件的操作都是通过文件描述符进行的。当打开或者创建一个文件的时候,内核向进程返回一个文件描述符(非负整数),后续对文件的操作就可以通过该文件描述符来执行,内核记录有关这个打开文件的信息。一个进程启动时,默认打开3个文件,标准输入、标准输出、标准错误,对应的文件描述符分别是0(STDIN_FILENO)、1(STDOUT_FILENO)、2(STDERR_FILENO)。这些常量定义在unistd.h头文件中。
我们以前可能没接触过文件描述符,接触较多的是文件指针,其实两者之间是可以通过函数fileno和fdopen相互转换的。函数fileno将文件指针转换为文件描述符,声明如下:
int fileno(FILE *stream);
其中,参数stream是文件指针。
函数fdopen将文件描述符转换为文件指针,声明如下:
FILE *fdopen(int fd, const char *mode);
其中,参数fd是文件描述符,mode是打开方式。
【例4.1】打印stdin、stdout和stderr的文件描述符值
(1)打开Visual Studio Code,新建一个test.cpp文件,在test.cpp中输入如下代码:
#include
#include
int main(void)
{
printf("fileno(stdin) = %d\n", fileno(stdin));
printf("fileno(stdout) = %d\n", fileno(stdout));
printf("fileno(stderr) = %d\n", fileno(stderr));
return 0;
}
(2)上传test.cpp到Linux,在终端下输入命令g++ -o test test.cpp,然后运行test,运行结果如下:
[root@localhost cpp98]# g++ -o test test.cpp
[root@localhost cpp98]# ./test
fileno(stdin) = 0
fileno(stdout) = 1
fileno(stderr) = 2
Linux提供open函数来打开或者创建一个文件。该函数声明如下:
#include
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
其中,参数pathname表示文件的名称,可以包含(绝对和相对)路径;flags表示文件打开方式;mode用来规定对该文件的所有者、文件的用户组及系统中其他用户的访问权限。如果函数执行成功,就返回文件描述符,如果函数执行失败,就返回-1。
文件打开的方式flags可以使用下列宏(当有多个选项时,采用“|”连接):
最后3个SYNC(同步)选项都会降低性能。使用这些宏需要包含头文件fcntl.h。值得注意的是,O_RDONLY、O_WRONLY和O_RDWR这3个选项是必选其一的。
参数mode只在创建文件时才使用,用于指定文件的访问权限。Mode可以使用下列宏:
使用这些权限宏,需要包含头文件sys/stat.h。文件的访问权限是根据umask&~mode得出来的,例如umask=0022,mode = 0655,则访问权限为644。umask是目前用户在建立档案或目录时的权限默认值,我们可以通过命令umask查看该值,比如:
[root@localhost ~]# umask
0022
[root@localhost ~]# umask -S
u=rwx,g=rx,o=rx
加S表示以字符形式显示。
下面看一个小例子,创建一个指定权限的文件。
打开文件,既可以用相对路径,又可以用绝对路径。比如,打开当前目录zww下的文件myfile.dat,可以这样写:
int fd = open("./zww/myfile.dat", O_RDWR);
其中,“.”表示当前工作目录,当前进程被启动的目录就是当前工作目录。
如果要以只读方式打开当前目录上级目录下的某个文件,可以这样写:
int fd = open("../myfile.dat", O_RDONLY); // 其中..表示当前工作目录的上一级目录
或者打开一个绝对路径下的文件,比如:
int fd = open("/etc/myfile.dat", O_CREAT| O_RDWR); // 不存在就新建,否则以读写方式打开
为了维持与早期的UNIX系统的向后兼容性,Linux也提供了一个专门创建文件的系统调用,即creat函数(注意结尾没有e)。它的声明如下:
int creat(const char *pathname, mode_t mode);
其中,参数pathname表示文件的名称,可以包含(绝对和相对)路径;mode用来规定对该文件的所有者、文件的用户组及系统中其他用户的访问权限,其取值与open函数的mode相同。如果函数执行成功,就返回文件描述符,否则返回-1。
在UNIX的早期版本中,open系统调用函数仅仅存在两个参数的形式。如果文件不存在,就不能打开这些文件。文件的创建则由单独的系统调用函数creat完成。在Linux及所有UNIX的近代版本中,creat系统调用函数是多余的,因为open也可以用来创建文件。下面两种形式等价。
int fd = creat(file, mode);
int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
【例4.2】创建一个只读的文件
(1)打开Visual Studio Code,新建一个test.cpp文件,在test.cpp中输入如下代码:
#include
#include
#include
#include
#include
int main(void)
{
int fd = -1;
char filename[] = "/root/test.txt"; // 注意路径中的/不要写成\
fd = creat(filename,0666); // 创建只读属性的文件
if (fd == -1)
printf("fail to pen file %s\n", filename);
else
printf("create file %s successfully\n", filename);
return 0;
}
(2)上传test.cpp到Linux,在终端下输入命令g++ -o test test.cpp,然后运行test,运行结果如下:
[root@localhost cpp98]# g++ -o test test.cpp
[root@localhost cpp98]# ./test
create file /root/test.txt successfully
我们在路径/root下创建了一个文件test.txt。即使test.txt存在,依然会成功创建。
文件不再使用的时候,需要把它关闭。可以用函数close来关闭文件,该函数声明如下:
#include
int close(int fd);
其中,参数fd为要关闭的文件的描述符。如果函数执行成功,就返回文件描述符,否则返回-1。
文件关闭以后,文件描述符不再指向任何文件,从而描述符可以再次使用。如果每次打开文件后都不关闭,就会将系统的文件描述符耗尽,导致不能再打开文件。
【例4.3】打开并关闭一个文件
(1)打开Visual Studio Code,新建一个test.cpp文件,在test.cpp中输入如下代码:
#include
#include
#include
#include
#include
int main(void)
{
int fd = -1;
char filename[] = "test.txt"; // 若没有使用绝对路径,则打开的是当前目录下的test.txt
fd = open(filename, O_CREAT | O_RDWR, S_IRWXU); // 打开文件
if (fd == -1)
printf("fail to pen file %s,fd:%d\n", filename, fd);
else
printf("Open file %s successfully,fd:%d\n", filename, fd);
close(fd);
return 0;
}
(2)上传test.cpp到Linux,在终端下输入命令g++ -o test test.cpp,然后运行test,运行结果如下:
[root@localhost cpp98]# g++ -o test test.cpp
[root@localhost cpp98]# ./test
Open file test.txt successfully,fd:3
文件的读取和写入示例,请打开如下链接阅读:
Linux C/C++编程-文件的读取与写入示例-CSDN博客