文章目录

  • 一、系统调用
    • 什么是系统调用:
    • 用户态到内核态切换途径方式
    • 普通函数调用与系统调用的区别:
      • 普通函数调用的步骤:
      • 系统调用的步骤:
  • 二、一切皆文件
  • 三、文件描述符
    • 什么是文件描述符:
    • 文件描述符与文件指针:
  • 四、文件的创建与打开
    • 问题1:C语言可以定义重名函数吗?
    • 问题2:系统调用为什么可以重名?
    • 问题3:r,w,a,r+,w+,a+分配对应哪些flags标志?
  • 五、文件读写
  • 六、系统IO与标准IO
  • 七、文件位置指针

一、系统调用

什么是系统调用:

​ 由操作系统向应用程序提供的程序接口信息,也叫应用编程接口(Application Programming Interface,API),它是是应用程序与操作系统之间交互的接口。

​ 操作系统的主要功能是为管理硬件资源和为应用程序开发人员提供良好的环境,使应用程序具有更好的兼容性,为了达到这个目的,内核提供了一系列具备了一定功能的内核函数,通过一组称为系统调用(system call)的接口呈现给用户。

​ 系统调用负责把应用程序的请求传给内核,调用相应的内核函数完成所需的处理,然后将处理结果返回给应用程序。

​ UNIX/Linux大分部的系统功能是通过系统调用实现的,这些系统调用被封装成了C函数的形式,但它们并不是真正的函数。

​ 标准库函数大部分工作在用户态,一部分函数会使用系统调用进入内核态(fopen/malloc),可以使用 time命令统计程序的在用户态和内核态的运行时间:

time ./<可执行文件>
real    0m0.002s    # 总执行时间
user    0m0.000s    # 用户态执行时间
sys     0m0.000s    # 内核态执行时间
总执行时间 = 用户态执行时间 + 内核态执行时间 + 用户态和内核态切换消耗的时间strace ./可执行文件名    # 追踪函数的调用过程

用户态到内核态切换途径方式

操作系统一般是通过中断来从用户态切换到内核态的。中断一般有两个属性,一个是中断号,一个是中断处理程序。不同的中断有不同的中断号,每个中断号都对应了一个中断处理程序。在内核中有一个叫中断向量表的数组来映射这个关系。当中断到来时,cpu会暂停正在执行的代码,根据中断号去中断向量表找出对应的中断处理程序并调用。中断处理程序执行完成后,会继续执行之前的代码。

中断分为硬件中断和软件中断,我们这里说的是软件中断,软件中断通常是一条指令,使用这条指令用户可以手动触发某个中断。中断号是有限的,所有不会用一个中断来对应一个系统调用(系统调用有很多)。Linux2.5之前(具体哪个版本不太清楚)下用int 0x80触发所有的系统调用,那如何区分不同的调用呢?对于每个系统调用都有一个系统调用号,在触发中断之前,会将系统调用号放入到一个固定的寄存器,0x80对应的中断处理程序会读取该寄存器的值,然后决定执行哪个系统调用的代码。

0x80指令会让cpu陷入中断,执行对应的0x80中断处理函数。不过在这之前,cpu还需要进行栈切换,即就是ESP寄存器的值所指向的栈。

中断处理程序除了系统调用(0x80)还有如除0异常(0x00)、缺页异常(0x14)等等

主要分为几步:

1.保存各种寄存器

2.根据系统调用号执行对应的系统调用程序,将返回结果存入到eax中

3.恢复各种寄存器

普通函数调用与系统调用的区别:

普通函数调用的步骤:

​ 1、调用者会先把要传递的参数压入栈内存

​ 2、根据函数名也就是函数地址跳转到函数所在的代码段位置

​ 3、接下来从栈内存中弹出参数

​ 4、定义局部变量扩展栈内存并执行函数中的相关代码

​ 5、返回执行结果

​ 6、销毁该函数的栈内存

​ 7、回到调用处继续执行

系统调用的步骤:

​ 1、程序中执行到系统调用位置,触发软件中断机制

​ 1、通过软中断机制进入内核运行状态

​ 2、然后内核负责把参数从用户空间拷贝到内核空间

​ 3、然后根据中断编号再执行相关操作

​ 4、等执行完毕后,再把执行结果内核空间拷贝到用户空间

​ 5、返回到程序再继续执行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mCzotxC9-1665314898629)(C:\Users\DELL\Pictures\中断.jpg)]

二、一切皆文件

​ 在UNIX和Linux系统下,把操作系统提供的服务和设备都抽象成了文件,因为这样可以给各种设备控制提供了一个简单而统一的接口,程序完全可以象访问普通磁盘文件一样,访问串行口、网络、打印机或其它设备。

​ 在UNIX和Linux系统下中的文件具有特别重要的意义,因为它在Linux中,(几乎)一切皆文件,大多数情况下只需要使用五个基本系统调用 open/close/read/write/ioctl,即可实现对各种设备的输入和输出,Linux中的任何对象都可以被视为某种特定类型的文件,可以访问文件的方式访问之。

    1. 目录文件
    1. 设备文件
    • A. 控制台:/dev/console
    • B. 声卡:/dev/audio
    • C. 标准输入输出:/dev/tty
    • D. 空设备:/dev/null
    1. 普通文件

三、文件描述符

什么是文件描述符:

​ 文件描述符是一种非负的整数,表示一个打开的文件,由系统调用(open/creat)返回,在后续操作文件时可以被内核空间引用,内核默认为每个进程打开三个文件描述符:

  • stdin 0 - 标准输入

  • stdout 1 - 标准输出

  • stderr 2 - 标准出错

在unistd.h中被定义为如下三个宏:

#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2

一般来说,我们打开文件后占用一个文件描述符3(0、1、2已被标准文件描述符占用),下一个则是4(如果它没被占用的话)…

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>int main() {// int open(const char *pathname, int flags);//     参数://         - pathname:要打开的文件路径//         - flags:对文件的操作权限设置还有其他的设置//           O_RDONLY,  O_WRONLY,  O_RDWR  这三个设置是互斥的//     返回值:返回一个新的文件描述符,如果调用失败,返回-1// 打开或创建一个文件int fd1 = open("temp.txt", O_RDONLY | O_CREAT);if(fd1 == -1) {perror("open");return -1;}int fd2 = open("temp.txt", O_RDONLY );if(fd2 == -1) {perror("open");return -1;}printf("fd1: %d\n", fd1);printf("fd2: %d\n", fd2);// 关闭文件描述符close(fd1);close(fd2);return 0;
}

运行结果:

我们观察上述代码可以发现:同一个进程的不同文件描述符可以指向同一个文件。

同时,当我们复制该会话(相当于打开了一个新进程),再运行该程序:

发现fd1 = 3 和 fd2 = 4,这表明:不同进程可以拥有相同的文件描述符。

进而,不同进程的不同文件描述符也可以指向同一个文件。

文件描述符与文件指针:

​ 在Linux系统中打开文件后,内存中(内核区间)就会有一个内核对象,也就是记录该文件相关信息的结构体变量,但内核为了自己的安全不能把它的地址返回给用户,而且由于内核区间和用户区间的原因,返回也无法访问、使用。

​ 而且一个进程可能会同时打开多份文件,所以操作系统就在内核区间创建了一张索引表,表的每一项都有一个指向已打开文件的内核对象,文件描述符就是索引表的主键,如果把索引表看作数组,那么文件描述符就是数组的下标,不同进程之间交换文件描述没有意义。

​ C语言中使用文件指针代表打开的文件,文件指针指向进程的用户区间中的一个被称为FILE结构的数据结构。FILE结构包括一个缓冲区和一个文件描述符。而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是文件描述符。

int fileno(FILE *stream);
功能:把文件指针转换成文件描述符FILE *fdopen(int fd, const char *mode);
功能:把文件描述符转换成文件指针

四、文件的创建与打开

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags);
功能:打开文件
pathname:文件路径
flags:打开文件的方式
返回值:文件描述符,失败返回负值int open(const char *pathname, int flags, mode_t mode);
功能:打开或创建文件
pathname:文件路径
flags:打开方式
mode:创建文件时的权限
返回值:文件描述符,失败返回负值int creat(const char *pathname, mode_t mode);
功能:专门用来创建文件,但基本不使用,因为open函数完全具备它的功能。注意:open/creat所返回的一定是当前未被使用的,最小文件描述符。
一个进程可以同时打开的文件描述符个数,受limits.h中定义的OPEN_MAX宏的限制,POSIX要求不低于16,传统UNIX是63,现代Linux是255。flags:O_APPEND 打开文件后位置指针指向末尾O_CREAT 文件不存在时创建O_RDONLY 只读权限O_WRONLY 只写权限O_RDWR 读写权限O_TRUNC 清空文件内容O_EXCL 如果文件存在则创建失败O_NOCTTY 若pathname指向控制终端,则不将该终端作为控制终端。O_NONBLOCK 若pathname指向FIFO/块/字符文件,则该文件的打开及后续操作均为非阻塞模式。O_SYNC   write等待数据和属性,被物理地写入底层硬件后再返回。O_DSYNC  write等待数据,被物理地写入底层硬件后再返回。O_RSYNC read等待对所访问区域的所有写操作,全部完成后再读取并返回。O_ASYNC   当文件描述符可读/写时,向调用进程发送SIGIO信号。
mode:S_IRWXU  00700S_IRUSR  00400S_IWUSR  00200S_IXUSR  00100   //uesrS_IRWXG  00070 S_IRGRP  00040S_IWGRP  00020S_IXGRP  00010   //groupS_IRWXO  00007S_IROTH  00004S_IWOTH  00002S_IXOTH  00001   //other
/*
Linux 文件的 ugo 权限把对文件的访问者划分为三个类别:文件的所有者、组和其他人。所谓的 ugo 就是指 user(也称为 owner)、group 和 other 三个单词的首字母组合。文件的所有者
文件的所有者一般是创建该文件的用户,对该文件具有完全的权限。在一台允许多个用户访问的 Linux 主机上,可以通过文件的所有者来区分一个文件属于某个用户。当然,一个用户也无权查看或更改其它用户的文件。文件所属的组
假如有几个用户合作开发同一个项目,如果每个用户只能查看和修改自己创建的文件就太不方便了,也就谈不上什么合作了。所以需要一个机制允许一个用户查看和修改其它用户的文件,此时就用到组的概念的。我们可以创建一个组,然后把需要合作的用户都添加都这个组中。在设置文件的访问权限时,允许这个组中的用户对该文件进行读取和修改。其他人
如果我想把一个文件共享给系统中的所有用户该怎么办?通过组的方式显然是不合适的,因为需要把系统中的所有用户都添加到一个组中。并且系统中添加了新用户该怎么办,每添加一个新用户就把他添加到这个组中吗?这个问题可以通过其他人的概念解决。在设置文件的访问权限时,允许其他人户对该文件进行读取和修改。
*/int close (int fd);
功能:关闭文件,成功返回0,失败返回-1

问题1:C语言可以定义重名函数吗?

​ 可以,但需要在不同的作用域下才可以重名。

​ 情况1:在不同的源文件中,static函数可以与普通函数重名。

​ 情况2:在函数内定义的函数可以与普通函数重名。

问题2:系统调用为什么可以重名?

​ 因为系统调用不是真正的函数,而是借助软中断实现的,决定执行哪个系统调用的是中断编号,而不是名字。

问题3:r,w,a,r+,w+,a+分配对应哪些flags标志?

"r"        O_RDONLY
"r+" O_RDWR
"w"       O_WRONLY|O_CREAT|O_TRUNC, 0666
"w+" O_RDWR|O_CREAT|O_TRUNC, 0666
"a"       O_WRONLY|O_CREAT|O_APPEND, 0666
"a+" O_RDWR|O_CREAT|O_APPEND, 0666
/*
r:以只读的方式打开文本文件,文件必须存在;w:以只写的方式打开文本文件,文件若存在则清空文件内容从文件头部开始写,若不存在则根据文件名创建新文件并只写打开;a:以只写的方式打开文本文件,文件若存在则从文件尾部以追加的方式开始写,文件原来存在的内容不会清除(除了文件尾标志EOF),若不存在则根据文件名创建新文件并只写打开;r+:以可读写的方式打开文本文件,文件必须存在;w+:以可读写的方式打开文本文件,其他与w一样;a+:以可读写的方式打开文本文件,其他与a一样;若打开二进制文件,可在后面加个b注明,其他一样,如rb,r+b(或rb+)。
*/

五、文件读写

ssize_t write(int fd, const void *buf, size_t count);
功能:写入文件内容
fd:文件描述符
buf:要写入的数据的内存首地址
count:要写入的字节数
返回值:成功写入的字节数ssize_t read(int fd, void *buf, size_t count);
功能:读取文件内容
buf:存储数据的内存首地址
count:想读取的内存字节数
返回值:成功读取到的字节数注意:它们与标准C的fwrite/fread很像,但更纯粹。

练习:以二进制形式写入1000000个整数到文件中,分别用标准文件读写和系统文件读写来完成,比较它们谁的速度更快,为什么?

// 标准IO
#include <stdio.h>int main(int argc,const char* argv[])
{FILE* wfp = fopen("stdio.dat","w");if(NULL == wfp){   perror("fopen");return -1; }   for(int i = 0; i<10000000; i++){   fwrite(&i,1,4,wfp);}   fclose(wfp);return 0;
}
/*
time ./stdio
real    0m0.224s
user    0m0.195s
sys     0m0.028s
*/
// 系统IO
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc,const char* argv[])
{int fd = open("sysio.dat",O_WRONLY|O_CREAT|O_TRUNC,0644);if(0 > fd) {   perror("open");return -1; }   for(int i=0; i<1000000; i++){   write(fd,&i,4);}   close(fd);return 0;
}
/*
time ./sysio
real    0m1.137s
user    0m0.104s
sys     0m1.033s
*/

六、系统IO与标准IO

​ 1、当系统调用被执行时,需要从用户态切换到内核态,执行完毕后再从内核态切换到用户态,频繁的切换就会导致性能损失。

​ 2、标准IO在内部维护一个缓冲区(1k,1024字节),只有在满足特定条件才会把缓冲区中的数据调用write进入写入,因此降低了系统调用的使用频率,减少用户态和内核态的来回切换次数,因此标准IO的速度比系统IO更快

​ 3、如果想提高系统IO的速度,可以尝试维护一个更大的缓冲区,先把数据存储在缓冲区中,等缓冲区满了,再调用write写入,这样系统IO会比标准IO更快。

​ 4、普通情况建议使用标准IO,因为比直接使用系统IO要快,如果对速度有很高的要求,可以使用系统IO+大缓冲区。

// 系统IO+大缓冲区
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc,const char* argv[])
{int fd = open("sysio.dat",O_WRONLY|O_CREAT|O_TRUNC,0644);if(0 > fd) {   perror("open");return -1; }   int buf[4096];for(int i=0; i<1000000; i++){   buf[i%4096] = i;if(i%4096 == 4095)write(fd,buf,sizeof(buf));}   close(fd);return 0;
}
/*
time ./sysio
real    0m0.005s
user    0m0.000s
sys     0m0.005s
*/

​ 5、UNIX和Linux只有这一套读写函数,没有文本文件的读写方式,可以使用ssanf/sprintf配合缓冲区来实现文本内容的读写。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>typedef struct Student
{int id;char name[20];float score;
}Student;int main(int argc,const char* argv[])
{int fd = open("text.txt",O_RDWR);if(0 > fd){perror("open");return -1;}Student stu = {10012,"hehe",365};char buf[256];sprintf(buf,"%d %s %g\n",stu.id,stu.name,stu.score);write(fd,buf,strlen(buf));close(fd);return 0;
}

练习:使用系统IO实现带覆盖检查的cp命令。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc,const char* argv[])
{if(3 != argc){puts("Use:./cp src dest");return 0;}int src_fd = open(argv[1],O_RDONLY);if(0 > src_fd){perror("open src");return -1;}int dest_fd = open(argv[2],O_WRONLY|O_CREAT|O_EXCL,0644);if(0 > dest_fd){printf("%s 文件已经存在是否覆盖?(y/n)",argv[2]);char cmd = getchar();if('y' != cmd && 'Y' != cmd){close(src_fd);printf("停止拷贝!\n");return 0;}dest_fd = open(argv[2],O_WRONLY|O_TRUNC);if(0 > dest_fd){perror("open dest");return -1;}}int ret = 0;char buf[4096];while(ret = read(src_fd,buf,sizeof(buf))){write(dest_fd,buf,ret);}close(src_fd);close(dest_fd);return 0;
}

argc,argv 用命令行编译程序时有用。
主函数main中变量(int argc,char *argv[ ])的含义
有些编译器允许将 main() 的返回类型声明为void,这已不再是合法的C++
main(int argc, char *argv[ ], char **env)才是UNIX和Linux中的标准写法。
argc: 整数,用来统计你运行程序时送给main函数的命令行参数的个数

argv[ ]: 指针数组,用来存放指向你的字符串参数的指针,每一个元素指向一个参数
argv[0] 指向程序运行的全路径名
argv[1] 指向在DOS命令行中执行程序名后的第一个字符串
argv[2] 指向执行程序名后的第二个字符串

argv[argc]为NULL。
**env:字符串数组。env[ ]的每一个元素都包含ENVVAR=value形式的字符
串。其中ENVVAR为环境变量,value 为ENVVAR的对应值。
argc, argv,env是在main( )函数之前被赋值的,编译器生成的可执行文件,main( )不是真正的入口点,而是一个标准的函数,这个函数名与具体的操作系统有关。

经典例子

对于理解argv[ ]函数很管用:

#include <stdio.h>//#包含<stdio.h>int main(int argc,char* argv[])    //整数类型主函数(整数类型统计参数个数,字符类型指针数组指向字符串参数)
{printf("%d\n",argc);           //格式化输出while(argc)                    //当(统计参数个数)printf("%s\n",argv[--argc]);   //格式化输出return 0;                      //返回0;正常退出
}

假设将其编译为 test.exe
在命令行下

> test.exe test hello

得到的输出结果为

3

hello

test

test.exe

main(int argc, char* argv[ ]),其中argc是指变量的个数,本例中即指test和hello这两个变量和程序运行的全路径名或程序的名字,argc即为3。

argv是一个char *的数组,其中存放指向参数变量的指针,此处argv[0]指向test.exe的全路径名或test.exe,argv[1]指向test,argv[2]指向hello。

再例:

#include<stdio.h>
int main(int argc,char *argv[])
{if(argc==1||argc>2)printf("请输入想要编辑的文件名如:fillname");if(argc==2)printf("编辑%s\n",argv[1]);return 0;
}

编译该程序:gcc -o edit edit.c

运行:〉edit

结果:请输入想要编辑的文件名如:fillname

运行:〉edit f1.txt

结果:编辑 f1.txt

执行edit时,argc为1,argv[0]指向edit

而执行edit f1.txt时,argc的值为2,argv[0]指向edit,argv[1]指向f1.txt

打印argv默认值

for(;n<=(26+i);n++)printf("argv_%d=[%s]\n",n,argv[n]);

无参数运行,得到的输出结果为:

argv_0=[main]argv_1=[(null)]argv_2=[REMOTEHOST=10.229.26.252]argv_3=[HOSTNAME=localhost.localdomain]argv_4=[SHELL=/bin/bash]argv_5=[TERM=vt100]argv_6=[HISTSIZE=1000]argv_7=[QTDIR=/usr/lib64/qt-3.3]argv_8=[OLDPWD=/home/view/zx]argv_9=[QTINC=/usr/lib64/qt-3.3/include]argv_10=[USER=view]argv_11=[LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.btm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35:]argv_12=[MAIL=/var/spool/mail/view]argv_13=[PATH=/usr/lib64/qt-3.3/bin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/lib/jdk/bin:/home/view/bin:.]argv_14=[INPUTRC=/etc/inputrc]argv_15=[PWD=/home/view/zx/c]argv_16=[JAVA_HOME=/usr/lib/jdk]argv_17=[LANG=zh_CN. GB18030]argv_18=[SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass]argv_19=[SHLVL=1]argv_20=[HOME=/home/view]argv_21=[LANGUAGE=zh_CN. GB18030:zh_CN. GB2312:zh_CN]argv_22=[LOGNAME=view]argv_23=[QTLIB=/usr/lib64/qt-3.3/lib]argv_24=[LESSOPEN=|/usr/bin/lesspipe. sh %s]argv_25=[G_BROKEN_FILENAMES=1]argv_26=[_=./main]argv_27=[(null)]

七、文件位置指针

​ 1、每个打开的文件都有一个记录读写位置的变量,它可能是整数,但习惯的称作位置指针,文件的读写操作都是从位置指针所指向地方进行的。

​ 2、lseek可以设置文件的位置指针,与标准C不一样的是它的返回值是它调整后的位置指针,所以系统调用中没有与ftell对应的函数,因为lseek就包含fseek和ftell的功能。

头文件:#include <sys/types.h>#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);
功能:调整文件位置指针,用法与标准C的fseek基本一致。
offset:偏移值
whence:基础位置//whence 可以是SEEK_SET(文件指针开始),SEEK_CUR(文件指针当前位置) ,SEEK_END为文件指针尾SEEK_SET The offset is set to offset bytes.从文件头部开始偏移offset个字节。SEEK_CUR   The offset is set to its current location plus offset bytes.从文件当前读写的指针位置开始,增加offset个字节的偏移量。SEEK_END  The offset is set to the size of the file plus offset bytes.文件偏移量设置为文件的大小加上偏移量字节。

​ 3、在超过文件末尾的位置写入数据就会形成文件黑洞,黑洞不会占用磁盘空间,但会计算成文件的大小,而且也不会影响文件的读写。

练习:使用lseek实现一个计算文件大小的命令,显示出文件的字节数,超过1024字节显示KB,超过1024KB显示MB,超过1024MB显示GB

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc,const char* argv[])
{if(2 != argc){puts("Use:./filesize <name>");return 0;}int fd = open(argv[1],O_RDONLY);if(0 > fd){printf("open %s %m\n",argv[1]);return -1;}size_t bytes = lseek(fd,0,SEEK_END);printf("%u\n",bytes);if(bytes > 1024*1024*1024)printf("%uGB %uMB %uKB %uByte\n",bytes/1024/1024/1024,bytes/1024/1024%1024,bytes/1024%1024,bytes%1024);else if(bytes > 1024*1024)printf("%uMB %uKB %uByte\n",bytes/1024/1024 % 1024,bytes/1024%1024,bytes%1024);else if(bytes > 1024)printf("%uKB %uByte\n",bytes/1024%1024,bytes%1024);elseprintf("%uByte\n",bytes);close(fd);return 0;
}if(0 > fd){printf("open %s %m\n",argv[1]);return -1;}size_t bytes = lseek(fd,0,SEEK_END);printf("%u\n",bytes);if(bytes > 1024*1024*1024)printf("%uGB %uMB %uKB %uByte\n",bytes/1024/1024/1024,bytes/1024/1024%1024,bytes/1024%1024,bytes%1024);else if(bytes > 1024*1024)printf("%uMB %uKB %uByte\n",bytes/1024/1024 % 1024,bytes/1024%1024,bytes%1024);else if(bytes > 1024)printf("%uKB %uByte\n",bytes/1024%1024,bytes%1024);elseprintf("%uByte\n",bytes);close(fd);return 0;
}​    

UNIXLinux操作系统---文件系统相关推荐

  1. 操作系统文件系统题库

    免费版:华文慕课-操作系统文件系统题库 网络课课后题 1.UNIX系统中,把输入输出设备看做是 A.普通文件 B.目录文件 C.特殊文件 D.索引文件 解析: 2.文件的逻辑结构是由下列哪一项决定的? ...

  2. Linux操作系统文件系统基础知识详解

    标签:基础知识操作系统根目录Linux程序 一 .Linux文件结构 文件结构是文件存放在磁盘等存贮设备上的组织方法.主要体现在对文件和目录的组织上. 目录提供了管理文件的一个方便而有效的途径. Li ...

  3. 操作系统文件系统实验_现代电脑操作系统原理课程,案例:Apple 操作系统技术演进...

    实验环境 ChCore 课程实验代码及说明.zip 大纲.txt 1.1 操作系统的定义.mp4 1.2 为什么学习操作系统.mp4 1.3 操作系统面临的挑战.mp4 1.4 案例:Apple 操作 ...

  4. fpga嵌入linux系统,基于FPGA的Virtex-5板的PetaLinux嵌入式操作系统文件系统挂载流程...

    今天总算完成了文件系统的加入,现在看来整个的工作过程少了一个懂linux代码的指导,探索起来确实不易.总结下最近做的事情,条理才逐渐清楚了. 刚开始接到这个任务时是要在petalinux嵌入式操作系统 ...

  5. 操作系统——文件系统

    文章目录 1.文件系统概述 1.1文件 1.1.1文件的定义和命名 1.1.2与文件相关的概念 1.2文件系统 1.2.1文件系统的定义和命名 1.2.2文件系统的类型 1.2.3文件管理的目的 2. ...

  6. 手写操作系统+文件系统开源啦

    哈喽,我是子牙,一个很卷的硬核男人.喜欢研究底层,聚焦做那些大家想学没地方学的课程:手写操作系统.手写虚拟机.手写模拟器.手写编程语言- 今年是我创业的第二年,已经做了两个课程:手写JVM.手写操作系 ...

  7. 利用who,w,ps和top等指令查看linux下的进程执行情况.,UNIXLINUX操作系统实验指导书...

    STAT 该进程的状态.其中S代表休眠状态:D代表不可中断的休眠状态:R代表运行状态:Z代表僵死状态:T代表停止或跟踪状态. TIME 该进程自启动以来所占用的总CPU时间.如果进入的是累计模式,那么 ...

  8. 操作系统(十一)文件系统实现

    操作系统 文件系统实现 文件系统实现 1.文件系统结构 2.文件系统实现 虚拟文件系统 VFS 3.目录实现 4.分配方法 4.1连续分配 连续分配--将逻辑地址映射到物理地址 扩展 4.2 链接分配 ...

  9. flash和linux文件系统,面向大容量Flash的高效Linux文件系统改进和实现

    摘要: 文件系统是Linux操作系统的重要组成部分.而本文对于面向大容量Flash文件系统高效性的研究则主要侧重于对于嵌入式Linux操作系统文件系统的研究.由于嵌入式设备介质的特殊性,电源系统的不稳 ...

最新文章

  1. IIS服务器下做301永久重定向设置方法[图解]
  2. tn文本分析语言(三):高级语法
  3. hexo发布后样式丢失
  4. vs编译时出现大量ws2def.h的错误的解决方法
  5. PDF文件怎么旋转保存
  6. 设计一个密码登录程序。要求: 设定用户名为lili,密码是123321。若用户名正确,密码也正确,则显示:“lili,欢迎您”
  7. 数据分析/运营——用户分层模型RFM
  8. 杨国福和张亮“天地对决” 麻辣烫江湖要变天了吗?
  9. 小米冲高端?差了几口气
  10. 桌面便签哪个软件好用?求推荐一款便签软件?
  11. 转-思维要裂变要敢闯想
  12. layui引入php项目,Layui使用入门教程
  13. 在计算机语言中的乘法,LOGO语言编程题  高精度乘法★★
  14. 辉芒微IO单片机FT60F210-URT
  15. PPP拨号和NDIS拨号的区别:
  16. Unity3D Shader系列之描边
  17. autojs点击方式汇总:autojs点击的几种方式
  18. WEB前端学习:CSS学习_用户界面样式
  19. ORA-01950: no privileges on tablespace ‘USERS‘
  20. EnglishPlayer ---- 英语听写工具发布了!

热门文章

  1. C语言 函数调用时的数据传递
  2. hping - 使用 TCP/UDP ping 解决防火墙拦截 ICMP ping
  3. Web前端--HTML+CSS+JS实现仿切水果小游戏
  4. NGUI Toggle
  5. json编辑器插件 vue_json编辑器vue-json-editor
  6. 毒性逆转 水平分割。。
  7. JavaScript高级程序设计 第4版 -- 操作符
  8. ffmpeg切割音频文件
  9. 读写文件操作OpenFile()
  10. 数学建模 —— 降维算法