Linux系统——基础IO(上)

作者:进击的荆棘日期:2026/9/18

💁‍♂️个人主页:进击的荆棘

👇作者其它专栏:

《数据结构与算法》《算法》《C++起始之路》《Linux》


目录

1.理解“文件”

2.C文件接口

3.系统文件I/O

4.理解“一切皆文件”

5.缓冲区


1.理解“文件”

1.1狭义理解

●文件在磁盘里

●磁盘是永久性存储介质,因此文件在磁盘上的存储是永久性的

●磁盘是外设(既是输出设备也是输入设备)

●磁盘上的文件本质是:对文件的所有操作,都是对外设的输入和输出,检查IO

1.2广义理解

●Linux下一切皆文件(磁盘、显示器、网卡、键盘……都是抽象化的过程)

1.3文件操作的归类认知

●对于0KB的空文件是占用磁盘空间的

●文件是文件属性(元数据)和文件内容的集合(文件=属性(元数据)+内容)

●所有的文件操作本质是文件内容操作和文件属性操作

1.4系统角度

●对文件的操作本质是进程对文件的操作

●磁盘的管理者是操作系统

●文件的读写本质不是通过C/C++的库函数来操作的(这些库函数只是为用户提供方便),而是通过文件相关的系统调用接口来实现的

2.C文件接口

2.1hello.c打开⽂件

1#include <stdio.h>
2
3int main()
4{
5    FILE *fp = fopen("myfile", "w");
6    if(!fp){
7        printf("fopen error!\n");
8    }
9    while(1);
10    fclose(fp);
11    return 0;
12}
13

打开的myfile文件在哪个路径下?

●在程序的当前路径下。系统如何知道程序的当前路径在哪里?

可以使用ls /proc/[进程id] -l命令查看当前正在运行进程的信息:

1[sjx@VM-8-12-centos io]$ ps ajx | grep myProc
2506729 533463 533463 506729 pts/249 533463 R+ 1002 7:45 ./myProc
3536281 536542 536541 536281 pts/250 536541 R+ 1002 0:00 grep --
4color=auto myProc
5[sjx@VM-8-12-centos io]$ ls /proc/533463 -l
6total 0
7......
8-r--r--r-- 1 hyb hyb 0 Aug 26 17:01 cpuset
9lrwxrwxrwx 1 hyb hyb 0 Aug 26 16:53 cwd -> /home/sjx/io
10-r-------- 1 hyb hyb 0 Aug 26 17:01 environ
11lrwxrwxrwx 1 hyb hyb 0 Aug 26 16:53 exe -> /home/sjx/io/myProc
12dr-x------ 2 hyb hyb 0 Aug 26 16:54 fd
13......

其中:

●cwd:指向当前进程运行目录的一个符号链接

●exe:指向启动当前进程的可执行文件(完整路径)的符号链接

打开文件,本质是进程打开,所以进程知道自己在哪里,即使文件不带路径,进程也知道。因此OS就能知道创建的文件放在哪里。

2.2hello.c写文件

1#include <stdio.h>
2#include <string.h>
3
4int main()
5{
6    FILE *fp = fopen("myfile", "w");
7    if(!fp){
8        printf("fopen error!\n");
9    }
10    const char *msg = "hello bit!\n";
11    int count = 5;
12    while(count--){
13        fwrite(msg, strlen(msg), 1, fp);
14    }
15    fclose(fp);
16    return 0;
17}

2.3hello.c读文件

1#include <stdio.h>
2#include <string.h>
3
4int main()
5{
6    FILE *fp = fopen("myfile", "r");
7    if(!fp){
8        printf("fopen error!\n");
9        return 1;
10    }
11    char buf[1024];
12    const char *msg = "hello bit!\n";
13    while(1){
14        //注意返回值和参数,此处有坑,仔细查看man⼿册关于该函数的说明
15        size_t s = fread(buf, 1, strlen(msg), fp);
16        if(s > 0){
17            buf[s] = 0;
18            printf("%s", buf);
19        }
20        if(feof(fp)){
21            break;
22        }
23    }
24    fclose(fp);
25    return 0;
26}
27

在上面的基础实现cat指令:

1#include <stdio.h>
2#include <string.h>
3
4int main(int argc, char* argv[])
5{
6    if (argc != 2)
7    {
8        printf("argv error!\n");
9        return 1;
10    }
11    FILE *fp = fopen(argv[1], "r");
12    if(!fp){
13        printf("fopen error!\n");
14        return 2;
15    }
16    char buf[1024];
17    while(1){
18        int s = fread(buf, 1, sizeof(buf), fp);
19        if(s > 0){
20            buf[s] = 0;
21            printf("%s", buf);
22        }
23        if(feof(fp)){
24            break;
25        }
26    }
27    fclose(fp);
28    return 0;
29}

2.4输出信息到显示器

1#include <stdio.h>
2#include <string.h>
3
4int main()
5{
6    const char *msg = "hello fwrite\n";
7
8    fwrite(msg, strlen(msg), 1, stdout);
9    printf("hello printf\n");
10    fprintf(stdout, "hello fprintf\n");
11 
12    return 0;
13}
14

2.5stdin&stdout&stderr

●C默认会打开三个输出流,分别是stdin,stdout,stderr

●这三个流的类型都是FILE*,fopen返回值类型,文件指针

1#include <stdio.h>
2
3extern FILE *stdin;
4extern FILE *stdout;
5extern FILE *stderr;

2.6打开文件的操作

1r  Open text file for reading.
2The stream is positioned at the beginning of the file.
3
4r+ Open for reading and writing.
5The stream is positioned at the beginning of the file.
6
7w Truncate(缩短) file to zero length or create text file for writing.
8The stream is positioned at the beginning of the file.
9
10w+ Open for reading and writing.
11The file is created if it does not exist, otherwise it is truncated.
12The stream is positioned at the beginning of the file.
13
14a Open for appending (writing at end of file).
15The file is created if it does not exist.
16The stream is positioned at the end of the file.
17
18a+ Open for reading and appending (writing at end of file).
19The file is created if it does not exist. The initial file position
20for reading is at the beginning of the file,
21but output is always appended to the end of the file.
22

3.系统文件I/O

打开文件的方式不仅仅是fopen,ifstream等流式,语言层的方案,其实才是系统打开文件最底层的方案。而学习系统文件IO之前,需了解如何给函数传递标志位,该方法在系统文件IO接口中会使用到:

3.1一种传递标志位的方法

1#include <stdio.h>
2
3#define ONE 0001 //0000 0001
4#define TWO 0002 //0000 0010
5#define THREE 0004 //0000 0100
6
7void func(int flags) {
8    if (flags & ONE) printf("flags has ONE! ");
9    if (flags & TWO) printf("flags has TWO! ");
10    if (flags & THREE) printf("flags has THREE! ");
11    printf("\n");
12}
13
14int main() {
15    func(ONE);
16    func(THREE);    
17    func(ONE | TWO);
18    func(ONE | THREE | TWO);
19    return 0;
20}

操作文件除了使用语言层的接口,还可以采用系统接口来进行文件访问。

3-2 hello.c写文件

1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <unistd.h>
6#include <string.h>
7
8int main()
9{
10    umask(0);
11    int fd = open("myfile", O_WRONLY|O_CREAT, 0644);
12    if(fd < 0){
13        perror("open");
14        return 1;
15    }
16    int count = 5;
17    const char *msg = "hello bit!\n";
18    int len = strlen(msg);
19    while(count--){
20        write(fd, msg, len);//fd: 文件描述符, msg:缓冲区⾸地址, len: 本次读取,期望
21写⼊多少个字节的数据。 返回值:实际写了多少字节数据
22    }
23    close(fd);
24    return 0;
25}
26

3.3hello.c读文件

1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <unistd.h>
6#include <string.h>
7
8int main()
9{
10    int fd = open("myfile", O_RDONLY);
11    if(fd < 0){
12        perror("open");
13        return 1;
14    }
15    const char *msg = "hello bit!\n";
16    char buf[1024];
17    while(1){
18        size_t s = read(fd, buf, strlen(msg));//类⽐write
19        if(s > 0){
20            printf("%s", buf);
21        }else{
22            break;
23        }
24    }
25    close(fd);
26    return 0;
27}
28

3.4接口介绍

open:man open

1#include <sys/types.h>
2#include <sys/stat.h>
3#include <fcntl.h>
4
5int open(const char *pathname, int flags);
6int open(const char *pathname, int flags, mode_t mode);
7
8pathname: 要打开或创建的⽬标⽂件
9flags: 打开⽂件时,可以传⼊多个参数选项,⽤下⾯的⼀个或者多个常量进⾏“或”运算,构成
10flags。
11参数:
12    O_RDONLY: 只读打开
13    O_WRONLY: 只写打开
14    O_RDWR : 读,写打开
15        这三个常量,必须指定⼀个且只能指定⼀个
16    O_CREAT : 若⽂件不存在,则创建它。需要使⽤mode选项,来指明新⽂件的访
17问权限
18    O_APPEND: 追加写
19返回值:
20    成功:新打开的⽂件描述符
21    失败:-1
22

mode_t:在Linux/glibc中,一般被定义为:typedef unsigned int mode_t

open函数具体使用哪个,和具体应用场景相关,若目标文件不存在,需要open创建,则第三个参数标识创建文件的默认权限,否则,使用两个参数的open

write,read,close,lseek,类比C文件相关接口

3.5open函数返回值

在认识返回值之前,得先认识系统调用和库函数

●上面的fopen,fclose,fread,fwrite都是C标准库当中的函数,称之为库函数(libc)

●而open,close,read,write,lseek都属于系统提供接口,称之为系统调用接口

所以,可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发。

3.6文件描述符fd

●通过open,我们知道了文件描述符就是一个小整数

3.6.1 0&1&2

●Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0,标准输出1,标准错误2

●0,1,2对应的物理设备一般是:键盘,显示器,显示器

所有输入输出还可以采用如下方式:

1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <string.h>
6
7int main()
8{
9    char buf[1024];
10    size_t s = read(0, buf, sizeof(buf));
11    if(s > 0){
12        buf[s] = 0;
13        write(1, buf, strlen(buf));
14        write(2, buf, strlen(buf));
15    }
16    return 0;
17}
18

已经知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*file,指向一张表files_struct,该表最重要的部分就是包含一个指针数组,每个元素都是一个指向打开文件的指针。所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。

对于以上原理结论可以通过内核源码验证:

首先要找到task_struct结构体在内核中的位置,地址为:/usr/src/kernels/3.1θ.0-1160.71.1.el7.x86_64/include/linux /sched.h (3.10.0-1160.71.1.el7.x86_64是内核版本,可使用uname -a查看服务器配置)

●要查看内容可直接用vs code在windows下打开内核源代码

●相关结构体所在位置

▢struct task_struct : /usr/src/kernels/3.10.0-1160.71.1.el7.x86_64/include/linux/sched.h

▢struct files_struct : /usr/src/kernels/3.10.0-1160.71.1.el7.x86_64/include/linux/fdtable.h

▢struct file : /usr/src/kernels/3.10.0-1160.71.1.el7.x86_64/include/linux/fs.h

3.6.2文件描述符的分配规则

1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5
6int main()
7{
8    int fd = open("myfile", O_RDONLY);
9    if(fd < 0){
10        perror("open");
11        return 1;
12    }
13    printf("fd: %d\n", fd);
14    close(fd);
15    return 0;
16}
17

输出结果 fd:3

关闭0或2后:

1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5
6int main()
7{
8    close(0);
9    //close(2);
10    int fd = open("myfile", O_RDONLY);
11    if(fd < 0){
12        perror("open");
13        return 1;
14    }
15    printf("fd: %d\n", fd);
16    close(fd);
17    return 0;
18}

结果为 fd:0后fd:2,可见,文件描述符的分配规则:在files_struct数组中,找到当前没有被使用的最小下标,作为新的文件描述符

3.6.3重定向

若关闭1

1#include <stdio.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5#include <stdlib.h>
6
7int main()
8{
9    close(1);
10    int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
11    if(fd < 0){
12        perror("open");
13        return 1;
14    }
15    printf("fd: %d\n", fd);
16    fflush(stdout);
17    close(fd);
18    exit(0);
19}

此时,本应输出到显示器上的内容,输出到了文件myfile中,其中,fd=1。这种现象叫做输出重定向。常见的重定向有:>,>>,<

输出重定向的本质:

3.6.4使用dup2系统调用

函数原型:

1#include <unistd.h>
2int dup2(int oldfd, int newfd);
1#include <stdio.h>
2#include <unistd.h>
3#include <fcntl.h>
4int main() {
5    int fd = open("./log", O_CREAT | O_RDWR);
6    if (fd < 0) {
7        perror("open");
8        return 1;
9    }
10    close(1);
11    dup2(fd, 1);
12    for (;;) {
13    char buf[1024] = {0};
14    size_t read_size = read(0, buf, sizeof(buf) - 1);
15    if (read_size < 0) {
16        perror("read");
17        break;
18    }
19    printf("%s", buf);    
20    fflush(stdout);
21    }
22    return 0;
23}
24
25

printf是C库中的IO函数,一般往stdout中输出,但是stdout底层访问文件的时候,找的还是fd:1,但此时,fd:1下标所表示的内容,已经变成了myfile的地址,不在是显示器文件的地址,所以,输出的任何消息都会往文件中写入,进而完成输出重定向。

3.6.5在myshell中添加重定向功能

1#include <iostream>
2#include <cstdio>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
6#include <sys/wait.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <fcntl.h>
10
11#define COMMAND_SIZE 1024
12#define FORMAT "[%s@%s %s]# "
13
14//shell的全局参数
15#define MAXARGC 128
16int g_argc;
17char* g_argv[MAXARGC];
18
19//环境变量参数表
20#define MAX_ENV 100
21char * g_env[MAX_ENV];
22int g_envs;
23
24//for test
25char cwd[1024];
26char cwdenv[1024];
27
28//退出码
29int lastcode=0;
30
31//重定向需要的变量
32#define NONE_REDIR 0   
33#define INPUT_REDIR 1   //<
34#define OUTPUT_REDIR 2  //>
35#define APPEND_REDIR 3  //>>
36int redir=NONE_REDIR;
37std::string filename;
38
39const char* GetUser(){
40  const char * user=getenv("USER");
41  return user==NULL?"none":user;
42}
43
44const char* GetHostname(){
45  const char * hostname=getenv("HOSTNAME");
46  return hostname==NULL?"none":hostname;
47}
48
49const char* GetPwd(){
50  //const char * pwd=getenv("PWD");
51  const char * pwd=getcwd(cwd,sizeof(cwd));
52  if(pwd){
53    snprintf(cwdenv,sizeof(cwdenv),"PWD=%s",cwd);
54    putenv(cwdenv);
55  }
56  return pwd==NULL?"none":pwd;
57}
58
59const char * GetHome(){
60  const char *home=getenv("HOME");
61  return home==NULL?"":home;
62}
63
64void InitEnv(){
65  extern char ** environ;
66  memset(g_env,0,sizeof(g_env));
67  g_envs=0;
68  //1.获取环境变量
69  for(int i=0;environ[i];i++){
70    //先为自己的环境变量参数表开辟空间
71    g_env[i]=(char*)malloc(strlen(environ[i])+1);
72    strcpy(g_env[i],environ[i]);
73    g_envs++;
74  }
75
76  g_env[g_envs]=NULL;//最后一个值需要为空
77  //2.导成环境变量
78  for(int i=0;g_env[i];i++){
79    putenv(g_env[i]);
80  }
81  environ=g_env;
82}
83
84std::string DirName(const char* pwd){
85#define SLASH "/"
86  std::string dir=pwd;
87  if(dir==SLASH) return SLASH;
88  auto pos=dir.rfind(SLASH);
89  if(pos==std::string::npos) return "BUG?";
90  return dir.substr(pos+1);
91}
92void MakeCommandLine(char prompt[],int size){
93  snprintf(prompt,size,FORMAT,GetUser(),GetHostname(),DirName(GetPwd()).c_str());
94}
95
96void PrintCommandPrompt(){
97  char prompt[COMMAND_SIZE];
98  MakeCommandLine(prompt,sizeof(prompt));
99  printf("%s",prompt);
100  fflush(stdout);
101}
102
103bool GetCommand(char* command,int size){
104  char *str=fgets(command,size,stdin);
105  if(str==NULL) return false;
106  command[strlen(command)-1]=0;//消除\n
107  if(strlen(command)==0) return false;
108  return true; 
109}
110bool CommandPrase(char *command){
111#define SPA " "
112  g_argc=0;
113  g_argv[g_argc++]=strtok(command,SPA);
114  while((bool)(g_argv[g_argc++]=strtok(nullptr,SPA)));
115  //减掉多余的1
116  g_argc--;
117  return g_argc>0?true:false;
118}
119void Cd(){
120  //四种清况 cd    cd -   cd ~   cd XXXNAME
121  if(g_argc==1){
122    std::string home=GetHome();
123    if(home.empty()) return ;
124    chdir(home.c_str());
125  }
126  else{
127    std::string where=g_argv[1];
128    if(where=="-"){
129     // 
130    }
131    else if(where=="~"){
132      chdir(getenv("HOME"));
133    }
134    else{
135      chdir(where.c_str());
136    }
137  }
138}
139void Echo(){
140  //三种清况 echo $?   ehco $PATH   echo "XXXXX"
141  if(g_argc==2){
142    std::string opt=g_argv[1];
143    if(opt=="$?"){
144      std::cout<<lastcode<<std::endl;
145      lastcode=0;
146    }
147    else if(opt[0]=='$'){
148      std::string env_name=opt.substr(1);
149      const char* env_value=getenv(env_name.c_str());
150      if(env_value)
151          std::cout<<env_value<<std::endl;
152    }
153    else {
154      std::cout<<opt<<std::endl;
155    }
156  } 
157}
158
159bool CheckAndExecIn(){
160  std::string cmd=g_argv[0];
161  if(cmd=="cd"){
162    Cd();
163    return true;
164  }
165  else if(cmd=="echo"){
166    Echo();
167    return true;
168  }
169  return false;
170}
171
172void Execte(){
173  pid_t id=fork();
174  if(id==0){
175    int fd=-1;
176    //判断是否是重定向
177    if(redir==INPUT_REDIR){
178      fd=open(filename.c_str(),O_RDONLY);
179      if(fd<0) exit(1);
180      dup2(fd,0);
181      close(fd);
182    }
183    else if(redir==OUTPUT_REDIR){
184      fd=open(filename.c_str(),O_CREAT|O_WRONLY|O_TRUNC,0666);
185      if(fd<0) exit(2);
186      dup2(fd,1);
187      close(fd);
188    }
189    else if(redir==APPEND_REDIR){
190      fd=open(filename.c_str(),O_CREAT|O_WRONLY|O_APPEND,0666);
191      if(fd<0) exit(2);
192      dup2(fd,1);
193      close(fd);
194    }
195    else {
196
197    }
198    //child
199    execvp(g_argv[0],g_argv);
200    exit(1);
201  }
202  int status=0;
203  //father
204  pid_t rid=waitpid(id,&status,0);
205  if(rid>0){
206    lastcode=WEXITSTATUS(status);
207  }
208}
209
210//void Print(char* command){
211//  printf("%s\n",command);
212//}
213
214void RvSpace(char cmd[],int &end){
215  while(isspace(cmd[end])){
216    end++;
217  }
218}
219void RedirCheck(char cmd[]){
220  redir=NONE_REDIR;
221  filename.clear();
222
223  int start=0;
224  int end=strlen(cmd)-1;
225  while(end>start){ 
226    if(cmd[end]=='<'){
227      cmd[end++]=0;
228      RvSpace(cmd,end);
229      redir=INPUT_REDIR;
230      filename=cmd+end;
231      break;
232    }
233    else if(cmd[end]=='>'){
234      if(cmd[end-1]=='>'){
235        cmd[end-1]=0;
236        //RvSpace(cmd,end);
237        redir=APPEND_REDIR;
238        //filename=cmd+end;
239        //break;
240      }
241      else{ 
242        //cmd[end++]=0;
243        //RvSpace(cmd,end);
244        redir=OUTPUT_REDIR;
245        //filename=cmd+end;
246        //break;
247      }
248      cmd[end++]=0;
249      RvSpace(cmd,end);
250      filename=cmd+end;
251      break;
252    }
253    else{
254      end--;
255    }
256  }
257}
258
259int main(){
260  InitEnv();
261  while(true){
262     //1.输出命令行提示符
263     PrintCommandPrompt();
264     //2.获取命令行输入
265     char command[COMMAND_SIZE];
266     if(!GetCommand(command,sizeof(command)))
267       continue;
268     //Print(command);
269    
270     //3.重定向检查
271     RedirCheck(command);
272     //printf("redir:%d,filename:%s\n",redir,filename.c_str());
273
274     //4.拆解命令行 "ls -a -l" -> "ls" "-a" "-l"
275     if(!CommandPrase(command))
276       continue;
277     //5.检测并处理内建命令
278     if(CheckAndExecIn())
279       continue;
280     //6.执行替换命令
281     Execte();
282  }
283  return 0;
284}
285

《Linux系统——基础IO(上)》 是转载文章,点击查看原文。


相关推荐


密码管理工具站正式上线啦
乱码三千2026/9/10

前言 互联网时代要存储的密码实在太多, 脑袋压根记不过来, 只能借助外物, 比如存到便签里, 或者建一个Excel表格, 但是存在两个问题, 那就是安全性和便捷性不够 我的要求是随时随地都能查看、编辑、保存和新增密码, 无论是外出还是在家, 也不管是使用电脑还是手机, 可以进行无缝切换 其实苹果自带的密钥就很好用, 但是局限于苹果设备, 万一哪天换安卓了, 就很尴尬, 虽然支持云端存储, 但是不能导出到本地, 安全性和便捷性还是不足 便签的话更不用说了, 明文显示, 安全性极差 既然存到第三方平


同一份 15 个流程 JSON,第六种语言也跑通了:工作流引擎 Rust 移植实录
mldong2026/9/2

一、第六格不是"翻译" 这个系列写过五门语言的工作流引擎:Java、Go、Python、Node、PHP。五门语言读的是同一份东西——引擎仓库里 flows/ 目录下的 15 个流程 JSON:简单审批、多任务、条件路由、fork-join、三种会签、退回发起人、混合模式……六语言 demo 共读这一个目录,改一处,六边验证。 第六种语言是 Rust。 先说清楚一件事,免得标题被误读:Rust 里不缺"工作流引擎"——做任务编排(durable execution)的有 Temporal、wor


OpenTelemetry Java 扩展:无需分叉 agent 即可自定义追踪
Elasticsearch2026/8/25

作者:来自 Elastic Sylvain Juge 一个 JAR 文件,在 OpenTelemetry Java agent 启动时加载,就可以过滤健康检查、重命名 span、添加资源属性以及控制采样,而无需修改应用程序代码。 你刚刚为一个 Java 应用设置了自动插桩。无需修改任何代码,追踪数据就开始流向你的可观测性平台。几分钟后,你发现健康检查端点正在大量充斥你的追踪视图,而且事务名称反映的是通用的框架模式,而不是你的业务领域操作。 分叉 agent 可以解决这个问题,但这样一来,你就需


把 Agent 做成一家公司,真比通用提示词好用吗?
苏灿烤鱼2026/8/12

它卖的不是一个万能 Agent,而是一套可挑选、可安装的 AI 专业分工。 ⚡️ 30 秒速读:msitarzewski/agency-agents 以 143,086 星、今日 +971 登上 GitHub Trending #1,连续 3 天在榜,排名从 #3、#2 升到 #1。它把不同专业角色写成独立 Agent 文件,每个文件包含身份与性格、核心任务与工作流、带代码示例的技术交付物、成功指标和沟通风格;可用原生桌面应用或 Shell 脚本安装到 Claude Code、Cursor、


Vite 8.1 深度拆解:Rolldown 统一打包器如何终结前端构建的「双引擎时代」
NutShell Wang2026/8/2

2026 年 3 月 12 日,Vite 8.0 正式发布,将 Rolldown——一个用 Rust 编写的打包器——作为唯一打包引擎引入,取代了此前 esbuild(开发)+ Rollup(生产)的双引擎架构。这被官方称为「自 Vite 2 以来最重大的架构变更」。三个月后的 Vite 8.1(6 月 23 日发布)进一步推出了实验性打包开发模式,在 10,000 个 React 组件的测试中实现了约 15 倍的启动加速。与此同时,Rolldown 本身也在快速迭代——1.0 正式版于 5 月


线程栈与TLS和线程互斥
keyipatience2026/7/25

线程栈 主线程(进程 main 栈)特性: (1)来源:fork 复制父进程栈 (2)可动态自动扩容 (3)缺页容错特殊:允许访问未映射页、不一定直接段错误的栈 线程栈 mem = mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 标志MAP_STACK:专门标记这块内存用作线程栈;默认固定 8MB 大小(一般够用),不支持动态扩容,空间用完直接栈溢出崩溃;属于进程虚拟地址里一块独


如何用 AI 协助解决陌生技术问题:拆解-分析-熟悉-解决四步法
dozenyaoyida2026/7/17

你接过陌生项目吗?那种打开 IDE,几千个文件铺开,光看目录名就头大,盯着屏幕两小时一行代码没写的感觉。 或者更常见的,线上突然报了个错,涉及一个你从没读过的模块,老板在群里 @ 你,你点开文件,密密麻麻的调用链,不知道从哪开始查。 我做了十年开发,最近两年重度用 AI 辅助。最大的体会是,面对陌生问题,卡住你的从来不是"难",是"乱"。你不知道从哪下手,不知道自己不知道什么,于是在原地打转。 下面这套方法我用了几十次,核心就四个字:拆解、分析、熟悉、解决。AI 在每个阶段扮演的角色不一样,你介


【从零开始大模型开发与微调:基于PyTorch与ChatGLM】(基于PyTorch卷积层的MNIST分类实战:从卷积直觉到高效卷积设计)
承渊政道2026/7/9

🔥承渊政道:个人主页 ❄️个人专栏: 《C语言基础语法知识》 《数据结构与算法》 《C++知识内容》 《Linux系统知识》 《算法刷题指南》 《测评文章活动推广》 《大模型语言路线学习》 《MySQL数据库学习》 《Python知识内容》 ✨逆境不吐心中苦,顺境不忘来时路!✨ 🎬 博主简介: 前面使用多层感知机完成了MNIST分类实战的演示.多层感知机是一种对目标数据进行整体分类的计算方法.虽然从演示效果来看,多层感知机可以较好地完成项目


开源「仓颉.Skill」2.0,你现在可以蒸馏任何视频!
AI袋鼠帝2026/7/1

大家好,我是袋鼠帝。 没想到cangjie-skill在4月开源,中间没怎么推,两个月还慢慢涨到了1.3K Star,有点出乎我的意料。 而且现在每天都还在增涨,感谢大家支持~ github.com/kangarookin… 说明大家对蒸馏书是有需求的(可以理解为人工智能拆书)。 也并不是像评论区一些人说的:“所有书AI都学过了,你这个是脱了裤子放屁。”那样不堪。 对一些大众非常熟悉的书,可能不太需要这个方式来蒸馏。但是有很多比较小众的书,AI不一定记得清楚,甚至还有很多新书是AI没有训练的。


AI Agent(六)- Dify 自定义工具实战 - 基于百度天气 API 搭建天气查询 Agent(天气智查助手)
BigDataMagician2026/6/22

文章目录 一、前言二、整体实现思路三、申请百度地图开放平台 AK1. 注册百度地图开放平台2. 登录百度地图开放平台3. 创建应用并获取AK4. 查看国内天气查询接口开发文档5. 接口测试 四、创建自定义工具1. OpenAPI 规范配置内容及说明1.1 OpenAPI 规范配置内容1.2 OpenAPI 规范配置说明 2. 配置OpenAPI 规范3. 工具测试 六、搭建天气智查助手Agent1. 创建Agent2. System Prompt(系统提示词)3. 调用工具4.

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读