目录

一、文件创建(creat 系统调用)​

1.1 函数原型

1.2 参数说明​

1.3 返回值​

1.4 使用示例

二、文件打开(open 系统调用)​

2.1 函数原型

2.2 参数说明​

2.3 返回值​

2.4 使用示例

三、文件读写(read 和 write 系统调用)​

3.1 read 系统调用​

3.2 write 系统调用​

3.3 使用示例

四、文件定位(lseek 系统调用)​

4.1 函数原型

4.2 参数说明​

4.3 返回值​

4.4 使用示例

五、文件关闭(close 系统调用)​

5.1 函数原型

5.2 参数说明​

5.3 返回值​

5.4 注意事项​

5.5 使用示例

六、总结与


在 Linux 系统中,文件操作是非常核心且基础的功能。无论是应用程序的开发,还是对系统的日常管理,都离不开对文件的创建、打开、读写、定位和关闭等操作。而这些操作的底层实现,很大程度上依赖于系统调用。本文将详细介绍 Linux 文件操作中涉及的主要系统调用,深入理解 Linux 文件操作的原理和实现方式。​


一、文件创建(creat 系统调用)​

在 Linux 中,创建一个新文件可以使用 creat 系统调用。它的主要功能是创建一个新的空文件,如果指定的文件已经存在,则会将其截断为零长度(即清空文件内容)。​

1.1 函数原型

#include <fcntl.h>
int creat(const char *pathname, mode_t mode);

1.2 参数说明​

  • pathname:指向要创建的文件路径名的字符串指针。可以是绝对路径,也可以是相对路径。​
  • mode:指定新文件的权限模式。它由一系列权限位组成,这些权限位决定了文件所有者、所属组和其他用户对该文件的访问权限。常见的权限位有:​
    • S_IRUSR:所有者具有读权限(0400)​
    • S_IWUSR:所有者具有写权限(0200)​
    • S_IXUSR:所有者具有执行权限(0100)​
    • S_IRGRP:所属组具有读权限(0040)​
    • S_IWGRP:所属组具有写权限(0020)​
    • S_IXGRP:所属组具有执行权限(0010)​
    • S_IROTH:其他用户具有读权限(0004)​
    • S_IWOTH:其他用户具有写权限(0002)​
    • S_IXOTH:其他用户具有执行权限(0001)​

这些权限位可以通过按位或(|)运算组合使用,例如,S_IRUSR | S_IWUSR 表示所有者具有读写权限。​

1.3 返回值​

  • 成功:返回一个非负的文件描述符(file descriptor),该文件描述符用于后续对文件的操作。​
  • 失败:返回 - 1,并设置 errno 来指示错误类型。常见的错误有:​
  • EEXIST:指定的文件已经存在,且没有被截断(当使用 O_CREAT | O_EXCL 标志时,如果文件存在则会返回该错误,但 creat 系统调用本身如果文件存在会截断文件,所以此错误在 creat 中较少见)​
  • ENOENT:路径名中的目录不存在​
  • EACCES:没有权限创建文件或访问路径中的目录​
  • ENOSPC:文件系统没有足够的空间创建新文件​

1.4 使用示例

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>int main() {int fd;// 创建一个名为"testfile.txt"的文件,所有者具有读写权限,所属组和其他用户无权限fd = creat("testfile.txt", S_IRUSR | S_IWUSR);if (fd == -1) {perror("creat failed");exit(EXIT_FAILURE);}printf("File created successfully with file descriptor: %d\n", fd);close(fd); // 创建文件后要记得关闭文件描述符return 0;
}

    使用 creat 函数创建了一个名为 “testfile.txt” 的文件,设置所有者具有读写权限。如果创建成功,会输出文件描述符;如果失败,会通过 perror 函数打印错误信息。​

    二、文件打开(open 系统调用)​

    open 系统调用是 Linux 中用于打开一个已存在的文件或创建一个新文件的主要系统调用。它比 creat 系统调用功能更强大,可以通过不同的标志组合实现多种操作。​

    2.1 函数原型

    #include <fcntl.h>
    int open(const char *pathname, int flags);
    int open(const char *pathname, int flags, mode_t mode);

    2.2 参数说明​

    pathname:与 creat 系统调用中的 pathname 参数相同,指向要打开或创建的文件路径名。​

    flags:用于指定打开文件的方式和行为,是一个整数,可以由多个标志按位或组合而成。常见的标志有:​

    • O_RDONLY:以只读方式打开文件​
    • O_WRONLY:以只写方式打开文件​
    • O_RDWR:以读写方式打开文件​
    • O_CREAT:如果指定的文件不存在,则创建该文件。此时需要提供第三个参数 mode 来指定新文件的权限。​
    • O_EXCL:与 O_CREAT 一起使用,如果文件已经存在,则 open 调用失败(返回 - 1),可以用于防止覆盖已存在的文件。​
    • O_TRUNC:如果文件已经存在且以可写方式打开(O_WRONLY 或 O_RDWR),则将文件截断为零长度。​
    • O_APPEND:以追加方式打开文件,每次写操作都将数据添加到文件的末尾。​

    mode:当 flags 中包含 O_CREAT 标志时,该参数用于指定新文件的权限模式,与 creat 系统调用中的 mode 参数相同。如果 flags 中不包含 O_CREAT,则该参数被忽略。​

    2.3 返回值​

    • 成功:返回一个非负的文件描述符,用于后续对文件的操作。​
    • 失败:返回 - 1,并设置 errno 指示错误类型。常见的错误与 creat 系统调用类似,此外还有:​
      • EINVAL:flags 参数无效​
      • EMFILE:进程已打开的文件描述符达到上限​

    2.4 使用示例

    #include <stdio.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <unistd.h>int main() {int fd1, fd2, fd3;// 以只读方式打开已存在的文件"testfile.txt"fd1 = open("testfile.txt", O_RDONLY);if (fd1 == -1) {perror("open for read failed");exit(EXIT_FAILURE);}// 以读写方式打开文件,如果文件不存在则创建,权限为所有者读写,组和其他用户只读fd2 = open("newfile.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);if (fd2 == -1) {perror("open for read-write and create failed");close(fd1);exit(EXIT_FAILURE);}// 以只写、追加方式打开文件,若文件不存在则创建fd3 = open("logfile.txt", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);if (fd3 == -1) {perror("open for write and append failed");close(fd1);close(fd2);exit(EXIT_FAILURE);}printf("fd1: %d, fd2: %d, fd3: %d\n", fd1, fd2, fd3);// 关闭文件描述符close(fd1);close(fd2);close(fd3);return 0;
    }

    展示了 open 系统调用的几种常见用法:只读打开已存在文件、读写打开并创建新文件、只写追加打开并创建新文件。​

    三、文件读写(read 和 write 系统调用)​

    打开文件后,就可以进行读写操作了。Linux 提供了 read 和 write 系统调用来实现对文件的读写。​

    3.1 read 系统调用​

    read 系统调用用于从已打开的文件中读取数据。​

    ①函数原型

    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);

    ②参数说明​

    • fd:文件描述符,即 open 或 creat 系统调用返回的非负整数,标识要读取的文件。​
    • buf:指向一个缓冲区的指针,用于存储读取到的数据。​
    • count:指定要读取的字节数。​

    ③ 返回值​

    • 成功:返回实际读取到的字节数。如果已经到达文件末尾,则返回 0。​
    • 失败:返回 - 1,并设置 errno 指示错误类型,如 EBADF(文件描述符无效)、EIO(I/O 错误)等。​

    3.2 write 系统调用​

    write 系统调用用于向已打开的文件中写入数据。​

    ①函数原型

    #include <unistd.h>
    ssize_t write(int fd, const void *buf, size_t count);

    ②参数说明​

    • fd:文件描述符,标识要写入的文件。​
    • buf:指向一个缓冲区的指针,该缓冲区中存储了要写入的数据。​
    • count:指定要写入的字节数。​

    ③返回值​

    • 成功:返回实际写入的字节数。注意,实际写入的字节数可能小于 count,这并不一定表示错误,可能是由于各种原因(如磁盘空间不足、信号中断等)导致的。​
    • 失败:返回 - 1,并设置 errno 指示错误类型,如 EBADF(文件描述符无效或不具有写权限)、EIO(I/O 错误)等。​

    3.3 使用示例

    #include <stdio.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>int main() {int fd;char write_buf[] = "Hello, Linux File Operation!";char read_buf[1024];ssize_t nwritten, nread;// 以读写方式打开文件,不存在则创建fd = open("rwtest.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);if (fd == -1) {perror("open failed");exit(EXIT_FAILURE);}// 写入数据nwritten = write(fd, write_buf, strlen(write_buf));if (nwritten == -1) {perror("write failed");close(fd);exit(EXIT_FAILURE);}printf("Wrote %zd bytes: %s\n", nwritten, write_buf);// 将文件指针移到文件开头(否则读取不到刚写入的数据)off_t offset = lseek(fd, 0, SEEK_SET);if (offset == -1) {perror("lseek failed");close(fd);exit(EXIT_FAILURE);}// 读取数据nread = read(fd, read_buf, sizeof(read_buf) - 1); // 留一个字节给'\0'if (nread == -1) {perror("read failed");close(fd);exit(EXIT_FAILURE);} else if (nread == 0) {printf("Reached end of file\n");} else {read_buf[nread] = '\0'; // 加上字符串结束符printf("Read %zd bytes: %s\n", nread, read_buf);}close(fd);return 0;
    }

    先向文件写入一段字符串,然后使用 lseek 系统调用将文件指针移到文件开头,再读取文件内容并打印。需要注意的是,write 调用返回的实际写入字节数可能小于请求的字节数,因此在实际应用中可能需要循环写入,直到所有数据都被写入。同样,read 调用也可能需要循环读取,直到读取到预期的数据量或到达文件末尾。​

    四、文件定位(lseek 系统调用)​

    在对文件进行读写操作时,系统会维护一个文件偏移量(file offset),也称为文件指针,它指示了下一次读写操作开始的位置。lseek 系统调用用于修改这个文件偏移量,实现对文件的随机访问。​

    4.1 函数原型

    #include <unistd.h>
    off_t lseek(int fd, off_t offset, int whence);

    4.2 参数说明​

    • fd:文件描述符,标识要操作的文件。​
    • offset:偏移量,是一个有符号整数,表示要移动的字节数。​
    • whence:用于指定偏移量的参考位置,有以下三种取值:​
      • SEEK_SET:将文件偏移量设置为 offset 字节(从文件开头开始计算)。​
      • SEEK_CUR:将文件偏移量设置为当前偏移量加上 offset 字节。​
      • SEEK_END:将文件偏移量设置为文件末尾加上 offset 字节(offset 为负时表示向文件开头方向移动)。​

    4.3 返回值​

    • 成功:返回新的文件偏移量(从文件开头开始计算的字节数)。​
    • 失败:返回 - 1,并设置 errno 指示错误类型,如 EBADF(文件描述符无效)、ESPIPE(文件是管道、FIFO 或套接字,这些文件不支持定位操作)等。​

    4.4 使用示例

    #include <stdio.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>int main() {int fd;char buf[100];off_t offset;// 创建并打开一个文件fd = open("seektest.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);if (fd == -1) {perror("open failed");exit(EXIT_FAILURE);}// 写入一些数据const char *data = "0123456789abcdefghijklmnopqrstuvwxyz";write(fd, data, strlen(data));// 将文件指针移到开头offset = lseek(fd, 0, SEEK_SET);if (offset == -1) {perror("lseek to beginning failed");close(fd);exit(EXIT_FAILURE);}printf("Moved to beginning, offset: %ld\n", (long)offset);// 读取5个字节ssize_t nread = read(fd, buf, 5);if (nread == -1) {perror("read failed");close(fd);exit(EXIT_FAILURE);}buf[nread] = '\0';printf("Read %zd bytes: %s\n", nread, buf);// 从当前位置向后移动10个字节offset = lseek(fd, 10, SEEK_CUR);if (offset == -1) {perror("lseek from current failed");close(fd);exit(EXIT_FAILURE);}printf("Moved 10 bytes from current, new offset: %ld\n", (long)offset);// 读取5个字节nread = read(fd, buf, 5);if (nread == -1) {perror("read failed");close(fd);exit(EXIT_FAILURE);}buf[nread] = '\0';printf("Read %zd bytes: %s\n", nread, buf);// 从文件末尾向前移动20个字节offset = lseek(fd, -20, SEEK_END);if (offset == -1) {perror("lseek from end failed");close(fd);exit(EXIT_FAILURE);}printf("Moved 20 bytes before end, new offset: %ld\n", (long)offset);// 读取5个字节nread = read(fd, buf, 5);if (nread == -1) {perror("read failed");close(fd);exit(EXIT_FAILURE);}buf[nread] = '\0';printf("Read %zd bytes: %s\n", nread, buf);close(fd);return 0;
    }

    展示了 lseek 系统调用的三种使用方式:从文件开头设置偏移量、从当前位置调整偏移量、从文件末尾调整偏移量。通过 lseek,我们可以灵活地定位到文件的任意位置进行读写操作,实现随机访问。​

    五、文件关闭(close 系统调用)​

    当对文件的操作完成后,需要使用 close 系统调用来关闭文件,释放与该文件相关的资源,如文件描述符等。​

    5.1 函数原型

    #include <unistd.h>
    int close(int fd);

    5.2 参数说明​

    • fd:要关闭的文件的文件描述符。​

    5.3 返回值​

    • 成功:返回 0。​
    • 失败:返回 - 1,并设置 errno 指示错误类型,如 EBADF(文件描述符无效或已经关闭)等。​

    5.4 注意事项​

    • 每个进程能打开的文件描述符数量是有限的,因此在使用完文件后,一定要及时调用 close 关闭文件,以释放文件描述符,避免资源耗尽。​
    • 关闭文件后,该文件描述符将不再有效,不能再用于对文件的读写等操作。​

    5.5 使用示例

    #include <stdio.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include <unistd.h>int main() {int fd;fd = open("closetest.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);if (fd == -1) {perror("open failed");exit(EXIT_FAILURE);}// 对文件进行一些操作...// 关闭文件if (close(fd) == -1) {perror("close failed");exit(EXIT_FAILURE);}printf("File closed successfully\n");return 0;
    }

    这个示例比较简单,展示了打开文件后进行一些操作,然后关闭文件的过程。在实际应用中,无论对文件的操作是否成功,都应该在适当的时候关闭文件。​

    六、总结与

    在实际使用这些系统调用时,需要注意以下几点:​

    • 始终检查系统调用的返回值,及时处理可能出现的错误。​
    • 注意文件权限的设置,确保文件的访问安全。​
    • 及时关闭不再使用的文件,释放系统资源。​
    • 对于读写操作,要考虑到实际读写的字节数可能小于请求的字节数,必要时进行循环操作。​

    随着 Linux 系统的不断发展,文件操作的方式和接口也在不断完善。但这些基础的系统调用仍然是理解 Linux 文件系统和进行底层开发的关键。未来,我们可以进一步学习 Linux 文件系统的底层原理,以及如何利用这些系统调用来实现更复杂的文件操作功能,如文件复制、移动、权限修改等。同时,也可以学习更高层次的文件操作库函数(如标准 C 库中的 fopen、fread、fwrite 等),它们是对这些系统调用的封装,使用起来更加方便,但了解其底层实现的系统调用有助于我们更好地理解和使用这些库函数。​

    通过不断学习和实践,我们可以更深入地掌握 Linux 文件操作技术,为开发高效、稳定的 Linux 应用程序打下坚实的基础。


    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
    如若转载,请注明出处:http://www.pswp.cn/pingmian/92642.shtml
    繁体地址,请注明出处:http://hk.pswp.cn/pingmian/92642.shtml
    英文地址,请注明出处:http://en.pswp.cn/pingmian/92642.shtml

    如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    FreeRTOS源码分析六:vTaskDelay vs xTaskDelayUntil任务延时

    系列文章目录 FreeRTOS源码分析一&#xff1a;task创建&#xff08;RISCV架构&#xff09; FreeRTOS源码分析二&#xff1a;task启动&#xff08;RISCV架构&#xff09; FreeRTOS源码分析三&#xff1a;列表数据结构 FreeRTOS源码分析四&#xff1a;时钟中断处理响应流程 Free…

    Linux学习-应用软件编程(fread/fwrite,流定义相关接口)

    freadsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 功能按块从文件读取数据&#xff0c;从文件中读 nmemb 个、每个 size 字节的元素&#xff0c;存入 ptr 指向的内存。参数- ptr &#xff1a;存储读取数据的内存首地址&#xff08;需提前分配足够…

    IP分片(IP Fragmentation)

    目录 一、核心概念:MTU与分片的必要性 二、IP分片的关键字段(IPv4头部) 三、分片与重组流程 1. 分片过程(发送端或中间路由器) 2. 重组过程(接收端) 四、IPv4与IPv6分片的差异 五、分片的潜在问题与风险 六、总结 一、传输效率降低,带宽开销增加 二、可靠性降低,数据丢…

    高并发内存池 内存释放回收(6)

    文章目录前言一、threadcache回收内存二、centralcache回收内存三、pagecache回收内存总结前言 Hello&#xff0c;我们继续乘胜追击   本篇难度较大&#xff0c;大家要好好学一下 一、threadcache回收内存 当某个线程申请的对象不用了&#xff0c;可以将其释放给 thread cac…

    2438. 二的幂数组中查询范围内的乘积

    2438. 二的幂数组中查询范围内的乘积 初始理解题目 首先&#xff0c;我们需要清楚地理解题目在说什么。题目给出一个正整数 n&#xff0c;要求我们构造一个数组 powers&#xff0c;这个数组满足以下条件&#xff1a; 元素性质​&#xff1a;数组中的每个元素都是 2 的幂。即…

    【PyTorch学习笔记 - 01】 Tensors(张量)

    最近项目需要优化一下目标检测网络&#xff0c;在这个过程中发现还是得增加对框架底层的掌握才可行。于是准备对pytorch的一些基本概念做一些再理解。参考PyTorch的wiki&#xff0c;对自己的学习过程做个记录。 Tensors 是一种特殊的数据结构&#xff0c;与数组和矩阵非常相似…

    【C/C++】(struct test*)0->b 讲解

    提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、什么是结构体成员的偏移量&#xff1f; 二、为什么需要计算偏移量&#xff1f; 三、如何计算偏移量&#xff1f; 四、总结 一、什么是结构体成员的偏移量&#…

    使用Pytest进行接口自动化测试(三)

    &#xff08;一&#xff09;YAML 之前在项目中&#xff0c;我们也是用过YAML来做配置文件&#xff0c;他用于以人类可读的形式存储信息&#xff0c; 特点: 一种简易的可读语言&#xff0c;用于人和计算机交换数据 通常用来存储配置信息 跟python类似&…

    算法训练营day46 647. 回文子串、516.最长回文子序列、动态规划总结篇

    今天是动态规划的最后一篇内容了&#xff0c;本篇主要是针对回文字符串这种“与众不同”的递推规律来进行讲解 647. 回文子串 统计并返回这个字符串中 回文子串 的数目 暴力解法 两层for循环&#xff0c;遍历区间起始位置和终止位置&#xff0c;然后还需要一层遍历判断这个区…

    Qt界面优化

    1.QSS在网页前端开发领域中&#xff0c;CSS 是一个至关重要的部分&#xff0c;描述了一个网页的 “样式”&#xff0c;从而起到对网页美化的作用。所谓样式&#xff0c;包括不限于大小、位置、颜色、背景、间距、字体等等。网页开发作为 GUI 的典型代表&#xff0c;也对于其他客…

    week1+2+3

    408 计组 1.基本组成2.数据的表示和运算定点数&#xff1a;把数字分为定点整数和定点小数分开存储 浮点数&#xff1a;用科学计数法存储 原码 -全部取反-> 反码 反码 1->补码 补码 -符号位取反->移码带余除法&#xff1a;设x,m∈Z&#xff0c;m>0则存在唯一的整数q…

    java8中javafx包缺少报错

    今天拉取一个jdk1.8的项目里面有一个代码用到了javafx&#xff0c;这个我记得是jdk中的包&#xff0c;正常不应该报错的。然后发现jdk中还真没有&#xff0c;查了一下是因为版本问题。 Java 8 及之前&#xff1a;Oracle JDK 自带 JavaFX&#xff0c;OpenJDK 通常不包含Java 9 …

    day072-代码检查工具-Sonar与maven私服-Nexus

    文章目录0. 老男孩思想-选对池塘钓美人鱼1. 代码回滚方案2. SonarQube2.1 代码检查工具2.2 部署sonarqube2.2.1 软件要求2.2.2 安装软件2.2.3 启动sonar2.2.4 部署插件2.3 sonar检查java代码2.3.1 创建sona项目2.3.2 分析java代码2.3.3 Jenkins结合sonar检查代码2.4 sonar检查非…

    【前端基础】15、列表元素、表格元素、表单元素(注:极其粗略的记载。)

    一、列表元素 1、什么是列表元素2、有序列表&#xff08;ol、li&#xff09; ol有序列表 直接子元素只能是li。 li列表中的每一项。3、无序列表&#xff08;ul、li&#xff09; ol无序列表 直接子元素只能是li。 li列表中的每一项。4、定义列表&#xff08;dl、dt、dd&#xff…

    IRFBG30PBF Vishay威世MOSFET场效应管

    IRFBG30PBF Vishay威世&#xff1a;超快MOSFET 场效应管一、产品定位IRFBG30PBF 是Vishay威世推出的600V/30A N沟道功率MOSFET&#xff0c;采用第五代TrenchFET技术&#xff0c;专为开关电源、电机驱动、新能源逆变器等高功率场景设计。以85mΩ超低导通电阻和超快反向恢复&…

    【07-AGI的讨论】

    AI ANI&#xff1a;artificial narrow intelligence; 如 智能音箱&#xff1b;自动驾驶汽车&#xff0c;网络搜索&#xff0c;其他用于专业特定事项的工具&#xff1b; AGI&#xff1a;artificial general intelligence; building AI systems that could do anything a typical…

    [激光原理与应用-225]:机械 - 3D图与2D图各自的作用

    在机械设计与加工领域&#xff0c;3D图和2D图是两种核心的工程表达方式&#xff0c;它们在产品设计、制造、装配及维护等环节中扮演不同角色&#xff0c;具有互补性。以下是它们各自的作用及具体应用场景的详细解析&#xff1a;一、3D图的作用1. 直观展示产品全貌三维可视化&am…

    【从零开始java学习|第一篇】java中的名词概念(JDK、JVM、JRE等等)

    目录 一、核心运行环境三要素&#xff08;JVM/JRE/JDK&#xff09; 二、常用开发指令&#xff08;JDK 自带工具&#xff09; 三、一些其他概念 四、总结核心逻辑链 要入门 Java&#xff0c;理解核心概念之间的关系是基础。以下是 Java 中最核心的基础概念、工具及相关名词的…

    UVa12345 Dynamic len(set(a[L:R]))

    [TOC](UVa12345 Dynamic len(set(a[L:R]))) 题目链接 UVA - 12345 Dynamic len(set(a[L:R])) 题意 有编号从 0 到 n−1 的 n 个数&#xff0c;有两种操作&#xff1a; Q L R 询问编号 L 到编号 R−1 的数中有多少个不同的数字。M X Y 将编号为 X 的数字改为 Y。 你的任务就是…

    [Ubuntu] VNC连接Linux云服务器 | 实现GNOME图形化

    将桌面环境修改为 GNOME 并通过 VNC 远程访问的步骤 & TightVNC 的安装与配置说明&#xff1a;1. 安装 GNOME 桌面环境 sudo apt update sudo apt install ubuntu-gnome-desktop -y2. 安装 TightVNC 服务器 sudo apt install tightvncserver -y3. 初始化 VNC Server 并设置…