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

做服装招聘的网站国外网站代做

做服装招聘的网站,国外网站代做,网上请人做软件的网站,wordpress主题不一样前言 本专题将基于Linux操作系统来带领大家学习操作系统方面的知识以及学习使用Linux操作系统。前面我们认识了Linux的各种指令以及工具#xff0c;并且学习了进程的相关知识#xff0c;那么接下来让我们进入新的章节#xff0c;学习新的内容。本章我们要学习的是——基础文… 前言 本专题将基于Linux操作系统来带领大家学习操作系统方面的知识以及学习使用Linux操作系统。前面我们认识了Linux的各种指令以及工具并且学习了进程的相关知识那么接下来让我们进入新的章节学习新的内容。本章我们要学习的是——基础文件IO。 本节重点 复习C语言⽂件IO相关操作认识⽂件相关系统调⽤接⼝认识⽂件描述符,理解重定向对⽐fd和FILE理解系统调⽤和库函数的关系理解重定向操作 1. 理解“文件” 1.1 一般角度 狭义上来说文件是存储在磁盘上的数据而磁盘内保存的数据与内存中不同磁盘是永久性存储介质当我们拔掉电源后磁盘上的数据不会消失因此文件在磁盘上的存储是永久性的。 我们知道磁盘也是外设它既是输出设备也是输入设备。因此我们对于文件的操作本质上是对外设的输入和输出简称IO。 对于文件的理解还有一个角度叫做Linux下一切皆文件在Linux系统中像键盘、显示器、网卡、磁盘等等都是文件Linux把各种硬件也都当作了文件。至于是如何实现的后面再讲 我们知道文件中不单单只有文件内容文件是文件属性元数据和文件内容的集合文件 属性元数据 内容因此对于大小为0KB的空文件也是有大小的会占用一定的磁盘空间。因此我们对文件的操作本质上是操作文件内容和操作文件属性两方面。 1.2 系统角度 我们知道要想访问一个文件首先我们需要先“打开”文件那么是谁去打开文件呢在操作系统中实际上是由进程去打开文件因此对文件的操作本质上是进程对文件的操作。 文件都保存在磁盘上而磁盘的管理者是操作系统也就是说文件的管理者是操作系统那么操作系统对于被打开的文件会进行管理管理的方法与进程的管理是一致的都是先描述再组织。具体的管理方法下面会讲 我们在之前学习C/C的时候包括其他的语言都可以通过相关接口去对文件进行操作。例如在C语言/C中我们可以使用对应的库函数去创建文件、修改文件等等。不过文件的读写本质其实不是通过这些库函数来操作的而是通过在库函数中调用文件相关的系统调用接口来实现的。像C语言中的fopen、fwrire等库函数都封装了底层OS的文件系统调用。 2. 回顾C语言文件接口 既然是讲文件操作那让我们回顾一下之气在C语言中学习的文件操作因为Linux的底层就是用C语言来实现的。 2.1 C中的读写操作 在C语言中我们如果想对文件进行操作首先要使用fopen函数打开对应的文件并且通过传递不同的参数来确定以什么样的权限来打开文件。 这里我们使用的函数都是库函数。 这些都是我们之前学习过的我们简单介绍一下即可。 首先是两个参数 path path可以是相对路径就是以当前进程所在的路径之前我们在讲解进程时讲过进程的PCB中包含着一个cwd也就是该进程当前的工作路径。所以我们可以直接输入文件名这样查找文件和创建文件都是在cwd所对应的路径下进行的。 打开⽂件本质是进程去打开文件。由于进程知道⾃⼰在哪⾥即便⽂件不带路径进程也知道。由此OS就能知道要创建的⽂件放在哪⾥。 此外path还可以直接写绝对路径。 mode r只读模式打开文件进行读取。如果文件不存在返回 NULL。w只写模式打开文件进行写入。如果文件已存在会将文件内容清空如果文件不存在则会创建新文件。a追加模式打开文件进行写入。如果文件存在数据会被追加到文件末尾如果文件不存在则会创建新文件。r读写模式打开文件进行读取和写入。如果文件不存在返回 NULL。w读写模式打开文件进行读取和写入。如果文件存在文件内容会被清空如果文件不存在则会创建新文件。a读写模式打开文件进行读取和写入。如果文件存在数据会被追加到文件末尾如果文件不存在则会创建新文件。b二进制模式。在文件操作时以二进制形式打开文件。例如rb 表示以二进制方式读取文件wb 表示以二进制方式写入文件。 而它的返回值类型FILE*是结构体指针它代表一个已经打开了的文件并持有有关这个文件的所有信息。至于该类型的具体含义我们下面再说。 我们以相应的权限打开文件后就可以进行相应的读写操作了这里又需要用到两个库函数分别是fread和fwrite。它们用于读文件和写文件我们简单的回顾一下 fwrite 功能 向文件中写入二进制数据。 参数说明 ptr指向要写入数据的内存缓冲区的指针size每个数据项的字节大小nmemb要写入的数据项个数stream文件指针 返回值 实际成功写入的数据项个数 一个简单的代码示例 #include stdio.h #include stdlib.hint main() {FILE *file;int numbers[] {1, 2, 3, 4, 5};// 写入数据file fopen(data.bin, wb);if (file ! NULL) {size_t written fwrite(numbers, sizeof(int), 5, file);printf(写入了 %zu 个整数\n, written);fclose(file);}return 0; }fread 功能 从文件中读取二进制数据。 参数说明 ptr指向存储读取数据的内存缓冲区的指针size每个数据项的字节大小nmemb要读取的数据项个数stream文件指针 返回值 实际成功读取的数据项个数。 一个简单的代码示例我们从上面写入的文件中读出数据 #include stdio.h #include stdlib.hint main() {FILE *file;int read_numbers[5];// 读取数据file fopen(data.bin, rb);if (file ! NULL) {size_t read fread(read_numbers, sizeof(int), 5, file);printf(读取了 %zu 个整数\n, read);for (int i 0; i read; i) {printf(%d , read_numbers[i]);}printf(\n);fclose(file);}return 0; }这里需要注意的是当我们对一个文件连续调用fread()读取文件时并不会从头开始读这是因为文件指针的位置是自动向前移的也就是说每次调用 fread() 后文件指针 FILE* 会自动移动到读取数据的末尾处下一次再调用 fread() 时就会从上次读取完的位置继续往后读。 这是因为当我们用 fopen() 打开一个文件时系统为你创建了一个文件指针FILE* 类型它其实是一个结构体它内部维护了一个“当前位置”文件偏移量的变量 第一次读取时从文件开头读取每次读取完数据后偏移量自动向前移动所以不会重复读相同位置 我们可以通过使用 rewind() 或 fseek() 函数去改变文件偏移量 rewind用于将文件指针重置到开头。 rewind(FILE *stream); //stream为需要重置的文件指针fseek用于手动控制文件指针的位置。 fseek(FILE *stream, long offset, int whence); //stream为需要设置的文件指针 //offset为偏移量单位为字节 //whence为基准值也就是从哪个位置偏移whence 有三个取值定义在 stdio.h 中 常量含义SEEK_SET从文件开头开始偏移SEEK_CUR从当前位置偏移SEEK_END从文件末尾开始偏移 注意事项 fread 和 fwrite 是按块block读写适合处理结构体、数组等二进制数据。返回值是成功读/写的块数不是字节数要用它判断操作是否成功。文件必须以 rb / wb 模式打开否则可能会出错或产生不可预期行为。对文本文件请使用 fprintf / fscanf不要用 fwrite / fread。 2.2 标准输入输出流 我们先来认识一下什么是流大家可能一直听过各种流但流究竟是什么呢 在 C 语言中“流”stream指的是数据的有序传输通道用于在程序和输入/输出设备如文件、终端、网络之间进行数据传输。 简单来说流是你和外部世界之间的桥梁数据像水一样通过这条“流”流进来或流出去。 在 C 标准库中 不直接操作“文件”或“终端”而是操作一种抽象对象FILE*流指针你使用 fopen() 打开一个文件实际上系统为你创建了一个流对象指针 在 C 语言中“流”是你与文件、终端等设备交换数据的通用通道用来隐藏底层设备差异统一进行读写操作。 我们平常往显示器上输出信息实际上就是往标准输出流中进行写入标准输出流一般就是显示器文件。 当我们在执行C程序时C会默认打开三个输入输出流 分别是stdin、stdout、stderr观察可以发现它们的类型都是FILE而fopen的返回值类型也是FILE*也就是说它们其实都是一个个被打开的文件。 名称类型默认连接的设备用途stdin输入流键盘接收输入stdout输出流屏幕终端打印正常输出内容stderr输出流屏幕终端打印错误或调试信息 为什么这三个文件流会默认打开呢 因为这三个标准流是所有程序与“外部世界”交互的最基本通道C语言运行时会自动打开它们这样你的程序就能立即读入数据、打印输出、报告错误无需手动处理底层设备逻辑。如果这三个流不自动打开程序连最基本的输入输出都做不了——你必须自己用 open() 或 fopen() 打开终端设备很麻烦。 那么我们如果想将信息输出到显示器上就可以通过多种不同的方法了 #include stdio.h #include string.h int main() {const char *msg hello fwrite\n;fwrite(msg, strlen(msg), 1, stdout);printf(hello printf\n);fprintf(stdout, hello fprintf\n);return 0; }这些是我们之前学习C语言时学习过的有关文件方面的知识我们进行了简单的回顾下面让我们进入新的学习环节。 3. 系统文件IO 打开⽂件的⽅式不仅仅是fopenifstream等语⾔层的⽅案其实它们的底层都是通过系统调用去打开⽂件我们这里主要讲解一下Linux系统下的系统调用。不过在学习系统⽂件IO之前先要了解下如何给函数传递标志位该⽅法在系统⽂件IO接⼝中会使⽤到。 3.1 标志位 给函数传递标志位也就是通过给函数传入特定的参数使其执行特定的功能。而这个功能的实现我们一般采用位图加宏的方式例如下面的代码 #include stdio.h#define ONE 0001 //0000 0001 #define TWO 0002 //0000 0010 #define THREE 0004 //0000 0100void func(int flags) {if (flags ONE) printf(flags has ONE! );if (flags TWO) printf(flags has TWO! );if (flags THREE) printf(flags has THREE! );printf(\n); } int main() {func(ONE);func(THREE);func(ONE | TWO);func(ONE | THREE | TWO);return 0; }如上面的代码所示我们通过位操作来实现通过传递不同的参数使函数执行不同的功能。简单解释一下上面的代码我们将不同的标志位定义为ONE、TWO、THREE当我们传入ONE时在函数内部只有flag ONE的结果为真因此只会执行该代码块内的代码而当我们传入ONE | WTO时在函数内部有flag ONE和flag TWO的结果为真所以会执行这两个代码块中的代码其他类似。 在C语言中像fopen、fclose、fread、fwrite这些库函数在底层实际上是封装了系统调用在Linux系统中这些系统调用分别是open、close、read、write下面让我们来认识一下这些系统调用接口。 3.2 文件系统调用 有了上面标志位的介绍下面让我们来看一看Linux中关于文件操作的系统调用 3.2.1 open 在 Linux 系统中open() 是一个用于打开或创建文件或设备的系统调用它返回一个文件描述符file descriptor后面详将供后续的 read()、write()、close() 等函数使用。 参数说明 pathname 要打开的文件路径如 file.txt、/dev/sda flags标志位指定打开方式常见的值如下表所示 宏名含义O_RDONLY只读O_WRONLY只写O_RDWR读写O_CREAT文件不存在则创建O_TRUNC文件存在则清空内容O_APPEND每次写入都追加到文件末尾O_EXCL和 O_CREAT 一起用确保文件不存在O_NONBLOCK非阻塞打开如设备或管道 mode权限位仅当使用 O_CREAT 创建文件时使用指定新文件的权限。 例如 open(log.txt, O_WRONLY | O_CREAT, 0644);表示 以只写方式打开 log.txt如果文件不存在就创建它新文件的权限为 rw-r--r-- 也就是说当我们在C语言中使用fopen打开文件时如果我们打开文件的权限设为w那么在fopen的底层实现中实际上是调用了open这个系统调用并且给它传入的flags为O_WRONLY | O_CREAT | O_TRUNC如果打开文件的权限为’a’那么传入的flags为O_WRONLY | O_CREAT | O_APPEND。当我们传入的标志位中如果有O_CREAT 那么我们就需要在传入一个参数mode也就是权限位指定创建新文件的权限。 函数具体使⽤哪个和具体应⽤场景相关如⽬标⽂件不存在需要open创建则第三个参数表⽰创建⽂件的默认权限,否则使⽤两个参数的open。 open成功执行返回值是新打开文件的文件描述符后面详将如果失败则返回-1。 C 语言不支持函数重载但 open() 有两个同名版本它是怎么做到的 这是不是 C 语言函数重载而是函数的可变参数机制变参 宏 Linux 的 open() 实际在源码中定义如下 int open(const char *pathname, int flags, ...);它用的是 C 语言中的变参...语法。这个机制允许传入 可选的第三个参数即 mode_t mode用于在创建文件时指定权限。 这是 C 语言中通过 ...变参实现“伪重载”的一种技巧。 随着Linux的发展open() 曾经是系统调用但在现代 Linux 中已演进为库函数它通过调用 openat() 系统调用来实现功能。这是 Linux 系统 API 演进的典型例子——保持接口兼容性的同时底层实现更强大、更安全。从严格的技术角度现在不应该说 open() 是系统调用它是库函数。但由于历史习惯和使用体验相同很多文档和程序员仍然这样称呼在这里我们还是先称其为系统调用因为其的确是我们fopen的底层调用。准确的说法是“open() 是对 openat() 系统调用的包装”。 3.2.2 colse close这个系统调用就相对简单它的作用就是用于关闭一个打开的文件描述符fd它的返回值成功返回0失败返回-1并设置errno。 close是fclose的底层调用由于我们现在还并不了解什么是文件描述符所以先了解一下即可。 3.2.3 read read() —— 从文件描述符中读取数据 参数说明 fd文件描述符由 open()、socket() 等返回buf数据缓冲区指针读入的数据存放在这里count最多读取的字节数 返回值 成功返回实际读取的字节数 count遇到文件结尾EOF返回 0失败返回 -1并设置 errno read是fread的底层调用所以它们的参数是比较相似的不同的在于我们使用fread读取文件的时候我们需要的从哪个文件流中读取而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(myfile, O_RDONLY);if(fd 0){perror(open);return 1;} const char *msg hello bit!\n;char buf[1024];while(1){ssize_t s read(fd, buf, strlen(msg));if(s 0){printf(%s, buf);}else{break;}} close(fd);return 0; }3.2.4 write write() —— 向文件描述符写入数据 参数说明 fd文件描述符buf要写的数据缓冲区指针count写入的字节数 返回值 成功返回实际写入的字节数可能 count失败返回 -1并设置 errno write是fwrite的底层调用。read和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);int fd open(myfile, O_WRONLY|O_CREAT, 0644);if(fd 0){perror(open);return 1;} int count 5;const char *msg hello bit!\n;int len strlen(msg);while(count--){write(fd, msg, len);//fd: 后⾯讲 msg缓冲区⾸地址 len: 本次读取期望写⼊多少个字节的数据。 返回值实际写了多少字节数据} close(fd);return 0; }read() 和 write() 是 Linux 中最基本、最通用的系统调用它们直接操作文件描述符支持各种 I/O 对象包括文件、设备、socket 等是一切高级 I/O 的基础。 3.3 文件描述符 前面我们认识文件操作的系统调用时我们发现这些系统调用都和一个称作文件描述符的整数有关就跟我们文件操作的库函数中的文件流FILE*指针一样。那么文件描述符到底是什么呢在回答这个问题之前我们先回顾一下刚开始所说的东西。 我们知道操作系统不仅要管理我们的进程还需要管理被打开的文件。我们知道对文件操作的本质实际上进程对文件进行操作那么在一个进程中我们可以打开很多个文件那么操作系统就需要对这些打开的文件进行管理因此在我们进程的PCB中就存在一个*files指针它的类型是files_struct的结构体在这个结构体中包含着当前进程所打开的文件的一些信息其中包含一个指针数组它的类型是file*对应着一个个文件对象每打开一个对象操作系统就会创建一个对应的file结构体对象里面存放了文件相关的inode元信息。 而我们的文件描述符其实就是上面我们所说的指针数组的下标下面我们通过图示来理解一下 所以我们所说的文件描述符其实就是fd_array[]数组的下标当我们程序运行的时候系统会默认打开三个文件分别是stdin、stdout、stderr三个文件它们也刚好对应了fd_array[]数组的前三个元素因此它们所对应的文件描述符就是0、1、2。那么我们也就知道了在C语言中的FILE结构体中一定封装了文件描述符fd。 ⽽现在知道⽂件描述符就是从0开始的⼩整数。当我们打开⽂件时操作系统在内存中要创建相应的数据结构来描述⽬标⽂件。于是就有了file结构体。表⽰⼀个已经打开的⽂件对象。⽽进程执⾏open系统调⽤所以必须让进程和⽂件关联起来。每个进程都有⼀个指针*files, 指向⼀张表files_struct,该表最重要的部分就是包含⼀个指针数组每个元素都是⼀个指向打开⽂件的指针所以本质上⽂件描述符就是该数组的下标。所以只要拿着⽂件描述符就可以找到对应的⽂件。 文件描述符的分配规则 我们通过代码来看 #include stdio.h #include sys/types.h #include sys/stat.h #include fcntl.h int main() {int fd open(myfile, O_RDONLY);if(fd 0){perror(open);return 1;}printf(fd: %d\n, fd);close(fd);return 0; }我们可以看到结果是fd3。那么关闭文件描述符0呢 #include stdio.h #include sys/types.h #include sys/stat.h #include fcntl.h int main() {close(0);int fd open(myfile, O_RDONLY);if(fd 0){perror(open);return 1;}printf(fd: %d\n, fd);close(fd);return 0; }发现是结果是 fd: 0 。可⻅⽂件描述符的分配规则在files_struct数组当中找到当前没有被使⽤的最⼩的⼀个下标作为新的⽂件描述符。 说了那么多接下来让我们验证一下我们上面所说的是否正确我们在Linux的内核源码中去寻找一下答案 在操作系统接口层面它们只认fd也就是文件描述符。那么为什么会存在文件描述符呢这是我们Linux系统层面的概念C语言的FILE结构体中只是封装了fd其实不论是C语言也好C、java也罢它们都有自己的文件操作接口这些接口的底层其实都调用的是系统接口这是为了方便我们使用这些语言的可移植性试想我们在Linux中使用C语言写了一个程序里面调用了Linux的系统调用那么当我们把这个程序在windows下去执行就会发生错误毕竟windows有自己的系统调用它并不认识Linux的系统调用。我们使用的这些语言它们在每个系统上都有属于该系统对应的库文件它们确保了我们在使用库函数的时候可以根据系统的不同去调节库函数底层实现的具体细节这样一来我们写的程序便可以在不同的系统上运行便具有了可移植性。 4. 重定向 当我们认识了文件描述符后我们就可以对重定向操作进行解释了。我们先来看一段代码 #include stdio.h #include sys/types.h #include sys/stat.h #include fcntl.h #include stdlib.h int main() {close(1);int fd open(myfile, O_WRONLY|O_CREAT, 00644);if(fd 0){perror(open);return 1;} printf(fd: %d\n, fd);fflush(stdout);close(fd);exit(0); }上述代码中我们先关闭了文件描述符1也就是标准输出stdout这样一来我们新打开的文件myfile的文件描述符是1运行该程序我们发现本来应该输出到显⽰器上的内容输出到了⽂件 myfile 当中其中fd1。这种现象叫做输出重定向。 那么重定向的本质是什么呢 因此重定向的本质实际上就是把对某个文件的操作通过改变文件描述符指向的内容从而改变操作的文件。这个过程是通过dup2系统调用来实现的 它的作用就是把 oldfd 的文件指针复制给 newfd替换 newfd 的原内容。 下面我们来看一下具体示例 输出重定向 #include fcntl.h #include unistd.h #include stdio.hint main() {int fd open(out.txt, O_WRONLY | O_CREAT | O_TRUNC, 0644);if (fd 0) {perror(open);return 1;}dup2(fd, 1); // 标准输出 → out.txtclose(fd); // fd 已不再需要printf(Hello, world!\n); // 实际写入到 out.txtreturn 0; }输入重定向 #include fcntl.h #include unistd.h #include stdio.hint main() {int fd open(input.txt, O_RDONLY);if (fd 0) {perror(open);return 1;}dup2(fd, 0); // 标准输入 ← input.txtclose(fd);char buf[128];fgets(buf, sizeof(buf), stdin); // 从 input.txt 读取printf(Read: %s, buf);return 0; }追加重定向 #include fcntl.h #include unistd.h #include stdio.hint main() {int fd open(log.txt, O_WRONLY | O_CREAT | O_APPEND, 0644);if (fd 0) {perror(open);return 1;}dup2(fd, 2); // 标准输出 → 追加到 log.txtclose(fd);printf(Appended line\n); // 会追加而不是覆盖return 0; }像我们的printf函数我们知道它是在终端上打印相应的内容实际上它的底层是向文件描述符为1的文件中写入而在C语言中声明的stdin、stdout、stderr实际上文件描述符为0、1、2的文件流也就是说它们对应的文件描述符而不是对应的文件我们可以通过更改文件描述符使其代表的变为其他文件。 因此我们在终端中的重定向操作实际上是通过dup2系统调用和文件的打开权限一同完成的。 尾声 本章讲解就到此结束了若有纰漏或不足之处欢迎大家在评论区留言或者私信同时也欢迎各位一起探讨学习。感谢您的观看
http://www.w-s-a.com/news/461020/

相关文章:

  • 购物网站修改注册信息模块的分析怎么注册公司logo
  • 那个网站可以做域名跳转的青岛网站建设定制
  • 网站登记模板互联网技术发展及其影响的调查
  • 北京专业的网站建设西安企业家名单
  • 移动网站开发服务器丰都集团网站建设
  • 网站开发逻辑图烫画图案设计网站
  • 客户管理系统哪找公司网站如何做优化
  • 常德企业网站建设广州站在哪里
  • 移动端网站建站视频教程网站如何做淘客
  • 注册网站会不会有风险网站建设实训致谢语
  • ssh框架做的家政服务网站需要做网站建设的公司
  • 众筹网站制作长春高端网站建设
  • 亳州网站网站建设wordpress汉化.po
  • 怎样给建设的网站提意见网红营销概念
  • 怎么知道一个网站是谁做的广告行业网
  • 上海app定制开发公司大城网站优化
  • 工厂 网站建设北京招聘网站设计师
  • 企业网站建设与网络营销的关系网页qq音乐在线听
  • 网站如何制作学校的做做代销的网站
  • 灌云网站建设维护常州市天宁区建设局网站
  • 广州中小企业网站建设网络营销平台的类型
  • 做非遗网站的原因wordpress ip 插件
  • 微信企业网站 源码下载wordpress 4.9.5 太卡
  • 湖北网站建设公司哪家好房地产最新政策调整
  • 重庆建设岗位培训网站今天重大新闻乌克兰
  • 流水线 东莞网站建设如何在网上销售产品
  • 哪些做图片赚钱的网站网站建设销售业绩任务
  • 建立网站 知乎如何做网站的图片滑动块
  • 国外做珠宝的网站有哪些滨湖区建设局官方网站
  • 关于中国幼教网站开发的经验中国建设银行晋中分行网站