Linux —— 文件操作

article/2025/10/12 1:02:46

目录

1.内核提供的文件系统调用

1.1open和close

1.2标记位

1.3write和read

2.文件描述

2.1文件描述符

 2.2文件描述符分配规则

3.重定向

3.1最“挫”的重定向

3.2使用系统调用

3.3重定向原理

3.4让我们的"shell"支持重定向操作

4.一切皆文件

5.缓冲区

5.1缓冲区的本质

5.2缓冲区的刷新策略

5.3缓冲区的位置

5.4缓冲区与写时拷贝

5.5模拟实现"缓冲区"

1.内核提供的文件系统调用

1.1open和close

通过[man]指令浏览其描述,这里截取片段。 

第一个open是文件存在的情况下打开文件,第一个参数为文件名,若不指定文件路径,则默认为父进程的工作路径。第二个参数为标记位,int类型的每个比特位的0 和 1代表了不同的标记。Linux提供了多种标记。

第二个open是文件不存在的情况下打开文件,第三个参数为文件创建的初始权限。

close即关闭文件。

 下面给出代码实例以供参考:

umask(0);       //将umask置0
int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);     //相当于C语言的fopen的"w",只写、自动创建、自动覆盖
//文件的权限受umask的影响
close(fd);

下面列举一些常用的标记:

  • O_WRONLY        ->只写
  • O_CREAT           ->创建
  • O_TRUNC          ->覆盖
  • O_RDONLY        ->只读
  • O_APPEND        ->追加

需要多个标记组合在一起时,使用 '|'(按位或运算符) 连接即可。

1.2标记位

int类型有4个字节,32个比特位,每一个比特位的0 和 1代表了不同的标记。例如有:......0001与......0010就是两个不同的标记。我们使用代码实例来演示:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>#define ONE (1<<0)
#define TOW (1<<1)      
#define THREE (1<<2)        
#define FOUR (1<<3)void select(int flags)
{if(flags & ONE) printf("one\n");if(flags & TOW) printf("tow\n");if(flags & THREE) printf("three\n");if(flags & FOUR) printf("four\n");
}int main()
{select(ONE);        select(ONE | TOW);select(ONE | TOW | THREE);select(ONE | TOW | THREE | FOUR);return 0;
}

 也就是说,Linux提供的标记实质上是一个宏,每一个宏代表了不同的信号。

1.3write和read

write是一个系统调用,其声明为([man]指令查看):

需要注意的是,write()是从文件的起始位置开始写的,如果在open()中没有O_TRUNC或者O_APPEND标记,那么为将文件以前的内容的一部分覆盖掉。也就是说,要想像C语言一样自动清空文件的内的数据必须加上O_TRUNC标记 。

下面给出write的实际使用案例以供参考:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{umask(0);       //将umask置0int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);     //相当于C语言的fopen的"w",只写、自动创建、自动覆盖if(fd < 0) return 1;char* msg = "hello Linux\n";write(fd,msg,strlen(msg));      //像fd描述的文件写入msg指向的字符串close(fd);return 0;
}

编译运行,查看生成的"log.txt"文件:

read也是一个系统调用,其声明为([man]指令查看):

这里以上面write生成的文件给出read的实际使用案例以供参考:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{int fd = open("log.txt",O_RDONLY);char buffer[64];read(fd,buffer,sizeof(buffer)-1);       //留一个位置补'\0'buffer[strlen(buffer)]=0;       //文件的字符串不以'\0'结尾printf("%s",buffer);close(fd);return 0;
}

2.文件描述

2.1文件描述符

进程可以打开多个文件,所以操作系统会有大量的文件。操作系统为了管理被打开的文件,使用了"先描述,再组织"的方法将被打开的文件描述为一个struct file的内核结构体,其包含了文件的大部分属性,多个内核结构体之前以特定的数据结构组织起来。

这些struct file结构体并不是文件描述符,而是操作系统为了管理被打开的文件而创建的。事实上,文件操作研究的是进程和被打开文件的关系,也就是说文件是被进程打开的。那么进程和struct file结构体中间还有一层结构体,名为struct files_struct(文件描述符表),在task_struct中有一个struct files_struct* files指针指向文件描述符表。文件描述表有一个专门用来存储struct file结构体的地址的指针数组(struct file* fd_array[]),这个数组的下标即为文件描述符

在进程(C语言程序)被加载到内存时,会默认生成打开三个文件(这些文件是C语言使用的,系统是是使用文件描述符的),即:

  • stdin    ->标准输入
  • stdout    ->标准输出
  • stderr    ->标准错误

这三个文件的struct file结构体的地址依次按顺序存储在struct file* fd_array数组对应的下标0、1、2位置。所以我们用户的进程第一次创建的文件的描述符为3。

下面给出进程与文件的假象模型图:

 2.2文件描述符分配规则

 在struct file* fd_array[]数组中,按下标从小到大的顺序,寻找最小、且没有被占用下标作为文件描述符。

下面给出一段代码供加深理解:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{close(0);close(2);       //关闭掉标准输入和标准错误文件,即清空数组的占用int fd = open("log.txt",O_RDONLY);printf("%d\n",fd);close(fd);return 0;
}

3.重定向

3.1最“挫”的重定向

观察下面这段代码以及现象:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{close(1);       //将fd=1的数组位置清空int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);     //文件打开时就占用fd=1的位置printf("hello world\n");fflush(stdout);close(fd);return 0;
}

以上是最原始的重定向操作。其原因在于:printf()函数是默认向fd=1对应的文件(标准输出)输出的,但是进行close(1)操作后,fd=1位置的内容就清空了,随后log.txt文件的struct file结构体地址占用了fd=1的位置,所以printf就向log.txt文件输出了。 

3.2使用系统调用

dup类接口是系统提供给我们的接口,其中dup2最为常用。我们通过[man]指令查询:

下面给出实际使用案例以供参考:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main()
{int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);dup2(fd,1);     //重定向printf("hello world");fflush(stdout);close(fd);return 0;
}

3.3重定向原理

上层看到的文件描述符是不会变的,例如printf规定了向标准输出输出,即向fd=1对应的文件输出,那么printf找的是文件描述符而不是对应的文件,所以fd的内容无论怎么变,上层找的还是fd。

子进程重定向不会影响父进程,因为进程之间相互独立。即子在进程在创建出来的时候,就拷贝了一份文件描述符表。但是文件不属于进程,是不会拷贝的。

3.4让我们的"shell"支持重定向操作

在上次模拟实现命令行解释器的基础上,再进行升级,以支持重定向操作。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>      
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#include <sys/wait.h>
#include <assert.h>#define NUM 1024
#define NON_REDIR 0     //无重定向
#define INPUT_REDIR 1       //输入重定向 '<'
#define OUT_REDIR 2        //输出重定向 '>'
#define APPEND_REDIR 3      //追加重定向 '>>'char command[NUM];      //c99数组
char* myargv[64];       //存储指令参数
char* file_name=NULL;
int redir_type=0;void command_check(char* command)
{assert(command);//首、尾指针char* begin = command;char* end = command+strlen(command);while(begin < end){if(*begin == '>'){*begin=0;begin++;if(*begin == '>'){redir_type=APPEND_REDIR;begin++;}else redir_type=OUT_REDIR;while(*begin == ' ') begin++;file_name=begin;}else if(*begin == '<'){*begin=0;       //置0redir_type=INPUT_REDIR;begin++;while(*begin == ' ') begin++;file_name = begin;}else ++begin;}}
int main()
{while(1){redir_type=NON_REDIR;file_name=NULL;char buffer[1024]={0};getcwd(buffer,sizeof(buffer)-1);        //获取shell的工作路径buffer[strlen(buffer)]=0;printf("[用户名@主机名 %s]",buffer);fflush(stdout);     //刷新缓冲区char* s = fgets(command,sizeof(command),stdin);     //输入指令command[strlen(command)-1]=0;       //清除 \n command_check(command);     //检查指令是否有重定向操作myargv[0] = strtok(command," ");int i = 1;while(myargv[i++] = strtok(NULL," "));      //切割空格if(myargv[0] != NULL &&  strcmp(myargv[0],"cd") == 0){if(myargv[1] != NULL) chdir(myargv[1]);      //cd命令移动shell的工作路径continue;}pid_t id = fork();if(id == 0){switch(redir_type)      //使用switch语句{case NON_REDIR:     //不作处理break;case INPUT_REDIR:       //输入重定向{int fd = open(file_name,O_RDONLY);if(fd < 0){perror("open:");exit(1);}dup2(fd,0);}break;case OUT_REDIR:case APPEND_REDIR:{umask(0);int flag = O_WRONLY | O_CREAT;if(redir_type == APPEND_REDIR) flag |= O_APPEND;else flag |= O_TRUNC;int fd = open(file_name,flag,0666);if(fd < 0){perror("open:");exit(1);}dup2(fd,1);}break;default:break;}execvp(myargv[0],myargv);        //进程替换exit(1);}waitpid(id,NULL,0);}return 0;
}

文件描述符表是属于进程的并且是一个内核数据结构,进程替换是不会影响它的,进程替换只是替换数据段和代码段,是不影响内核数据结构的。

对于文件的关闭,在进程退出时自动关闭。其本质还是在于struct file里面的计数器,这个计数器记录有多少个进程正在引用这个struct file,当进程退出时,计数器就会减1,当计数器为0才文件才销毁。

4.一切皆文件

不止是磁盘上的可执行文件被打开才是文件,硬件也是文件。键盘、鼠标、显示器、内存、硬盘等等都是文件。

操作系统能够使用驱动来管理硬件,那么在驱动上,就一定有硬件与操作系统的IO交互方法。那么在内核中,都有唯一的一份struct file内核结构体对应硬件,以便操作系统管理。所以在Linux的视角来看,一切皆文件。

那么在上层想要与硬件互动时,也是通过struct file结构体实现的,其原因在于此结构体有硬件与操作系统IO交互方法的函数指针,通过这些函数指针去调用不同的交互方式。

发现了吗?即使磁盘上的各种可执行文件或者是硬件非常杂乱,但是在操作系统下总是能有序的抽象化成一个struct file结构体来进行管理。也就是说,我们通过统一的struct file结构体(其中描述了文件的共有属性)来操作不同的文件。用官方的话说(参考Linux内核设计与实现原理):我们可以直接使用open()、read()和write()这样的系统调用而无需考虑具体文件系统和实际物理介质。这样的行为就构成了内核的子系统——虚拟文件系统(VFS)。

5.缓冲区

5.1缓冲区的本质

缓冲区就是内存上的一段,专门用来做缓存工作(将进程的数据拷贝到缓冲区)。

需要缓冲区的原因在于:将数据直接写入外设的效率是非常低的(外设的处理速度相对于cpu的处理速度慢了几千几万倍),当大量进程和大量数据时,进程更多的时间花费在与外设的交互上。

将数据先交给缓冲区,与外设的交互由缓冲区去完成,那么进程就不再被外设“耽搁”了。那么节省进程进行IO的时间就是缓冲区的本质。

5.2缓冲区的刷新策略

缓冲区的刷新有三个策略和两个例外。

三个策略:

  • 无缓冲:当数据写入时,立即刷新缓冲区。
  • 行缓冲:数据每写入一行,缓冲区刷新一次。
  • 全缓冲:数据一直写入直至缓冲区满,此时再刷新。

两个例外:

  • 用户强制刷新(例如fflush)就会立即刷新缓冲区。
  • 进程退出时,一般都要进程缓冲区的刷新。

5.3缓冲区的位置

调用C语言库函数exit时会刷新缓冲区;调用系统调用_exit时不会刷新缓冲区(上一篇博客讲到的)。可以证明,缓冲区的位置不在内核当中。

在使用C语言编程时,缓冲区的位置在FILE结构体中(由C语言提供)。FILE结构体里面封装了缓冲区字段、文件描述符字段等等,由此可见,在上层使用C语言编程时,调用的都是底层的接口。也因此可以得出一个结论:使用系统调用与外设进行IO交互数据不会写入缓冲区(因为系统调用可以直接使用操作系统提供的fd,而不需要使用C语言的FILE结构体)。

5.4缓冲区与写时拷贝

给出一段代码,观察向不同的外设写入数据时产生的不同效果:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main()
{const char* msg_write="write\n";const char* msg_fprintf="fprintf\n";const char* msg_fwrite="fwrite\n";printf("printf\n");fwrite(msg_fwrite,sizeof(char),strlen(msg_fwrite),stdout);fprintf(stdout,"%s",msg_fprintf);fputs("fputs\n",stdout);write(1,msg_write,strlen(msg_write));       //这五个函数都是向标准输出输出fork();     //创建一个子进程return 0;
}

其原因在于:正常运行程序时,是向标准输出输出的,缓冲区采用的是行刷新策略(write除外),所以当创建子进程之前,父进程的缓冲区数据已经被刷到标准输出了,创建子进程后,子进程的缓冲区与父进程共享,即子进程的缓冲区没有数据,进程退出时即使刷新缓冲区也不会触发写时拷贝。 

当输出重定向到文件时,缓冲区采用的是全缓冲策略(write除外),所以创建子进程后父进程的缓冲区依然有数据(wtire的数据不经过缓冲区直接输出到了文件上),子进程共享父进程的缓冲区,而这两个进程任意一个进程退出时,会触发缓冲区的刷新,此时就会触发写时拷贝,也就看到了上面的现象。

5.5模拟实现“缓冲区”

为了加深理解,这里展示一个超级、无敌、极限、超纯净阉割版的缓冲区模拟实现。

//头文件#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>#define SIZE 1024#define ALL 0       //全缓冲策略
#define LINE 1      //行刷新策略(暂时只实现一个吧)
typedef struct _FILE
{int flags;      //缓冲区刷新策略int fileno;     //文件描述符char cush[SIZE];        //缓冲区int size;       //有效数据int cap;        //最大容量
}_FILE;_FILE* _fopen(const char* filename,const char* mode);       //模拟fopen
void _fclose(_FILE* fp);     //模拟fclose
void _fflush(_FILE* fp);        //模拟fflush
void _fwrite(const char* msg,int size,int len,_FILE* fp);     //模拟fwrite
//源文件#include "_stdio.h"_FILE* _fopen(const char* filename,const char* mode)       //模拟fopen
{int flags=0;if(strcmp(mode,"w") == 0){flags |= (O_WRONLY | O_CREAT | O_TRUNC);}else if(strcmp(mode,"r") == 0){flags |= O_RDONLY;}else if(strcmp(mode,"a") == 0){flags |= (O_WRONLY | O_CREAT | O_APPEND);}//上面在确认文件打开方式int fd=0;if(flags & O_RDONLY) fd=open(filename,flags);else fd=open(filename,flags,0666);if(fd < 0){const char* msg=strerror(errno);write(1,msg,strlen(msg));return NULL;    //创建文件失败}//上面在创建文件_FILE* fp = (_FILE*)malloc(sizeof(_FILE));fp->flags=LINE;     //默认行刷新fp->fileno=fd;fp->size=0;fp->cap=SIZE;memset(fp->cush,0,SIZE);//上面在初始化_FILE结构体return fp; 
}void _fclose(_FILE* fp)     //模拟fclose
{_fflush(fp);close(fp->fileno);
}void _fflush(_FILE* fp)        //模拟fflush
{if(fp->size > 0){write(fp->fileno,fp->cush,fp->size);fp->size=0;}
}void _fwrite(const char* msg,int size,int len,_FILE* fp)     //模拟fwrite
{//size没什么乱用,对齐fwrite而已memcpy(fp->cush+fp->size,msg,len);fp->size+=len;//行刷新if(fp->cush[fp->size-1] == '\n'){write(fp->fileno,fp->cush,fp->size);fp->size=0;}else if(fp->size == fp->cap){write(fp->fileno,fp->cush,fp->size);fp->size=0;}}
//主函数#include "_stdio.h"#include <stdio.h>
int main()
{_FILE* fp = _fopen("log.txt","w");const char* msg="hello Linux\n";int cnt = 10;while(cnt){_fwrite(msg,sizeof(char),strlen(msg),fp);printf("count:%d\n",cnt--);sleep(1);}_fclose(fp);return 0;
}

 读者自行将上面的代码copy走,将主函数的msg字符串的'\n'删除掉或保留,在Linux终端下观察文件的数据情况。

 


http://chatgpt.dhexx.cn/article/tn8qepUE.shtml

相关文章

文件操作详解

1.文件的概念 文件的基本概念   所谓“文件”是指一组相关数据的有序集合。 这个数据集有一个名称&#xff0c;叫做文件名。实际上在前面的各章中我们已经多次使用了文件&#xff0c;例如源程序文件、目标文件、可执行文件、库文件 (头文件)等。文件通常是驻留在外部介质(如磁…

文件操作(C语言)

目录 一、前言 二、文件的打开和关闭 三、文件的读写 1.文件的顺序读写 2.文件的随机读写 四、文件结束的判定 一、前言 当我们向写好的通讯录程序中输入信息时&#xff0c;有时我们希望能保存输入的信息&#xff0c;不用每次打开这个程序都要重新输入&#xff0c;这时就…

文件操作详解(超级详细)

正常我们的程序在执行的时候程序结束后&#xff0c;会将所有数据清楚&#xff0c;那么我们应该如何保存数据呢&#xff1f;这里我们就需要用文件操作。 一、文件的打开和关闭 1.文件打开、关闭函数—fopen、fclose //打开文件 FILE * pf fopen ( const char * filename, const…

虚拟机安装黑苹果【虚拟机安装,黑苹果安装,黑苹果无法全屏问题】(这应该全网最全的资源了吧~)

一&#xff0c;资源下载 链接&#xff1a;https://pan.baidu.com/s/1cyGiDvkJinx8dnB57gO7UQ 提取码&#xff1a;i615 PS&#xff1a;里面有虚拟机资源&#xff0c;Drawin.ios文件和苹果镜像文件 这里只讲如何用虚拟机安装黑苹果&#xff0c;不讲如何安装虚拟机&#xff0c;下…

VMware虚拟机安装黑苹果10.15 || AMD R7 5800处理器

VMwar版本&#xff1a;16Pro 链接&#xff1a;https://pan.baidu.com/s/1qGHEynWSV4YS9WSNonxiuA?pwdazvh 提取码&#xff1a;azvh macOS链接&#xff0c;版本为Catalina 10.5。这个版本后&#xff0c;os安装包就过10G了&#xff0c;会特别卡。 链接&#xff1a;https://pan…

VMware16安装macOS10.15.1 - 黑苹果 - osx虚拟机

效果图 步骤 下载安装VMware&#xff0c;并且利用unlocker开启macos的支持VMware利用unlocker开启MacOS支持_Rudon滨海渔村的博客-CSDN博客效果步骤下载安装vmware16http://www.winwin7.com/soft/17946.html下载unlocker3.0 &#xff08;这里包括了darwin.iso和darwinPre15.is…

vm虚拟机15.5安装黑苹果maxos-10.14

鼎峰_小配针对vm虚拟机安装黑苹果maxos在学习和研究探索的过程中的一点点心得&#xff0c;从刚接触时的一脸懵逼&#xff0c;到后来慢慢的了解了&#xff0c;废话不多说&#xff0c;直接上干货。 一、需要准备的软件&#xff1a; a)解锁虚拟机MAC补丁&#xff1a;Unlocker 3.0…

图文详解如何在VMware Workstation11虚拟机上安装黑苹果Mac OS X 10.10系统

想要体验黑苹果系统当然要借助于VMware虚拟机了&#xff0c;那么下面大家就来看看亦是美网络小编的图文详解如何在VMware Workstation11虚拟机上安装黑苹果Mac OS X 10.10系统的教程吧&#xff01; 小编的安装环境&#xff1a; 实体机windows8.1专业版 VMware workstation 1…

win10上的VMware安装黑Mac(黑苹果、AMD)

使用AMD处理器的笔记本&#xff0c;在虚拟机上安装MAC操作系统。 本机安装配置&#xff1a; 华硕天选 AMD Ryzen 4800H 24G运存 Mac OS 10.13 High Sierra 1. 下载所需资源 所需资源下载链接&#xff1a; mac os 10.13镜像&#xff0c;其他工具 链接: https://pan.baidu.com/s/…

VMware虚拟机安装macOS黑苹果教程,亲测流程,全过程问题解决方案记录

先介绍流程,安装过程中遇到的问题都在最后列出并写出解决方案,找解决方案的直接到最后 准备: 1.VMware虚拟机 我的比较老,为VMware Workstation 14 Pro 14.1.3 build-9474260 2.unlocker 解锁VM的macOS系统 3.macOS的小白版cdr安装包(推荐)或者macOS的dmg安装包 4.如果…

Windows下VMmare黑苹果macOS Catalina 10.15虚拟机安装VMware tools工具

请先安装好macOS Catalina 10.15虚拟机。 VMware 10.15.5安装macOS Catalina 10.15请参考我的博客 Windows下VMware Workstations Pro15.5.0安装macOS Catalina 10.15虚拟机&#xff08;详细教程&#xff09; 如果VMware安装的虚拟机不安装VMware tools工具将无法全屏、进行虚…

Windows 10虚拟机Vmware 安装 黑苹果macos10.14

工具链接 提取码&#xff1a;zko1 VMware16.2.3安装 VMware16.2.3 连接手机有问题&#xff0c;改用 VMware15.5.6-16341506 流程: 虚拟机 MacOS系统解锁创建虚拟机安装macOS安装VMware tools 虚拟机 MacOS系统解锁 使用工具&#xff1a;Unlocker.7z 停止VM服务:停止所有VMwa…

黑苹果从入门到精通:最详细的VMware安装macOS教程

前言 不知为何&#xff0c;以前我发的两篇关于黑苹果的文章或没过审或被删除&#xff0c;最近SMZDM上有不少优质的黑苹果文章发出来&#xff0c;貌似禁令已开&#xff0c;前段时间在一篇写的很不错的黑果文章下吹牛说今年要写一个系列&#xff0c;故有了这篇文章作为系列的开头…

VMware虚拟机安装黑苹果MacOS Mojave系统详细教程

更多资源请百度搜索&#xff1a;前端资源网 欢迎关注我的博客&#xff1a;www.w3h5.com 大家好&#xff0c;我的主要更新渠道是自己搭建的博客&#xff0c;为了节省流量&#xff0c;我开了防盗链。。。所以其他平台可能会有图片不能显示的问题&#xff0c;请转至我的博客进行查…

给windows装个Mac黑苹果虚拟机

点击上方↑↑↑蓝字[协议分析与还原]关注我们 “ windows下安装使用苹果Mac虚拟机。” 平常的生活工作中&#xff0c;我大部分时候使用Windows&#xff0c;偶尔用用Mac。实在是用不惯Mac&#xff0c;但有的时候&#xff0c;有些工作还是需要在Mac上搞&#xff0c;不得不用&…

分享Win10虚拟机VMware安装黑苹果MacOS Sierra图文教程

虚拟机VMware安装黑苹果MacOS详细图文教程&#xff0c;安装也比较简单亿破姐这里使用的但是过程挺复杂了。 准备工作 &#xff08;1&#xff09;虚拟机 VMware Workstation Pro &#xff08;2&#xff09;解锁虚拟机MAC补丁 Unlocker &#xff08;3&#xff09;苹果系统懒人…

使用VmWare安装黑苹果系统

目录 1.介绍2.破解安装VMware3.unlocker解锁虚拟机3.1 关闭VMware相关的进程3.2 执行安装命令 4.VmWare创建虚拟机5. 下载并配置镜像以及虚拟机设置5.1 修改镜像5.2 修改虚拟机安装路径文件内容 6. 选择镜像启动虚拟机7.安装macOS系统7.1 开启此虚拟机7.2 选择语言->简体中文…

VMware虚拟机安装黑苹果步骤与常见问题,VMware16,MacOS12.01(Moterey)

资源准备&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1JFtpMVrULiky9l3SvCXX-w 提取码&#xff1a;c452 说明&#xff1a; 1.镜像版本10.14和12.01根据需要选择其一即可&#xff0c;10.14的后缀为cdr&#xff0c;12.01的后缀为ISO&#xff0c;这两种文件VMware都支…

在VM虚拟机上装“黑苹果

如何在VM虚拟机上装“黑苹果” 一: 装机所需 安装过程 一: 装机所需 1、windows7/10.&#xff08;本次使用windows10&#xff09; 2、 VMware workstation Pro 3 、MAC系统镜像(本次使用的是10.14) 4、 unlocker-master(将mac的文件装入VM) 安装过程 1.创建新的虚拟机 2.…

【系统】VMware虚拟机安装黑苹果系统macOS 12.5详细步骤

虽然我更喜欢Windows系统&#xff0c;但有些情况下需要Mac运行某些软件或脚本&#xff0c;又不好意思到处借电脑&#xff0c;这时候只需要在虚拟机运行一下就可以了。之前有分享过macOS.Catalina.10.15安装教程&#xff0c;时隔多年&#xff0c;这次分享的是较新的macOS.Monter…