当前位置: 首页 > news >正文

Linux 入门七:从基础到进阶的文件操作

一、Linux 文件系统基础:一切皆文件的哲学

在 Linux 的世界里,“一切皆文件” 是核心设计哲学。无论是普通文件、目录、设备(如硬盘、串口),还是网络套接字,都被抽象为文件模型,通过统一的接口进行操作。这种设计让开发者能以一致的方式处理不同类型的资源。

1.1 文件类型详解

文件类型核心特性典型示例 / 路径
普通文件存储数据,分为文本文件(可读字符)和二进制文件(字节流数据)hello.txt(文本)、image.bin(二进制)
目录文件存储文件和子目录列表,通过 ls 命令查看内容/etc/home/user
设备文件- 字符设备:按字节读写(如键盘、串口)
- 块设备:按数据块读写(如硬盘)
/dev/ttyS0(串口)、/dev/sda(硬盘)
管道文件进程间通信通道,通过 mkfifo 创建,用于单向数据传输pipe_file
套接字文件网络通信抽象,常见于 /var/run 目录,用于进程间网络通信db.sock(数据库套接字)

1.2 核心文件操作分类

  1. 基础操作:打开 / 关闭文件、读写数据(文件交互的入口与核心)
  2. 控制操作:权限管理、光标定位、文件状态查询(精细化管理文件属性)
  3. 高级操作:原子操作、文件锁定、IO 模型配置(应对复杂场景的关键技术)

二、标准 C 库文件操作:缓冲 IO 的便捷之道

标准 C 库提供带缓冲机制的文件操作函数,适合处理文本和格式化数据,减少系统调用次数,提升 I/O 效率。

2.1 打开文件:fopen 家族

FILE *fopen(const char *path, const char *mode);          // 常规打开文件  
FILE *freopen(const char *path, const char *mode, FILE *stream); // 重定向标准流(如 stdin/stdout)  
FILE *fdopen(int fildes, const char *mode);               // 文件描述符转文件指针  
核心模式参数(快速查表)
模式读写权限创建 / 覆盖行为定位起点典型应用场景
r只读文件必须存在文件开头读取配置文件
w只写清空已存在文件 / 创建新文件文件开头初始化日志文件
a追加写文件不存在时创建文件末尾追加日志记录
r+读写文件必须存在文件开头读写配置文件
a+读写追加文件不存在时创建文件末尾读写日志文件

示例:安全打开文件并处理错误

#include <stdio.h>  
int main() {  FILE *fp = fopen("data.txt", "a+");  if (fp == NULL) {  perror("Failed to open file"); // 打印系统级错误信息(如权限不足)  return 1;  }  fclose(fp); // 及时关闭文件,释放资源  return 0;  
}  

2.2 读写操作:从基础到进阶

① 格式化读写(文本处理首选)
// 写入:将结构化数据按格式写入文件  
fprintf(fp, "Name: %s, Age: %d\n", "Alice", 30);  // 读取:按预设格式解析文件内容  
char name[20];  
int age;  
fscanf(fp, "Name: %s, Age: %d", name, &age); // 自动跳过空格和换行  
② 二进制读写(高效存储二进制数据)
struct Student {  char name[20];  int age;  
};  
struct Student stu = {"Bob", 25};  // 写入:直接存储结构体到文件  
fwrite(&stu, sizeof(struct Student), 1, fp);  // 读取:恢复二进制数据到结构体  
struct Student readStu;  
fread(&readStu, sizeof(struct Student), 1, fp);  
③ 单字符 / 字符串操作(细粒度数据处理)
int ch = fgetc(fp);         // 读取单个字符(返回 ASCII 值,失败时返回 EOF)  
fputc('A', fp);            // 写入单个字符  char buf[100];  
fgets(buf, 100, fp);       // 读取一行(含换行符,最多读取 size-1 个字符)  
fputs("Hello\n", fp);       // 写入字符串(不自动添加换行符,需手动添加)  

2.3 关键辅助函数(提升操作精度)

  • 文件结束检测feof(fp) 返回非零值时表示到达文件尾(需在读操作后调用,避免误判)
  • 光标定位
    fseek(fp, 0, SEEK_END); // 定位到文件末尾  
    long size = ftell(fp);   // 获取当前光标位置(即文件大小,单位:字节)  
    
  • 缓冲区控制fflush(fp) 强制刷新缓冲区(重要!避免程序崩溃导致数据未写入磁盘)

三、Linux 系统级文件操作:底层控制的力量

Linux 系统级文件操作通过内核提供的系统调用实现,直接操作文件描述符(File Descriptor),具有无缓冲、高性能的特点,适用于设备控制、底层资源管理等场景。

3.1 打开文件:open 函数深度解析

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

函数参数详解
参数说明
pathname要打开的文件路径(绝对路径或相对路径),如 "/etc/hosts" 或 "data.txt"
flags打开文件的模式和标志(必背核心参数,可通过按位或 `` 组合多个标志)。
mode仅在创建新文件(使用 O_CREAT 标志)时有效,指定文件权限(八进制,如 0666)。
核心 flags 参数分类(按功能分组)
一、基础打开模式(必选其一)
标志位功能示例
O_RDONLY以只读模式打开文件,文件必须存在。open("config.txt", O_RDONLY);
O_WRONLY以只写模式打开文件。`open("log.txt", O_WRONLYO_CREAT, 0644);`
O_RDWR以读写模式打开文件。open("temp.txt", O_RDWR);
二、创建与控制标志(可选组合)
标志位功能
O_CREAT若文件不存在则创建新文件。需配合 mode 参数设置权限(如 0666)。
O_EXCL与 O_CREAT 同时使用时,若文件已存在则打开失败(避免重复创建)。
O_TRUNC若文件已存在且以写模式打开(O_WRONLY/O_RDWR),则清空文件内容。
O_APPEND以追加模式打开文件,每次写入时自动定位到文件末尾(不覆盖原有内容)。
三、特殊模式(设备文件 / 管道专用)
标志位功能
O_NONBLOCK非阻塞模式,用于设备文件(如串口、管道)。无数据时立即返回,不阻塞进程。
权限计算:mode & ~umask
  • mode:用户指定的文件权限(八进制,如 0666 表示所有者 / 组 / 其他用户均可读可写)。
  • umask:系统默认权限掩码(通过 umask 命令查看,默认值通常为 0022),用于屏蔽某些权限。
  • 实际权限 = mode 按位与 umask 的取反值。
    // 示例:创建文件并设置权限  
    int fd = open("user.txt", O_CREAT | O_WRONLY, 0666);  
    // 若 umask=0002,实际权限为 0666 & ~0002 = 0664(所有者/组可读可写,其他用户可读)  
    

3.2 读写操作:直接操作文件描述符

基础读写函数
#include <unistd.h>  
ssize_t read(int fd, void *buf, size_t count);   // 从文件读取数据  
ssize_t write(int fd, const void *buf, size_t count); // 向文件写入数据  
参数详解
函数参数说明
readfd文件描述符(通过 open 函数返回)。
buf用于存储读取数据的缓冲区(指针)。
count期望读取的字节数。成功时返回实际读取的字节数(0 表示文件末尾),失败返回 -1
writefd文件描述符(需以写模式打开)。
buf包含要写入数据的缓冲区(指针)。
count期望写入的字节数。成功时返回实际写入的字节数,失败返回 -1
示例:文件复制(系统调用版)
#include <fcntl.h>  
int main() {  int src_fd = open("source.txt", O_RDONLY);       // 只读打开源文件(fd=3)  int dest_fd = open("dest.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); // 创建目标文件  char buf[4096];  ssize_t n;  while ((n = read(src_fd, buf, sizeof(buf))) > 0) { // 循环读取,直到返回 0(文件末尾)  write(dest_fd, buf, n); // 将读取的数据写入目标文件  }  close(src_fd); // 关闭文件描述符,释放系统资源  close(dest_fd);  return 0;  
}  

3.3 文件描述符:0、1、2 的特殊意义

Linux 系统为每个进程预定义了三个标准文件描述符,用于输入输出操作:

描述符宏定义默认设备功能典型用法
0STDIN_FILENO键盘(标准输入)接收用户输入数据scanf("%d", &num);(底层调用 read(0, ...)
1STDOUT_FILENO屏幕(标准输出)输出程序结果printf("Hello\n");(底层调用 write(1, ...)
2STDERR_FILENO屏幕(标准错误)输出错误或警告信息perror("Error");(底层调用 write(2, ...)
重定向示例:将错误输出到文件
#include <stdio.h>  
int main() {  freopen("error.log", "w", stderr); // 将标准错误流(2)重定向到文件  fprintf(stderr, "ERROR: Invalid file path at line %d\n", __LINE__);  // 错误信息不再显示在屏幕,而是写入 error.log  return 0;  
}  

3.4 高级操作:光标定位与状态查询

3.4.1 光标控制:lseek 函数
#include <unistd.h>  
off_t lseek(int fd, off_t offset, int whence);  
参数详解
参数说明
fd文件描述符(需以读 / 写模式打开)。
offset偏移量(字节数),可正(向后)可负(向前)。
whence偏移起点(必背常量):
SEEK_SET(文件开头)、SEEK_CUR(当前位置)、SEEK_END(文件末尾)。
典型用法示例
场景代码效果
定位到文件开头lseek(fd, 0, SEEK_SET);光标移动到第 1 字节(偏移量 0)
从当前位置后移 10 字节lseek(fd, 10, SEEK_CUR);光标在当前位置基础上增加 10 字节
获取文件大小off_t size = lseek(fd, 0, SEEK_END);size 存储文件总字节数
回退 5 字节lseek(fd, -5, SEEK_CUR);光标从当前位置向前移动 5 字节
3.4.2 文件状态获取:stat 家族函数
#include <sys/stat.h>  
int stat(const char *path, struct stat *buf);       // 通过路径获取文件状态  
int fstat(int fd, struct stat *buf);             // 通过文件描述符获取文件状态  
int lstat(const char *path, struct stat *buf);   // 获取符号链接本身的状态(而非指向的文件)  
struct stat 关键成员
成员说明
st_mode文件类型 + 权限(通过宏判断,如 S_ISREG() 判断普通文件,S_IRUSR 表示所有者读权限)。
st_size文件大小(字节数,仅对普通文件有效,设备文件返回 0)。
st_mtime最后修改时间(time_t 类型时间戳,可通过 localtime() 转换为可读格式)。
示例:打印文件权限与大小
struct stat file_stat;  
if (stat("data.txt", &file_stat) == 0) {  printf("文件权限(八进制):%o\n", file_stat.st_mode & 0777); // 提取权限(去掉文件类型标志)  printf("文件大小:%ld 字节\n", file_stat.st_size);  
}  

知识总结:系统级文件操作核心脉络

  1. 打开文件:通过 open 函数设置模式(如 O_RDWR)和权限(结合 umask 计算实际权限)。
  2. 读写数据:使用 read/write 直接操作文件描述符,适合高性能场景(如大文件复制)。
  3. 特殊描述符:掌握 0(输入)、1(输出)、2(错误)的用途,学会重定向标准流。
  4. 高级控制
    • lseek 实现光标精准定位(开头、当前位置、末尾偏移)。
    • stat 家族函数获取文件详细信息(类型、权限、大小、时间等)。

通过系统调用,开发者可直接操控文件底层行为,满足高性能、高可靠性场景需求。后续可结合标准 IO 库(如 fopen/fread),在不同场景下灵活组合使用,提升开发效率。

四、目录与文件管理:系统运维必备技能

4.1 目录操作:创建、删除、遍历

核心函数与参数
#include <sys/stat.h>  
#include <dirent.h>  
1. 创建目录:mkdir
int mkdir(const char *pathname, mode_t mode);  
  • 参数
    • pathname:目录路径(如 "./new_dir")。
    • mode:目录权限(八进制,如 0755 表示所有者可读可写可执行,组 / 其他用户可读可执行)。
  • 示例
    if (mkdir("project", 0755) == -1) {  perror("mkdir failed"); // 失败原因可能是路径已存在或权限不足  
    }  
    
2. 删除空目录:rmdir
int rmdir(const char *pathname);  

  • 限制:只能删除空目录,非空目录需先删除内部文件(可通过 rm -r 命令实现,但编程需递归删除)。
  • 示例
    if (rmdir("empty_dir") == -1) {  perror("rmdir failed"); // 错误码 `ENOTEMPTY` 表示目录非空  
    }  
    
3. 遍历目录:opendir + readdir
DIR *opendir(const char *pathname);          // 打开目录,返回目录流指针  
struct dirent *readdir(DIR *dirp);            // 读取目录项,返回 `struct dirent`  
void closedir(DIR *dirp);                    // 关闭目录流  

  • struct dirent 成员
    • d_name:文件名(包含 . 表示当前目录,.. 表示上级目录)。
  • 示例
    DIR *dir = opendir(".");  
    struct dirent *entry;  
    while ((entry = readdir(dir)) != NULL) {  if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {  continue; // 跳过当前和上级目录  }  printf("文件/目录:%s\n", entry->d_name);  
    }  
    closedir(dir); // 必须关闭目录流,避免资源泄漏  
    

4.2 文件管理:重命名、删除、权限修改

1. 重命名文件 / 目录:rename
int rename(const char *oldpath, const char *newpath);  

  • 参数
    • oldpath:原路径(如 "old.txt")。
    • newpath:新路径(如 "new.txt" 或 "./subdir/new.txt")。
  • 示例
    if (rename("draft.txt", "final.txt") == -1) {  perror("rename failed"); // 失败原因可能是路径不存在或权限不足  
    }  
    
2. 删除文件:unlink
int unlink(const char *pathname);  

  • 注意:仅能删除文件,删除目录需用 rmdir(且目录为空)。
  • 示例
    if (unlink("temp.log") == -1) {  perror("unlink failed"); // 错误码 `ENOENT` 表示文件不存在  
    }  
    
3. 修改权限:chmod
int chmod(const char *pathname, mode_t mode);  

  • 参数
    • pathname:文件 / 目录路径。
    • mode:权限值(可通过宏组合,如 S_IRUSR | S_IWUSR 表示所有者读写)。
  • 权限宏定义
    • 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,其他用户执行)。
  • 示例
    // 设置文件为所有者读写,组和其他用户只读(0644)  
    chmod("data.txt", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);  
    

知识总结:系统级操作核心脉络

  1. 文件操作
    • open 函数通过 flags 组合实现多样打开模式,权限计算需考虑 umask 影响。
    • read/write 直接操作描述符,适合大文件高效读写;lseek 实现光标精准定位。
  2. 目录与文件管理
    • 目录操作需区分空目录删除(rmdir)和非空处理,遍历目录时注意过滤 . 和 ..
    • 权限修改通过 chmod 结合宏定义实现细粒度控制,rename/unlink 用于文件重命名和删除。

通过掌握系统级文件操作,开发者可深入底层控制文件行为,为嵌入式开发、系统编程等场景打下坚实基础。实际开发中,建议结合标准 IO 库(如 fopen)和系统调用,平衡效率与便捷性。

五、进阶操作:应对复杂场景的关键技术

5.1 改变文件大小:ftruncate 函数

#include <unistd.h>  
int ftruncate(int fd, off_t length);  

函数参数
参数说明
fd已打开的文件描述符(必须以 写入模式 打开,如 O_WRONLY 或 O_RDWR)。
length目标文件大小(字节数),用于扩展或截断文件。
核心功能
  • 文件截断:若原文件大小 > length,超出部分被删除(数据永久丢失,谨慎使用)。
  • 文件扩展:若原文件大小 < length,文件被扩展至 length 字节,中间区域填充 0(形成文件空洞)。
示例:创建 1MB 空文件
int fd = open("large_file.dat", O_WRONLY | O_CREAT, 0644); // 创建文件并以只写模式打开  
if (fd == -1) {  perror("open failed");  return -1;  
}  
ftruncate(fd, 1024 * 1024); // 设置文件大小为 1MB(1048576 字节)  
close(fd); // 关闭文件描述符  

5.2 原子操作:pread/pwrite 函数

#include <unistd.h>  
ssize_t pread(int fd, void *buf, size_t count, off_t offset);  // 原子读  
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); // 原子写  
函数参数
参数说明
fd文件描述符(需以读 / 写模式打开)。
buf读写缓冲区(读时存储数据,写时提供数据)。
count读写的字节数。
offset相对于文件开头的偏移量(字节数),读写操作从该位置开始,不改变文件指针位置。
核心优势
  • 无需手动定位:直接指定偏移量,无需先调用 lseek,避免多线程 / 进程场景下的指针竞争。
  • 原子性保证:操作期间文件指针保持不变,确保数据一致性(尤其适合多进程并发读写同一文件不同区域)。
示例:精准写入文件中间位置
int fd = open("data.bin", O_RDWR); // 以读写模式打开二进制文件  
if (fd == -1) {  perror("open failed");  return -1;  
}  
pwrite(fd, "update", 6, 100); // 在第 100 字节处写入 "update",不影响当前文件指针  
close(fd);  

5.3 文件描述符深度解析

① 本质与特性
  • 定义:文件描述符是进程打开文件的 非负整数句柄(范围 0~1023,默认每个进程最多打开 1024 个文件)。
  • 底层机制:系统为每个进程维护 文件描述符表,记录打开文件的状态(如光标位置、权限、文件类型等)。
  • 特殊值
    • 0STDIN_FILENO):标准输入(默认键盘)。
    • 1STDOUT_FILENO):标准输出(默认屏幕)。
    • 2STDERR_FILENO):标准错误(默认屏幕)。
② 描述符复制:dup/dup2
int dup(int oldfd); // 自动分配最小可用描述符,与 `oldfd` 指向同一文件  
int dup2(int oldfd, int newfd); // 指定新描述符(若 `newfd` 已打开则先关闭)  

函数区别典型场景
dup系统自动分配未使用的最小描述符(如 oldfd=3,返回 4)。透明复制描述符,无需指定具体数值。
dup2手动指定 newfd,若 newfd 已占用则先关闭,再指向 oldfd重定向标准流(如将 stdout 指向文件)。
典型应用:重定向标准输出到文件
int log_fd = open("output.log", O_WRONLY | O_CREAT | O_TRUNC, 0644);  
if (log_fd == -1) {  perror("open log failed");  return -1;  
}  
dup2(log_fd, 1); // 将标准输出(1)重定向到 log_fd,后续 `printf` 输出到文件  
printf("This message is written to output.log\n");  
close(log_fd);  

5.4 文件锁定:fcntl 函数实现进程间同步

#include <fcntl.h>  
struct flock {  short l_type;   // 锁类型(`F_RDLCK` 读锁、`F_WRLCK` 写锁、`F_UNLCK` 解锁)  short l_whence; // 偏移起点(`SEEK_SET`/`SEEK_CUR`/`SEEK_END`)  off_t l_start;  // 锁定区域起始位置(0 表示文件开头)  off_t l_len;    // 锁定区域长度(0 表示整个文件)  pid_t l_pid;    // 持有锁的进程 ID(仅 `F_GETLK` 时返回)  
};  
int fcntl(int fd, int cmd, struct flock *lock);  
核心命令(cmd 参数)
命令功能
F_SETLK设置锁状态(阻塞模式:无冲突则加锁,有冲突则返回 -1)。
F_GETLK检测锁冲突(返回第一个阻止当前锁的信息,无冲突时 l_type=F_UNLCK)。
操作流程(以写锁为例)
  1. 初始化锁结构体
    struct flock lock = {  .l_type = F_WRLCK,  // 写锁(独占锁,其他进程无法读写)  .l_whence = SEEK_SET,  .l_start = 0,       // 从文件开头锁定  .l_len = 0          // 锁定整个文件  
    };  
    
  2. 加锁
    if (fcntl(fd, F_SETLK, &lock) == -1) {  perror("lock failed"); // 失败原因:已有其他进程持有写锁  
    }  
    
  3. 解锁
    lock.l_type = F_UNLCK;  
    fcntl(fd, F_SETLK, &lock); // 释放锁  
    
注意事项
  • 锁类型:读锁(F_RDLCK)可共享,允许多进程同时读;写锁(F_WRLCK)互斥,仅允许单进程写。
  • 建议性锁:需所有进程配合检查锁状态,否则可能导致数据不一致(不阻止强制读写)。

5.5 设备控制:ioctl 函数(串口 / 硬件操作)

#include <sys/ioctl.h>  
int ioctl(int fd, int request, ...); // 第三个参数为可变参数,依赖设备类型  
典型场景:串口配置(设置 115200 波特率,8 数据位,无校验)
  1. 包含必要头文件
    #include <termios.h>  // 串口配置相关结构体  
    
  2. 获取当前配置
    struct termios options;  
    if (tcgetattr(fd, &options) == -1) {  perror("tcgetattr failed");  return -1;  
    }  
    
  3. 设置波特率
    cfsetispeed(&options, B115200); // 设置输入波特率  
    cfsetospeed(&options, B115200); // 设置输出波特率  
    
  4. 配置数据位与校验位
    options.c_cflag &= ~CSIZE;    // 清除数据位掩码  
    options.c_cflag |= CS8;       // 设置 8 数据位  
    options.c_cflag &= ~PARENB;   // 禁用奇偶校验(无校验位)  
    
  5. 激活配置
    if (tcsetattr(fd, TCSANOW, &options) == -1) {  perror("tcsetattr failed");  return -1;  
    }  
    

5.6 权限检测:access 函数

#include <unistd.h>  
int access(const char *pathname, int mode);  
mode 参数(可通过 | 组合多个标志)
宏定义检测类型返回值示例
F_OK文件是否存在0(存在),-1(不存在)if (access("config.ini", F_OK)) { /* 文件不存在 */ }
R_OK是否可读0(可读),-1(不可读)if (access("log.txt", R_OK)) { /* 无读权限 */ }
W_OK是否可写0(可写),-1(不可写)if (access("data.txt", W_OK)) { /* 无写权限 */ }
X_OK是否可执行0(可执行),-1(不可执行)if (access("/bin/bash", X_OK)) { /* 不可执行 */ }
示例:安全检查配置文件权限
if (access("config.ini", R_OK | W_OK) != 0) {  fprintf(stderr, "Error: Missing read/write permission for config.ini\n");  exit(1);  
}  

知识总结:进阶操作核心要点

  1. 文件大小控制ftruncate 用于精准调整文件大小,注意写入模式打开文件的必要性。
  2. 原子操作pread/pwrite 避免多进程场景下的文件指针混乱,确保数据读写原子性。
  3. 描述符技巧dup/dup2 实现描述符复制与重定向,灵活控制标准输入输出。
  4. 并发控制fcntl 文件锁区分读锁 / 写锁,确保多进程访问文件的一致性。
  5. 设备交互ioctl 结合 termios 结构体配置串口等设备,掌握波特率、数据位等参数设置。
  6. 权限检测access 函数快速校验文件访问权限,提升程序健壮性。

通过进阶操作的学习,开发者可应对复杂场景下的文件操作需求,从基础读写进阶到系统级控制,为高性能、高可靠性的程序开发奠定基础。

六、高级主题:IO 模型与时间处理

6.1 标准输入输出文件描述符

① 底层实现与缓冲区特性

Linux 进程启动时自动打开三个标准流,本质是文件描述符的高层封装,对应关系如下:

  • stdin(标准输入) → 文件描述符 0STDIN_FILENO
  • stdout(标准输出) → 文件描述符 1STDOUT_FILENO
  • stderr(标准错误) → 文件描述符 2STDERR_FILENO

核心特性

  • 缓冲区机制
    • stdout:默认行缓冲,数据会先存入缓冲区,遇到换行符或缓冲区满时才输出到屏幕(提升效率)。
    • stderr无缓冲,错误信息立即输出,确保关键信息不丢失(如 perror 直接调用 write(2, ...))。

底层等价关系

printf("hello") = fwrite("hello", 1, 5, stdout) = write(1, "hello", 5);  
scanf("%d", &num) = fscanf(stdin, "%d", &num) = read(0, buf, sizeof(buf)) + 解析逻辑;  
② 重定向实战:改变输入输出目标

通过 freopen 函数可将标准流重定向到文件,实现 “输入从文件读取” 或 “输出到文件存储”。

#include <stdio.h>  
int main() {  // ① 输入重定向:从文件读取数据(替代键盘输入)  freopen("input.dat", "r", stdin);  // 将标准输入重定向到 input.dat  int a, b;  scanf("%d %d", &a, &b);  // 实际从文件读取数据  // ② 错误重定向:将错误信息写入日志  freopen("error.log", "a", stderr);  // 追加模式打开日志文件  fprintf(stderr, "Error: Division by zero at line %d\n", __LINE__);  // 错误信息写入 error.log  return 0;  
}  

6.2 时间处理:从时间戳到可读格式

核心函数与结构体
#include <time.h>  
time_t time(NULL);          // 获取 Unix 时间戳(1970-01-01 至今的秒数)  
struct tm *gmtime(const time_t *timep); // 转换为 UTC 时间(格林威治时间,无时区偏移)  
struct tm *localtime(const time_t *timep); // 转换为本地时间(自动调整时区,如中国为 UTC+8)  
struct tm 成员解析(以 localtime 为例):
成员含义示例(2023-10-01 15:30:45)
tm_year年份(从 1900 开始,需 +1900)123 → 2023 年
tm_mon月份(0-11,需 +1)9 → 10 月
tm_mday日(1-31)1
tm_hour小时(0-23)15
tm_min分钟(0-59)30
tm_sec秒(0-59)45
示例:打印当前时间
int main() {  time_t now = time(NULL);  // 获取时间戳  struct tm *local = localtime(&now);  // 转换为本地时间  // 格式化为 "YYYY-MM-DD HH:MM:SS"  printf("Local Time: %d-%02d-%02d %02d:%02d:%02d\n",  local->tm_year + 1900,  // 年份修正  local->tm_mon + 1,       // 月份修正  local->tm_mday,  local->tm_hour,  local->tm_min,  local->tm_sec);  return 0;  
}  

6.3 IO 模型对比与 select 函数实战

四大 IO 模型核心特性
模型阻塞特性典型函数适用场景关键优势
阻塞 IO操作未完成时进程挂起read/write简单文件操作(如日志写入)代码逻辑简单,无需处理异步事件
非阻塞 IO立即返回,无数据时 errno=EAGAINopen(O_NONBLOCK)设备轮询(如串口实时数据读取)避免进程阻塞,适合实时性要求不高的轮询
多路转接同时监控多个描述符select/poll高并发服务器(处理多文件 / 套接字)单进程管理大量描述符,降低资源消耗
异步 IO内核完成后通知aio_read/aio_write大数据量非阻塞操作(如大文件传输)无需轮询,内核主动通知操作完成
select 函数详解
#include <sys/select.h>  
int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptionset, struct timeval *timeout);  

  • 参数

    • maxfd:监控的最大描述符 + 1(如监控 fd1=3, fd2=5,则 maxfd=6)。
    • readset/writeset/exceptionset:分别用于监控可读、可写、异常的描述符集合。
    • timeout:超时时间,NULL 表示永久阻塞,{0, 0} 表示立即返回。
  • 操作步骤

    1. 初始化集合
      fd_set read_fds;  
      FD_ZERO(&read_fds);  // 清空集合  
      FD_SET(fd1, &read_fds);  // 添加描述符 fd1 到读集合  
      FD_SET(fd2, &read_fds);  // 添加描述符 fd2 到读集合  
      
    2. 启动监控
      struct timeval timeout = {2, 0};  // 超时 2 秒  
      int ready = select(6, &read_fds, NULL, NULL, &timeout);  
      
    3. 处理就绪事件
      if (ready > 0) {  // 有描述符就绪  if (FD_ISSET(fd1, &read_fds)) handle_read(fd1);  // fd1 可读时处理  if (FD_ISSET(fd2, &read_fds)) handle_read(fd2);  // fd2 可读时处理  
      } else if (ready == 0) {  printf("Select timeout, no data ready\n");  // 超时无事件  
      } else {  perror("Select error");  // 错误处理  
      }  
      

6.4 串口编程基础(嵌入式开发核心)

① 串口设备文件路径
类型设备路径说明
传统串口/dev/ttyS0(COM1)、/dev/ttyS1(COM2)主板集成串口,常见于嵌入式设备
虚拟串口(终端)/dev/pts/0/dev/pts/1终端模拟器(如 xshell 生成的串口)
USB 转串口/dev/ttyUSB0/dev/ttyUSB1插入 USB 转串口设备后动态生成
② 配置步骤(9600 波特率,8 数据位,无校验)
  1. 打开串口(非阻塞模式)

    int fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);  
    if (fd == -1) {  perror("Failed to open serial port");  exit(1);  
    }  
    
     
    • O_NOCTTY:禁止串口成为控制终端(避免输入影响进程)。
    • O_NDELAY:非阻塞模式,无数据时立即返回。
  2. 获取当前配置

    struct termios options;  
    if (tcgetattr(fd, &options) == -1) {  perror("Failed to get serial options");  exit(1);  
    }  
    
  3. 设置核心参数

    // ① 波特率  
    cfsetispeed(&options, B9600);  // 输入波特率  
    cfsetospeed(&options, B9600);  // 输出波特率  // ② 数据位(8 位)  
    options.c_cflag &= ~CSIZE;  // 清除数据位掩码  
    options.c_cflag |= CS8;     // 设置 8 数据位  // ③ 停止位(1 位,默认值无需额外设置,清除 CSTOPB)  
    options.c_cflag &= ~CSTOPB;  // ④ 无校验位  
    options.c_cflag &= ~PARENB;  // 禁用奇偶校验  
    
  4. 激活配置(立即生效)

    if (tcsetattr(fd, TCSANOW, &options) == -1) {  perror("Failed to set serial options");  exit(1);  
    }  
    
  5. 读写操作

    // 读取数据(非阻塞模式,无数据时返回 -1,errno=EAGAIN)  
    char buf[1024];  
    ssize_t n = read(fd, buf, sizeof(buf));  
    if (n > 0) {  printf("Received: %s\n", buf);  
    }  // 发送数据(如 AT 命令控制串口设备)  
    const char *cmd = "AT\r\n";  
    write(fd, cmd, strlen(cmd));  
    

知识总结:高级主题核心要点

  1. 标准流重定向:利用 freopen 灵活改变输入输出目标,适用于日志记录、批量数据处理。
  2. 时间处理:掌握 time/gmtime/localtime 的配合使用,实现时间戳与可读格式的转换。
  3. IO 模型选择:根据场景选择阻塞 / 非阻塞模式,select 函数是多描述符监控的核心工具。
  4. 串口编程:熟悉设备路径、配置流程(波特率 / 数据位 / 停止位),是嵌入式开发与硬件交互的基础。

通过高级主题的学习,开发者可深入理解 Linux 文件操作的底层机制,应对复杂 IO 场景(如高并发、设备控制),为系统级编程和嵌入式开发提供支撑。

七、知识体系总结:从基础到实战的路线图

核心函数对比表

功能分类标准 IO 函数系统 IO 函数特殊用途函数
打开文件fopen/freopenopen/creatfdopen(描述符转文件指针)
读写文件fread/fwriteread/writepread/pwrite(原子操作)
文件定位fseek/ftelllseek-
文件控制fflush/fcloseclose/ftruncatefcntl(文件锁 / 状态控制)
目录操作-mkdir/rmdir/opendirstat/lstat(文件状态查询)
设备控制-ioctltermios(串口参数配置)

新手成长路线

  1. 基础篇:掌握 fopen/fread/fwrite,理解文件打开模式与缓冲区机制
  2. 系统篇:深入 open/read/write/lseek,掌握文件描述符与权限计算
  3. 进阶篇:学习文件锁(fcntl)、IO 模型(select)、串口配置(termios
  4. 实战篇:开发简易文件管理器、串口调试工具、多线程日志系统

关键提醒

  • 错误处理:所有文件操作函数需检查返回值(如 fopen 返回 NULLopen 返回 -1),并用 perror 打印具体错误
  • 资源释放:及时关闭文件(fclose/close)、释放目录流(closedir)、解锁(fcntl 解锁操作)
  • 场景选择:文本处理用标准 IO,设备控制 / 高性能场景用系统 IO,复杂并发场景结合 IO 模型优化

通过系统学习文件操作的全生命周期(创建、读写、控制、删除),结合底层系统调用与高层库函数的对比,开发者能全面掌握 Linux 文件操作的核心逻辑。记住:多写代码、多调试,逐步积累实战经验,是掌握这一核心技能的关键。

相关文章:

Linux 入门七:从基础到进阶的文件操作

一、Linux 文件系统基础&#xff1a;一切皆文件的哲学 在 Linux 的世界里&#xff0c;“一切皆文件” 是核心设计哲学。无论是普通文件、目录、设备&#xff08;如硬盘、串口&#xff09;&#xff0c;还是网络套接字&#xff0c;都被抽象为文件模型&#xff0c;通过统一的接口…...

DeepSeek的神经元革命:穿透搜索引擎算法的下一代内容基建

DeepSeek的神经元革命&#xff1a;穿透搜索引擎算法的下一代内容基建 ——从语义网络到价值共识的范式重构 一、搜索引擎的“内容饥渴症”与AI的基建使命 2024年Q1数据显示&#xff0c;百度索引网页总数突破3500亿&#xff0c;但用户点击集中在0.78%的高价值页面。这种“数据…...

【时时三省】(C语言基础)用switch语句实现多分支选择结构 例题

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 例题&#xff1a; 用switch语句处理菜单命令。在许多应用程序中&#xff0c;用菜单对流程进行控制&#xff0c;例如从键盘输入一个 A 或 a 字符&#xff0c;就会执行A操作&#xff0c;输入一…...

CMake macro

CMake中的macro主要用于在调用处直接展开代码&#xff0c;类似于文本替换&#xff0c;其作用类似于C语言的#define宏&#xff0c;但具备更复杂的结构。以下是详细分析&#xff1a; 1. macro的作用 代码展开&#xff1a;调用宏时&#xff0c;其内容会原地展开&#xff0c;如同…...

高防服务器防御DDoS全解析——从架构设计到实战对抗

本文系统阐述高防服务器对抗DDoS攻击的技术原理与实施路径&#xff0c;深度剖析BGP线路、流量清洗、协议栈优化等关键技术&#xff0c;结合2024年最新攻击案例与Gartner防御框架&#xff0c;提供企业级防御体系构建指南&#xff0c;涵盖硬件选型、策略配置、合规审计等全生命周…...

高防IP如何构筑DDoS防线?_解析抗攻击核心技术体系

本文深度解析高防IP防御DDoS攻击的技术实现路径&#xff0c;涵盖流量清洗机制、智能调度策略、混合防护架构三大核心技术体系。通过2023年某金融平台800Gbps混合攻击实战案例&#xff0c;结合Gartner最新防护成熟度模型&#xff0c;给出高防IP部署的六步实施框架与成本优化方案…...

RDD行动算子和累加器

RDD行动算子&#xff1a; 是能触发真正计算数据的算子 reduce:聚集RDD元素 collect:返回数据集所有元素 foreach:分布式遍历元素 count:返回元素个数: first:返回首个元素 take:返回前n个元素 takeOrdered:返回排序后的前n个元素 aggregate:分区和分区间数据聚合 fol…...

【计算机网络】同步操作 vs 异步操作:核心区别与实战场景解析

&#x1f4cc; 引言 在网络通信和分布式系统中&#xff0c;**同步&#xff08;Synchronous&#xff09;和异步&#xff08;Asynchronous&#xff09;**是两种基础却易混淆的操作模式。本文将通过代码示例、生活类比和对比表格&#xff0c;帮你彻底理解它们的区别与应用场景。 1…...

iframe学习与应用场景指南

一、iframe核心原理与学习路径 1. 嵌套网站的本质原理 技术特性&#xff1a; • 浏览器为每个iframe创建独立的window对象和DOM环境 • 资源独立加载&#xff1a;子页面拥有自己的CSS/JS/Cookie作用域 • 跨域限制&#xff1a;同源策略下无法直接访问DOM&#xff08;需CORS或…...

基于SSM的线上花店鲜花销售商城网站系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

【大模型理论篇】Search-R1: 通过强化学习训练LLM推理与利⽤搜索引擎

最近基于强化学习框架来实现大模型在推理和检索能力增强的项目很多&#xff0c;也是Deep Research技术持续演进的缩影。之前我们讨论过《R1-Searcher:通过强化学习激励llm的搜索能⼒》&#xff0c;今天我们分析下Search-R1【1】。 1. 研究背景与问题 ⼤模型&#xff08;LLM&a…...

错误码code:9568282 error: install releaseType target not same怎么处理?

目录 1.背景 2.解决方案 1.背景 当前是由于应用从4.1版本升级到5.0版本,然后安装应用会报错9568282 ,如果签名是一致的&#...

qt联动其他库实现一个客户端(本章主要是概述如何实现)

一.服务器功能 1.能连接多个客户端通信 2.负责统计与手机客户端的数据 3.遇到客户端请求数据时能检索数据库并发送对应数据 4.服务器需要能连接到公网 5.服务器需要有账号密码登录功能 6.服务器要有日志与管理员系统能统计信息 二.客户端 1.客户端需要有登录界面 2.客户端需要…...

爱普生FC1610AN5G手机中替代传统晶振的理想之选

在 5G 技术引领的通信新时代&#xff0c;手机性能面临前所未有的挑战与机遇。从高速数据传输到多任务高效处理&#xff0c;从长时间续航到紧凑轻薄设计&#xff0c;每一项提升都离不开内部精密组件的协同优化。晶振&#xff0c;作为为手机各系统提供稳定时钟信号的关键元件&…...

SpringMVC基础二(RestFul、接收数据、视图跳转)

ReauestMapping ReauestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上&#xff0c;用于类上&#xff0c;表示类中的所有响应请求的方法都是以该地址作为父路径。 创建一个新项目&#xff1a;设置为web项目 编写web.xml&#xff08;此配置也几…...

BERT - 段嵌入(Segment Embedding)

1. 段嵌入&#xff08;Segment Embedding&#xff09;的作用 在BERT模型中&#xff0c;段嵌入的主要作用是区分不同的句子。具体来说&#xff1a; 单句任务&#xff1a;所有位置的段嵌入都是0。 句子对任务&#xff1a;第一个句子的所有位置使用段嵌入0&#xff0c;第二个句子…...

Kaggle-Disaster Tweets-(二分类+NLP+模型融合)

Disaster Tweets 题意&#xff1a; 就是给出一个dataframe包含text这一列代表着文本&#xff0c;文本会有一些词&#xff0c;问对于每条记录中的text是真关于灾难的还是假关于灾难的。 比如我们说今天作业真多&#xff0c;这真是一场灾难。实际上这个灾难只是我们调侃而言的。…...

关于哈希冲突的讨论

文章目录 1. 什么是哈希冲突&#xff1f;2. 为什么会产生哈希冲突&#xff1f;3. 如何解决哈希冲突&#xff1f;4. 为什么哈希算法一定会产生冲突&#xff1f;5. 存在不发生冲突的哈希算法吗&#xff1f;6. 为什么不用无冲突的哈希算法&#xff08;如完美哈希&#xff09;&…...

傅利叶发布首款开源人形机器人N1:开发者可实现完整复刻

2025年4月11日&#xff0c;上海——通用机器人公司傅利叶正式发布首款开源人形机器人 Fourier N1&#xff0c;并同步开放涵盖物料清单、设计图纸、装配指南、基础操作软件在内的完整本体资源包。作为傅利叶 “Nexus 开源生态矩阵” 的首个落地项目&#xff08;“N1” 即 “Nexu…...

2020年INS SCI1区TOP:平衡复合运动优化算法BCMO,深度解析+性能实测

目录 1.摘要2.算法原理3.结果展示4.参考文献5.代码获取 1.摘要 元启发式算法因其强大的鲁棒性和简便的编程方式&#xff0c;在优化领域中发挥着重要作用。本文提出了一种基于平衡复合运动优化算法BCMO&#xff0c;其核心思想是在解空间中平衡个体的复合运动特性。通过概率选择…...

2022年全国职业院校技能大赛 高职组 “大数据技术与应用” 赛项赛卷(3卷)任务书

2022年全国职业院校技能大赛 高职组 “大数据技术与应用” 赛项赛卷&#xff08;3卷&#xff09;任务书 背景描述&#xff1a;模块A&#xff1a;大数据平台搭建&#xff08;容器环境&#xff09;&#xff08;15分&#xff09;任务一&#xff1a;Hadoop HA安装部署任务二&#x…...

Express中间件(Middleware)详解:从零开始掌握(4)

下面我将为你提供四个实战项目的完整实现代码&#xff0c;每个项目都展示了Express中间件的实际应用场景。 1. API网关实现 const express require(express); const rateLimit require(express-rate-limit); const helmet require(helmet); const morgan require(morgan)…...

Ubuntu22环境下,Docker部署阿里FunASR的gpu版本

番外: 随着deepseek的爆火,人工智能相关的开发变得异常火爆,相关的大模型开发很常见的agent智能体需要ASR语音识别的功能,阿里开源的FunASR几乎是把一个商业的项目放给我们使用了。那么我们项目中的生产环境怎么部署gpu版本的语音识别服务呢?经过跟deepseek的一上午的极限…...

vue springboot 案例 收集

vue springboot 案例 收集 SpringbootVue前后端分离项目-管理系统 https://blog.csdn.net/m0_56308072/article/details/130893828...

Windows环境下本地部署deepseek-r1或其他大模型 【保姆级教程】

目录 背景准备工作开始部署下载olloma安装olloma下载deepseek-r1模型使用如何使用 结束语 背景 最近deepseek本地部署的概念越来越火&#xff0c;勾起了我学习的兴趣。 我就在思考如何使用家用机或者平时打游戏的机器来本地部署deepseek&#xff0c;给自己开发个智能体来辅佐…...

ubuntu20.04系统安装apollo10.0系统

文章目录 前言一、安装基础软件1、更新相关软件2 安装 Docker Engine 二、获取 GPU 支持1、安装显卡驱动2、安装 Nvidia container toolkit 三、安装 Apollo 环境管理工具1、安装依赖软件2、在宿主机添加 Apollo 软件源的 gpg key&#xff0c;并设置好源和更新3、安装aem 四、安…...

图片文本识别OCR+DeepSeekapi实现提取图片关键信息

用到的技术&#xff1a; 通过腾讯OCR文字识别&#xff0c;deepseek的api实现 目录 需求分析&#xff1a; 文字识别&#xff08;OCR&#xff09;具体实现步骤 起步工作 代码编写 deepseek整合消息&#xff0c;返回文本关键信息 起步工作 编写工具类 具体调用实现 具体…...

minio改成https+域名访问

思路有两个&#xff1a; 方式一&#xff1a;通过nginx反向代理&#xff0c;将https配置在nginx&#xff0c;内部的MinIO还是使用HTTP&#xff1b;方式二&#xff1a;MinIO服务端直接配置成HTTPS&#xff1b; 注意&#xff1a; 私钥需要命名为&#xff1a;private.key 公钥需要…...

unity与usb串口通信(web版)

一、本文介绍在web环境下unity与usb串口进行通信的代码 本篇使用本地服务器作为unity与串口的中介&#xff0c;unity发送数据到服务器&#xff0c;服务器发送给串口收到响应并解析返回给uinty。 使用websocket协议。 注&#xff1a; 1.我的硬件是检测磁阻液位&#xff0c;用…...

UE5每次都打开上一次的工程文件 , 如何取消?

点击左上角 - 文件 点击 打开项目 取消勾选 - 启动时固定加载上次打开的项目...

AI大模型与人类未来的协作图景:从工具到“数字共生体”

📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:技术跃迁与文明重塑的十字路口 2020年代以来,人工智能特别是**AI大语言模型(Large Language Models, LLMs)**的迅猛发展,正在从根本上改变人类与技术的关系。从最初的“智能写作助手”到今日…...

C++ I/O 性能优化指南

在高性能计算和大规模数据处理中&#xff0c;I/O 性能优化是提升系统整体效率的关键环节。C 作为一种高性能编程语言&#xff0c;提供了丰富的工具和机制来优化 I/O 操作。本文将详细介绍在 Linux 环境下&#xff0c;如何通过代码层面的优化、系统调用的选择以及多线程技术等手…...

Idea忽略已提交文件

全局忽略 项目根目录下新增.gitignore文件&#xff0c;写入想要忽略的信息&#xff0c;以下可参考 **/src/main/resources/application-local.yamltarget/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/### IntelliJ IDEA ### .idea/mod…...

Mamba原理及在low-level vision的工作[持续更新]

文章目录 Mamba原理选择性扫描&#xff08;Selective Retain Information&#xff09;&#xff1a;选择有关/无关信息状态空间模型&#xff08;SSM&#xff09;Mamba的选择性保留信息Mamba的扫描操作&#xff08;The Scan Operation&#xff09; 硬件感知&#xff08;Hardware-…...

openlayers入门02 -- 地图控件

地图控件 1.视图跳转控件&#xff08;ZoomToExtent&#xff09; 视图跳转控件用于将地图快速跳转到指定的范围。示例&#xff1a; // 视图跳转控件&#xff08;extent这里用的是学校的经纬度范围&#xff0c;可以按照需要修改&#xff09; const ZoomToExtent new ol.contro…...

Python 装饰器(Decorator)

文章目录 代码解析1. 装饰器定义 timer(func)2. 应用装饰器 timer **执行流程****关键点****实际应用场景****改进版本&#xff08;带 functools.wraps&#xff09;** 这是一个 Python 装饰器&#xff08;Decorator&#xff09; 的示例&#xff0c;用于测量函数的执行时间。下…...

UE的AI判断队伍归属的机制:IGenericTeamAgentInterface接口

从官方论坛老哥那学来的&#xff0c;优点在于使用项目设置&#xff0c;像配置碰撞一样&#xff0c;能配置碰撞通道对其他碰撞通道的反应&#xff0c;如阻挡&#xff0c;忽略&#xff0c;重叠&#xff0c;全局配置队伍归属&#xff0c;也能配置当前队伍对其他队伍的身份识别&…...

安宝特新闻丨Vuzix Core™波导助力AR,视角可调、高效传输,优化开发流程

Vuzix Core™ 光波导技术 近期&#xff0c;Vuzix Core™光波导技术赋能AR新视界&#xff01;该系列镜片支持定制化宽高比调节及20至40视场角范围&#xff0c;可灵活适配各类显示引擎。通过创新的衍射光波导架构&#xff0c;Vuzix Core™实现了光学传输效率与图像质量的双重突破…...

基于springboot留守儿童网站的设计与实现 docx

收藏关注不迷路&#xff01;&#xff01; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff08;免费咨询指导选题&#xff09;&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;希望帮助更多…...

AST 技术进行 JavaScript 反混淆实战

一、AST 技术核心原理 抽象语法树&#xff08;AST&#xff09; 是代码的“骨架”&#xff0c;它把代码拆解成一个个节点&#xff0c;就像把一棵大树拆成树枝、树叶一样。通过分析和修改这些节点&#xff0c;我们可以精准地还原代码的逻辑。 二、实战案例 1&#xff1a;还原字…...

基于ECharts+Spark的疫情防控数据分析平台(源码+lw+部署文档+讲解),源码可白嫖!

摘要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;特别是近几年来&#xff0c;新冠疫情出现以来&#xff0c;疫情防控数据分析平台当然不能排除在外。我本次开发的疫情防控数据分析平台是在…...

wireshark过滤器表达式的规则

1.抓包过滤器语法和实例 抓包过滤器类型Type&#xff08;host、net、port&#xff09;、方向Dir&#xff08;src、dst&#xff09;、协议Proto&#xff08;ether、ip、tcp、udp、http、icmp、ftp等&#xff09;、逻辑运算符&#xff08;&&与、|| 或、&#xff01;非&am…...

使用 Python 扫描 Windows 下的 Wi-Fi 网络实例演示

使用 Python 扫描 Windows 下的 Wi-Fi 网络 代码实现代码解析 1. 导入库2. 解码混合编码3. 扫描 Wi-Fi 网络4. 运行函数 这是我当前电脑的 wifi 连接界面。 这个是运行的效果图&#xff1a; 代码实现 我们使用了 Python 的 subprocess 模块来调用 Windows 的内置命令 netsh…...

Redis 字符串(String)详解

1. 什么是字符串类型 在 Redis 中&#xff0c;字符串&#xff08;String&#xff09; 是最基本的数据类型。它可以包含任何数据&#xff0c;比如文本、JSON、甚至二进制数据&#xff08;如图片的 Base64 编码&#xff09;&#xff0c;最大长度为 512 MB。 字符串在 Redis 中不…...

【Taro3.x + Vue3】搭建微信小程序

IOS环境为例 打开终端环境有多种办法&#xff0c;例举一个&#xff1a;在访达里新建一个文件夹&#xff0c;鼠标右键选择。 一、先安装Taro的环境 npm install -g tarojs/cli安装完成后&#xff0c;可以输入命令检验是否安装成功&#xff1a; taro --version二、创建项目 …...

P8668 [蓝桥杯 2018 省 B] 螺旋折线

题目 思路 一眼找规律题&#xff0c;都 1 0 9 10^9 109说明枚举必然超时&#xff0c;找规律&#xff0c;每个点找好像没有什么规律&#xff0c;尝试找一下特殊点&#xff0c;比如&#xff1a;对角线上的点 4 16 36(右上角&#xff09; 4k^2&#xff0c;看在第几层&#xff08;…...

【14】数据结构之哈夫曼树篇章

目录标题 哈夫曼树哈夫曼树的定义哈夫曼树的构造哈夫曼编码哈夫曼树的实现 哈夫曼树 哈夫曼树的定义 路径&#xff1a;从一个结点到另一个结点的路线树的路径长度&#xff1a;从树根到树中每个结点的路径长度之和结点的权&#xff1a;在一些应用中&#xff0c;赋予树中结点的…...

初识SpringAI(接入硅基流动deepseek)

①创建项目 ②application.yml spring:application:name: pgs-aiai:openai:api-key: sk-vrozloxjpjgkozaggtodbmwyfmubmxqpdpbvbbxpcgleanugbase-url: https://api.siliconflow.cn/chat:options:model: deepseek-ai/DeepSeek-V3 api-key&#xff1a;去硅基流动官网生成你的密钥…...

两个有序序列合并算法分析

一 问题背景 合并两个有序序列是常见操作,例如在归并排序中。传统方法需要额外空间,时间复杂度为 O(n)。但若要求原地合并(不占用额外内存),则需借助 手摇算法(或称内存反转或三次反转算法)。 二 手摇算法原理 手摇算法通过三次反转操作,实现数组片段的原…...

Robot---SPLITTER行星探测机器人

1 背景 先给各位读者朋友普及一个航天小知识&#xff0c;截止到目前为止&#xff0c;登陆火星的火星车有哪些&#xff1f;结果比较令人吃惊&#xff1a;当前只有美国和中国登陆过火星。 “勇气”号&#xff08;Spirit&#xff09;&#xff1a;2004年1月4日&#xff0c;美国国家…...