精华内容
下载资源
问答
  • 详细设计的伪代码的实例

    万次阅读 2018-01-18 10:48:16
    使用伪代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java,etc)实现。因此,伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。 介于自然语言与编程语言之间。 它以编程...

    代码(Pseudocode)是一种算法描述语言。使用伪代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java,etc)实现。因此,伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。 介于自然语言与编程语言之间。

      它以编程语言的书写形式指明算法的职能。相比于程序语言(例如Java, C++,C, Dephi 等等)它更类似自然语言。它是半角式化、不标准的语言。我们可以将整个算法运行过程的结构用接近自然语言的形式(这里,你可以使用任何一种你熟悉的文字,中文,英文 等等,关键是你把你程序的意思表达出来)描述出来. 使用伪代码, 可以帮助我们更好的表述算法, 不用拘泥于具体的实现.

      人们在用不同的编程语言实现同一个算法时意识到,他们的实现(注意:这里是实现,不是功能)很不同。尤其是对于那些熟练于不同编程语言的程序员要理解一个(用其他编程语言编写的程序的)功能时可能很难,因为程序语言的形式限制了程序员对程序关键部分的理解。这样伪代码就应运而生了。

      当考虑算法功能(而不是其语言实现)时,伪代码常常得到应用。计算机科学在教学中通常使用虚拟码,以使得所有的程序员都能理解。

      综上,简单的说,让人便于理解的代码。不依赖于语言的,用来表示程序执行过程,而不一定能编译运行的代码。在数据结构讲算法的时候用的很多。 

    语法规则

      例如,类Pascal语言的伪代码的语法规则是: 在伪代码中,每一条指令占一行(else if,例外)。指令后不跟任何符号(Pascal和C中语句要以分号结尾)。书写上的“缩进”表示程序中的分支程序结构。这种缩进风格也适用于if-then-else语句。用缩进取代传统Pascal中的begin和end语句来表示程序的块结构可以大大提高代码的清晰性;同一模块的语句有相同的缩进量,次一级模块的语句相对与其父级模块的语句缩进。

        算法的伪代码语言在某些方面可能显得不太正规,但是给我们描述算法提供了很多方便,并且可以使我们忽略算法实现中很多麻烦的细节。通常每个算法开始时都要描述它的输入和输出,而且算法中的每一行都给编上号码,在解释算法的过程中会经常使用算法步骤中的行号来指代算法的步骤。算法的伪代码描述形式上并不是非常严格,其主要特性和通常的规定如下:
            1) 算法中出现的数组、变量可以是以下类型:整数、实数、字符、位串或指针。通常这些类型可以从算法的上下文来看是清楚的,并不需要额外加以说明。
            2) 在算法中的某些指令或子任务可以用文字来叙述,例如,"设x是A中的最大项",这里A是一个数组;或者"将x插入L中",这里L是一个链表。这样做的目的是为了避免因那些与主要问题无关的细节使算法本身杂乱无章。
            3) 算术表达式可以使用通常的算术运算符(+,-,*,/,以及表示幂的^)。逻辑表达式可以使用关系运算符=,≠,<,>,≤和≥,以及逻辑运算符与(and),或(or),非(not)。
            4) 赋值语句是如下形式的语句:a<-b 。
    这里a是变量、数组项,b是算术表达式、逻辑表达式或指针表达式。语句的含义是将b的值赋给a。
            5) 若a和b都是变量、数组项,那么记号a<->b 表示a和b的内容进行交换。
            6) goto语句具有形式
                                            goto label(goto标号)
    它将导致转向具有指定标号的语句。
            7) 条件语句有以下两种形式:
                                                if c then s或者 
                                                   if c then s
                                                      else s′
    这里c是逻辑表达式,s和s′是单一的语句或者是被括在do和end之间的语句串。对于上述两种形式,假若c为真,则s被执行一次。假若c为假,则在第一种形式中,if语句的执行就完成了,而在第二种形式中,执行s′。在所有的情况下,控制就进行到了下一个语句,除非在s或s′中的goto语句使控制转向到其它地方。
             8) 有两种循环指令:while和for。
             while语句的形式是
                                                  while c do  
                                                        s
                                                      end
    这里c是逻辑表达式,而s是由一个或更多个语句组成的语句串。当c为真时,执行s。在每一次执行s之前,c都被检查一下;假若c为假,控制就进行到紧跟在while语句后面的语句。注意,当控制第一次达到while语句时,假若c为假,则s一次也不执行。 
           for语句的形式是
                                          for var init to limit by incr do
                                                            s
                                                          end
    这里var是变量,init、limit和incr都是算术表达式,而s是由一个或多个语句组成的语句串。初始时,var被赋予init的值。假若incr≥0,则只要var≤limit,就执行s并且将incr加到var上。(假若incr<0,则只要var≥limit,就执行s并且将incr加到var上)。incr的符号不能由s来该改变。
          9) exit语句可以在通常的结束条件满足之前,被用来结束while循环或者for循环的执行。exit导致转向到紧接在包含exit的(最内层)while或者for循环后面的一个语句。
         10) return用来指出一个算法执行的终点;如果算法在最后一条指令之后结束,它通常是被省略的;它被用得最多的场合是检测到不合需要的条件时。return的后面可以紧接被括在引号的信息。
          11) 算法中的注释被括在/* */之中。诸如read和output之类的各种输入或者输出也在需要时被用到。
         

    伪代码实例

      伪代码只是像流程图一样用在程序设计的初期,帮助写出程序流程。简单的程序一般都不用写流程、写思路,但是复杂的代码,最好还是把流程写下来,总体上去考虑整个功能如何实现。写完以后不仅可以用来作为以后测试,维护的基础,还可用来与他人交流。但是,如果把全部的东西写下来必定可能会让费很多时间,那么这个时候可以采用伪代码方式。比如:

      IF 九点以前 THEN

         do 私人事务;

      ELSE 9点到18点 THEN

      工作;

      ELSE

      下班;

      END IF

      这样不但可以达到文档的效果,同时可以节约时间. 更重要的是,使结构比较清晰,表达方式更加直观.

      下面介绍一种类Pascal语言的伪代码的语法规则。

      在伪代码中,每一条指令占一行(else if 例外,),指令后不跟任何符号(Pascal和C中语句要以分号结尾);

      书写上的“缩进”表示程序中的分支程序结构。这种缩进风格也适用于if-then-else语句。用缩进取代传统Pascal中的begin和end语句来表示程序的块结构可以大大提高代码的清晰性;同一模块的语句有相同的缩进量,次一级模块的语句相对与其父级模块的语句缩进; 

      在伪代码中,通常用连续的数字或字母来标示同一即模块中的连续语句,有时也可省略标号。

      符号△后的内容表示注释;

      在伪代码中,变量名和保留字不区分大小写,这一点和Pascal相同,与C或C++不同;

      在伪代码中,变量不需声明,但变量局部于特定过程,不能不加显示的说明就使用全局变量;

      赋值语句用符号←表示,x←exp表示将exp的值赋给x,其中x是一个变量,exp是一个与x同类型的变量或表达式(该表达式的结果与x同类型);多重赋值i←j←e是将表达式e的值赋给变量i和j,这种表示与j←e和i←e等价。

      例如:

      x←y

      x←20*(y+1)

      x←y←30

      以上语句用C分别表示为:

      x = y;

      x = 20*(y+1);

      x = y = 30;

      选择语句用if-then-else来表示,并且这种if-then-else可以嵌套,与Pascal中的if-then-else没有什么区别。

      例如:

      if (Condition1)

      then [ Block 1 ]

      else if (Condition2)

      then [ Block 2 ]

      else [ Block 3 ]

      循环语句有三种:while循环、repeat-until循环和for循环,其语法均与Pascal类似,只是用缩进代替begin - end;

      例如:

      1. x ← 0

      2. y ← 0

      3. z ← 0

      4. while x < N

      1. do x ← x + 1

      2. y ← x + y

      3. for t ← 0 to 10

      1. do z ← ( z + x * y ) / 100

      2. repeat

      1. y ← y + 1

      2. z ← z - y

      3. until z < 0

      4. z ← x * y

      5. y ← y / 2

       上述语句用C或C++来描述是:

      x = y = z = 0;

      while( z < N )

      {

      x ++;

      y += x;

      for( t = 0; t < 10; t++ )

      {

      z = ( z + x * y ) / 100;

      do {

      y ++;

      z -= y;

      } while( z >= 0 );
         }
      z = x * y;

      }

      y /= 2;

      数组元素的存取有数组名后跟“[下标]”表示。例如A[j]指示数组A的第j个元素。符号“ …”用来指示数组中值的范围。

      例如:

      A[1…j]表示含元素A[1], A[2], … , A[j]的子数组;

      复合数据用对象(Object)来表示,对象由属性(attribute)和域(field)构成。域的存取是由域名后接由方括号括住的对象名表示。

      例如:

      数组可被看作是一个对象,其属性有length,表示其中元素的个数,则length[A]就表示数组A中的元素的个数。在表示数组元素和对象属性时都要用方括号,一般来说从上下文可以看出其含义。

      用于表示一个数组或对象的变量被看作是指向表示数组或对象的数据的一个指针。对于某个对象x的所有域f,赋值y←x就使f[y]=f[x],更进一步,若有f[x]←3,则不仅有f[x]=3,同时有f[y]=3,换言之,在赋值y←x后,x和y指向同一个对象。

      有时,一个指针不指向任何对象,这时我们赋给他nil。

      函数和过程语法与Pascal类似。

      函数值利用 “return (函数返回值)” 语句来返回,调用方法与Pascal类似;过程用 “call 过程名”语句来调用;

      例如:

      1. x ← t + 10

      2. y ← sin(x)

      3. call CalValue(x,y)

      参数用按值传递方式传给一个过程:被调用过程接受参数的一份副本,若他对某个参数赋值,则这种变化对发出调用的过程是不可见的。当传递一个对象时,只是拷贝指向该对象的指针,而不拷贝其各个域。

    展开全文
  • 蛋糕连锁店网站管理系统是海南赞赞网络公司针对甜品糕点连锁企业开发的建站系统。程序主要采用了 thinkphp5内核开发,拥有独立自主的标签系统、函数系统、极方便二次开发,网站设计人员可以在该系统基础上设计出漂亮...
  • 本篇介绍密钥管理子系统,只涉及内核如何管理密钥,不涉及内核加密算法的实现。密钥本质上是一段数据,内核对它的管理有些类似对文件的管理。但是因为Linux内核不愿意让密钥像文件那样“静态”存储在磁盘或者其他...

    本篇介绍密钥管理子系统,只涉及内核如何管理密钥,不涉及内核加密算法的实现。密钥本质上是一段数据,内核对它的管理有些类似对文件的管理。但是因为Linux内核不愿意让密钥像文件那样“静态”存储在磁盘或者其他永久性存储介质上,所以内核对密钥的管理又有些像对进程的管理,有创建、实例化、删除等操作。

    先从系统中可见的伪文件系统proc看起,内核密钥管理在proc文件系统中创建了两个只读文件:/proc/keys和/proc/key-users。它们没有被创建在/proc/pid目录下,而是被直接创建在了proc文件系统的根目录下。这就造成了进程根本无法查看到别的进程的密钥。keys文件列出当前进程可查看的密钥,所以不同的进程读出的内容会不同。列出的内容包括序列号、过期时间、访问允许位、uid、gid、类型、描述等。key-users列出密钥的统计信息,包括uid、使用计数、密钥总数量和实例化数量、密钥数量的配额信息、密钥占用内存的配额信息。

    密钥

    密钥在内核代码中称为key,因为key是由用户态进程创建,由内核管理,其实体存储在内核申请的内存中,所以密钥管理需要实施配额管理。密钥有对称密钥和非对称密钥两大类,每类密钥又有很多种。密钥种类不同,payload中数据的格式和长度也不同。所以key数据结构中包含了数据成员type,其类型为key_type,其中包含若干函数指针,用于处理payload。主要内容可以参见include/linux/key-type.h。

    include/linnux/key.h
    struct key {
    	...
    	key_serial_t serial;       //内核通过此序列号来唯一地标识一个key
    	struct key_user *user;     //包含一些和用户配额相关的数据,像用户拥有key的数量,用户拥有key占用总内存之类
    	kuid_t uid;                //标识key的属主
    	kgid_t gid;                //标识key的属组
    	key_perm_t perm;           //key的访问权限
    	void *security;            //被LSM使用,指向的内容由具体的LSM模块定义
    	
    	unsigned short datalen;    //标识payload的长度
    	union {
    		union{
    			unsigned long value;
    			void __rcu *rcudata;
    			void *data;
    			void *data2[2];
    		} payload;
    		struct assoc_array keys;
    	};
    	
    	union {
    		struct keyring_index_key index_key;
    		struct {
    			struct key_type *type;
    			char *description;   //字符串,用于用户态进程查询密钥。用户态先用该字符串从内核查询到key对应的serial,后面直接用serial对key进行操作
    		};
    	};
    	unsigned long flags;         //包含密钥的状态信息和密钥的生命周期有关
    	...
    };
    
    include/linux/key_type.h
    struct key_type {
    	const char* name;
    	...
    	int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
    	int (*update)(struct key *key, struct key_preparsed_payload *prep);
    	int (*match)(const struct key *key, const void *desc);
    	void (*revoke)(struct key *key);
    	...
    };
    

    flags用于存放密钥的状态信息。密钥是动态创建的,它是有生命周期。用户态进程首先会创建密钥,内核响应用户态进程的请求会生成一个密钥,分配内存。密钥的第二个状态是instantiated,内核将用户态进程提供的输入填入密钥的负载(payload)之中。这时的密钥就可以被用来做加解密使用。密钥的死亡状态有三种。revoke和invalidate都是由用户态进程发起的请求,内核对invalidate的响应是立即让密钥失效,收回密钥上的资源;内核对revoke的响应也是让密钥失效并收回资源,只是在此之前先调用密钥所属的类型(struct key_type)中定义的一个函数(revoke)。dead状态不是由用户态进程删除密钥导致的,而是由于一种类型(key_type)的密钥失效导致的。

    		-------------
    		| allocated |   -----> user_construct
    		-------------                 /      |
    		        |                    /       |
    		        |                  /         |
    		       \/               \ /          |
    		----------------                    \/
    		| instantiated | <-----     negatice
    		----------------      
    		/        |        \
    	/            |            \
    \/              \/              \/
    revoked  dead       mvalidated
    

    密钥的构造由用户态进程发起,密钥的payload数据由用户态进程提供,或者由用户态进程指令内核生成。当内核子系统要用到某个密钥,而这个密钥还不存在怎么办?一种简单的做法是由内核启动一个用户态进程,再由这个进程来填充密钥的payload。在发起新进程之前,内核首先分配一个密钥,将密钥的状态设置为user_construct。发起的新进程负责填充密钥的payload。这时,进程有两个选择:一个是立刻提供payload并通知内核将密钥的状态置为instantiated;另一个是不能马上提供payload数据,它就通知内核将密钥的状态置为negative,以后再提供数据并修改状态。

    security/keys/request_key.c
    struct key *request_key(struct key_type *type, const char *description, const char *callout_info){
    	struct key *key;    // 定义密钥结构体变量
    	size_t callout_len = 0;
    	int ret;
    
    	if (callout_info){
    		callout_len = strlen(callout_info);
    		// request_key_and_link会尝试查找密钥,如果没有找到,request_key_and_link会调用construct_key_and_link
    		key = request_key_and_link(type, description, callout_info, callout_len, NULL, NULL, KEY_ALLOC_IN_QUOTA);
    		if (!IS_ERR(key)){
    			ret = wait_for_key_construction(key, false);
    			if (ret < 0){
    				key_put(key);
    				return ERR_PTR(ret);
    			}
    		}
    	}
    	return key;
    }
    

    密钥类型

    钥匙环keyring
    钥匙环可以包含若干密钥,当然这些密钥可以是另一个钥匙环。寻找一个密钥时,需要配合参数type,也就是说,不同类型的密钥在不同的名字空间中。比如一个类型为trusted的密钥和一个类型为user的密钥可以同名(严格地说,不是名字,是描述description),不会引起冲突。而是,一个密钥可以链接到多个钥匙环,密钥在不同的钥匙环中,其名字(描述)总是一样的。keyring使用key结构体类型的assoc_array成员,非keyring使用payload。

    struct key {
    	...
    	union {
    		union{
    			unsigned long value;
    			void __rcu *rcudata;
    			void *data;
    			void *data2[2];
    		} payload;
    		struct assoc_array keys;
    	};
    

    密钥挂在钥匙环上,钥匙环可以再挂在另一个钥匙环上。当用户态进程要找一个钥匙,该从哪个钥匙环开始?文件系统有一个根目录,根目录是文件查找的起点。钥匙环也类似,钥匙环有若干个特殊的ID,供用户态进程查找。

    ID含义
    -1线程keyring
    -2进程keyring
    -3会话keyring
    -4用户ID对应的keyring
    -5用户会话keyring
    -6组ID对应的keyring
    -7request_key操作中认证密钥(auth_key)的keyring
    -8request_key目的keyring

    每个线程有一个自己的钥匙环,每个进程有一个自己的钥匙环。会话概念的引入和登录(login)过程有关,用户登录系统,就是启动了一次会话,这次登录的进程,及后续子孙进程共享同一个会话id。现在通过字符终端tty登录Linux还是这样的情况。简而言之,一个会话就是一组进程,它们共享一些资源,比如会话钥匙环。
    用户ID对应的钥匙环和组ID对应的钥匙环,脱离进程而存在。用户会话钥匙环主要用在登录程序,用户登录系统,输入用户名和口令,登录程序启动新进程(一般是一个shell),同时启动一个新会话,这个新进程的会话钥匙环就先设置为此次登录的用户的用户会话钥匙环

    user类型的密钥由用户态进程创建,并且一般是用户态进程使用此种类型密钥。logon类型和user类型很相似,主要区别在于进程可以写入logon类型密钥的负载,但是不能读出logon类型密钥的负载。logon类型密钥的负载存储的是用户名和口令。内核中的一些子系统,比如cifs,会使用这些信息。

    asymmetric对应非对称密钥,非对称密钥有两个密钥:公钥和私钥,公钥存储在payload成员中,私钥存储在type_data中。

    encrypted这种类型的密钥之所以命名为encrypted,原因是用户态进程只能读到加密后的密钥数据,因此用户态进程是无法使用这种密钥的。这种密钥是由内核中的程序使用的,如ecryptfs和IMA。用来加密encrypted密钥数据的密钥有两种,一种是前面提到的user类型的密钥,另一种是后面要提到的trusted类型的密钥。内核中的密钥,是由用户态进程动态创建的,这里,encryted类型的密钥的设计的初衷就是不允许用户态接触到明文存储的密钥数据,那么,用户态进程又该怎么创建这种密钥呢?答案是,创建这种密钥时的payload是一个字符串,其中包含一个指令,内核根据该指令来创建密钥。指令语法:

    1. “new [format] key-type:master-key-name keylen” -创建密钥,密钥长度为keylen,使用类型为key-type,名字为master-key-name的密钥作为此次创建的密钥的加密密钥。format有两种形式:deflaut和ecryptfs。加密密钥的类型可以是trusted或者user。
    2. “load hex_blob”-根据hex_blob的值来创建密钥,hex_blob是一个hex字符串,字符串本身是有格式的,其中包含用于加密的密钥的类型和名字、哈希校验值及加密后的密钥数据。一般用法是创建一个encrypted密钥,将其内容读出导入一个文件,在每次系统启动时根据文件内容创建密钥。比如:
      cat /etc/keys/kmk | keyctl padd user kmk @u
      keyctl add encrypted evm-key "load `cat /etc/keys/evm-key` " @u
    3. “update key-type:master-key-name”-改变用于加密密钥的密钥。用户修改密钥的负载(payload),负载字符串是上面这个格式时,encrypted类型的密钥的加密密钥就会被更改。

    trusted这种类型的密钥和TPM相关。由TPM硬件生成一个密钥,并存储在TPM硬件中。同encrypted类型,创建密钥时的payload是一个指令字符串。语法是:
    “new keylen [options]”
    “load hex_blob [pcrlock=pcrnum]”

    系统调用

    密钥管理子系统添加了三个系统调用:

    1. key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t keyring)
      创建成功后,新密钥会被链接入参数keyring表示的钥匙环中
    2. long keyctl(int cmd, …) …后续参数由cmd取值决定
      cmd的取值有:KEYCTL_GET_KEYRING_ID、KEYCTL_JOIN_SESSION_KEYRING、KEYCTL_UPDATE、KEYCTL_REVOKER、KEYCTL_DESCRIBE、KEYCTL_CLEAR、KEYCTL_LINK、KEYCTL_UNLINK、KEYCTL_SEARCH、KEYCTL_READ、KEYCTL_CHOWN、KEYCTL_SETPERM、KEYCTL_INSTANTIATE、KEYCTL_INSTANTIATE_IOV、KEYCTL_NEGATE、KEYCTL_REJECCT、KEYCTL_SET_TIMEOUT、KEYCTL_INVALIDATE、KEYCTL_GET_SECURITY、KEYCTL_GET_PERSISTENT、KEYCTL_SET_REQKEY_KEYRING、KEYCTL_ASSUME_AUTHORITY
    3. key_serial_t request_key(const char *type, const char *description, const char *callout_info, key_serial_t keyring)
      用户态进程通过这个系统调用让内核查询一个密钥,并将其链接入参数指定的钥匙环。如果这个密钥已经存在,则这个系统调用的功能和keyctl(KEYCTL_SEARCH, …)几乎没有区别。如果这个密钥不存在,在这个系统调用中内核还要负责创建密钥。那么,密钥的pauload在哪里?内核的做法是根据参数callout_info启动一个用户态进程,由这个用户态进程来具体创建并实例化这个密钥。实际中的问题是内核启动的这个进程本身可能还是无法创建密钥,它又要启动别的进程来做这个工作。在这种重复委托的情况下,有两个东西必须以某种方式传递:一个是密钥,这个密钥已经在内核中创建了,需要用户态进程来实例化;另一个是钥匙环,就是这个密钥在成功实例化后,需要被链接到哪一个钥匙环中。还有一个额外的数据,就是进程的凭证,helper 1或者helper 2或者helper n进程要为process 1进程实例化密钥,这些helper可能要查找process 1的一些和密钥相关的数据。内核引入了一种新的密钥类型:key_type_request_key_auth。这种类型的密钥不是用来加密数据的,而是用来在进程间传递实例化一个密钥所需的信息。在内核创建进程helper 1的时候,先创建一个key_type_request_key_auth类型的密钥,链接入helper 1进程的会话钥匙环。key_type_request_key_auth类型的密钥的payload的子成员data本是void指针,其所指的实例的类型为request_key_auth。
    struct request_key_auth{
    	struct key *target_key;
    	struct key *dest_keyring;
    	const struct cred *cred;
    	void *callout_info;
    	size_t callout_len;
    	pid_t pid;
    }
    

    helper 1进程启动后就可以调用keyctl(KEYCTL_ASSUME_AUTHORITY, …),将这个key_type_request_key_auth类型的密钥置入自己的进程数据结构的request_key_auth。内核在做密钥相关的查找时,也会查找与request_key_auth中cred相关的密钥。

    密钥访问类型详情
    Read读出一个密钥的payload;读出一个钥匙环下所有链接的信息
    Write写入一个密钥的payload;在一个钥匙环中添加链接或删除链接
    View查看一个密钥的类型、描述等属性
    Search查找一个钥匙环,在搜索一个钥匙环时只会递归搜索其下有搜索访问权限的子钥匙环
    Link允许一个密钥或钥匙环被链接入一个钥匙环
    Set Attribute允许修改密钥的uid、gid、访问许可信息
    展开全文
  • 操作系统学习笔记:文件管理

    千次阅读 2020-12-13 21:50:17
    对于文件文件系统的概念、存放文件的介质、文件存放形式、文件操作形式、文件系统的安全性、磁盘调度算法的知识进行了相关的介绍!

    目录:

    一、概述:

    文件的概念:

    文件系统:

    文件的分类:

    文件的操作:

    文件类型

    二、文件的结构和存取方式:

    文件的存取方式:

    文件的逻辑结构:

    存储介质:

    文件的物理结构:

    三、文件目录:

    文件控制块:

    文件目录结构:

    目录查找和目录的改进:

    四、文件系统及其实现:

    文件系统的定义及其功能:

    打开文件表:

    外存空间的调度:

    五、文件的使用:

    主要操作:

    文件共享:

    六、文件系统的安全性和数据一致性:

    防止人为因素造成的文件不安全性:

    防止自然因素或系统因素造成的文件不安全性:

    文件系统的数据一致性:

    七、磁盘调度:

    提高文件系统的性能措施:

    磁盘I/O(输入输出)时间:

    磁盘的移臂调度算法:

    磁盘的优化分布:


    一、概述:

    文件的概念:

    什么是文件?

    文件是在逻辑上具有完整意义的信息集合,它有一个名字作标识。一个文件必须要有一个文件名,用户利用文件名访问文件。 

     

    文件的基本特征:

    ——文件的内容为一组相关信息,可以是源程序、可执行的二进制代码程序、待处理的数据、表格、声音、图像等。

    ——文件具有保存性。文件被保存在如磁盘、磁带等存储介质中,其内容可以被长期保存和多次使用

    ——文件可按名存取。每一个文件拥有唯一的标识名信息,用户无需了解文件所在的存储介质。

     

    文件的基本属性:


    文件系统:

    什么是文件系统?

    文件系统是操作系统中负责管理和存取文件的程序板块,也称为信息管理系统

     

    文件系统的组成:

    它由管理文件所需的数据结构(例如文件控制块、存储分配表等)、相应的管理软件以及访问文件的一组操作所组成。

     

    文件系统应当具有的五大功能:

     

    ——完成文件存储空间的管理

    • 建立文件时进行文件存储空间的分配,在删除文件时进行文件空间的回收。

    ——实现文件名到物理地址的映射

    • 这种映射对于用户来讲是透明的,用户不必了解文件的存放位置和查找方法等,只需要指出文件名就可以找到相应的文件。
    • 这一映射是通过在文件说明部分中文件的物理地址来实现的。

    ——实现文件和目录的操作管理。

    • 文件的建立、读、写和目录管理等基本操作是文件系统的基本功能。
    • 文件操作管理负责根据各种操作的要求完成各种操作所规定的任务,如从外存中读出数据,或将数据写入外存中。

    ——提供文件共享能力安全可靠措施

    • 文件共享是指多个用户可以使用同一文件,安全是防止文件被盗窃或破坏。
    • 通常采用多级保护措施来实现文件的共享与安全。另外,还要提供保证文件系统的可靠性办法。

    ——文件系统向用户提供了有关文件和目录操作的借口。


    文件的分类:

    按文件的性质和用途分类:

    ——系统文件:

    • 该类文件只允许用户通过系统调用来执行它们,而不允许对其进行修改和读写。系统文件主要由操作系统核心、各种系统应用程序和数据所组成。

    ——库文件:

    • 该类文件包括允许用户对其进行读取、执行,但是不允许对其进行修改的子程序库。如C语言子程序库等。

    ——用户文件:

    • 用户文件是用户委托文件系统保存的文件。
    • 这类文件只有文件的所有者和被授权的用户才能使用。
    • 用户文件主要由源程序、目标程序、用户数据库等组成。

     

    按文件的组织形式分类:

    ——普通文件:

    • 既包括系统文件也包括用户文件、库函数文件和使用程序文件。
    • 普通文件主要是指组织格式为系统中所规定的最一般格式的文件,也就是平常所说的文件。

    ——目录文件:

    • 由文件的目录信息构成的特殊文件数据。

    ——特殊文件:

    • 有的系统中,所有的输入、输出设备都被看作特殊文件。
    • 这组特殊文件在使用形式上与普通文件相同,如查找目录、存取操作等。
    • 但是特殊文件的使用是与设备处理程序密切相关的。系统必须把对特殊文件的操作转入到对不同的设备的操作。

     

    按使用和管理情况分类:

    ——临时文件:

    • 它是一种私有资源,使用户在某次求解问题过程中产生的中间文件。
    • 这种文件仅仅保存在磁盘上。在作为“档案”的外存介质上没有副本。临时文件随用户撤离系统而撤离,因此不可共享。

    ——永久文件:

    • 这是用户经常要使用文件。
    • 这类文件不仅在磁盘上有文件副本,且在作为”档案“的介质上也有一个可用的副本。

    ——档案文件:

    • 仅保存在作为“档案”用的外存介质上,以备查证和恢复用。

     

    按文件系统提出的保护级别分类:

    ——只读文件:

    • 只允许用户对其执行读操作,对于写操作,系统将拒绝执行并给出错误信息。

    ——读写文件:

    • 只允许用户对其进行读、写操作,而拒绝对其执行任何其他的操作。

    ——不保护文件:

    • 这类文件是不加保护措施的文件,所有用户都可以对其进行存取等所有操作。

     

    按文件的数据流向分类:

    ——输入型文件:

    • 这些文件只能读。

    ——输出型文件:

    • 这些文件只能写入。

    ——输入\ 输出文件:

    • 这类文件既可读又可写。

     

    文件的分类还有许多种,但是在文件系统中比较重要的两种分类方式是按文件的逻辑结构物理结构进行分类。下一节我将仔细介绍!

     


    文件的操作:

    文件系统不应要求用户必须了解文件的物理组织才能使用文件,而应方便用户,提供给用户按其逻辑组织形式来使用文件

    一个文件系统至少要提供用户以下的文件操作功能:

    ——建立、删除、读、写、截断文件,文件换名、打开文件、关闭文件、复制文件(基本操作) 。

    ——修改、插入、删除数据项操作 。

    ——文件查找。

    ——修改文件属性:变更文件主的名字。


    文件类型:

    使用形式:主文件名字 扩展文件名

    • 其中,扩展文件名部分指出文件的类型

     

    有三种类型文件可以被执行:

     

    二、文件的结构和存取方式:

    文件的组织结构是指文件的构造方式,用户和文件系统往往从不同的角度对待同一个文件

    因此对于任何一个文件都存在两种形式的结构:

    ——文件的逻辑结构:用户按自己对信息的使用要求组织文件,这种文件是独立于物理环境而构造的,因此把用户概念中的文件称为文件的逻辑结构,或称逻辑文件

    ——文件的物理结构:又称为文件的存储结构,是指文件在辅存上的存储组织形式,这与存储介质的性质有关

    • 无论是文件的逻辑结构还是物理结构,其构造方式都会影响对文件的处理速度

    文件的存取方式:

    ——顺序存取:

    • 顺序存取是按照文件的逻辑地址顺序存取。

    ——随机存取:

    • 随机存取法允许用户根据记录的编号存取文件的任一记录,或者是根据存取命令把读写指针移到欲读写处来读写。

    ——按键存取:

    • 按键(关键字)存取是一种用在复杂文件系统,特别是数据库管理系统中的存取方法。

    文件的逻辑结构:

    设计文件系统时,选择逻辑结构应遵循的原则:

    • 便于修改
    • 应提高检索效率
    • 使文件信息占据最小的存储空间
    • 便于用户进行操作

    文件的逻辑结构分类:

    ——记录式文件(有结构文件):

    记录式文件在逻辑上被看成一组连续有序的记录的集合。每个记录由彼此相关的域构成。

    根据记录的长度分类:定长记录文件、变长记录文件。

    • 定长记录文件:文件中所有记录的长度都是相同的。所有记录中的各数据项都处在记录中相同的位置,具有相同的顺序及长度,文件的长度用记录数目表示。
    • 变长记录文件:文件中各记录的长度不相同。原因可能是一个记录中所包含的数据详数目不同。

    记录式文件可把文件中的记录按各种不同的方式排列,构成不同的逻辑结构,这样的记录式文件可以分为三类

    • 顺序文件:它是指按照某种顺序排列的记录所构成的文件,通常是定长记录文件,因此能用较快的速度查找文件的记录。
    • 索引文件:通常建立一张索引表,为每一个记录设置一个表项,以加速对于记录的检索速度。索引表本身就是一个定长记录的顺序文件,从而也就可以方便地实现直接存取。
    • 索引顺序文件:是上述两种文件方式的结合,它将顺序文件中的所有记录分为若干组(譬如50个记录为一组),并且为顺序文件建立一张索引表,在索引表中为每组中的第一个记录建立一个索引项,其中含有记录的键值和指向该记录的指针。

    索引顺序文件可能是最为常见的一种逻辑文件形式。它有效的克服了变长记录文件不便于直接存取的缺点,而且所付出的代价也在可接受的范围之内。

     

    ——流式文件(无结构文件):

    无结构的流式文件是相关的有序字符的集合(源程序文件、目标代码文件、文档文件等)。

    ——特点是:

    • 流式文件是指文件内的数据不再组成记录,只是依次的一串信息的集合。
    • 字符是构成文件的基本单位。
    • 读取经常按照长度来读取所需的信息,也可以使用插入的特殊字符作为分界。
    • 查找困难、管理简单。

    存储介质:

    常用的存储介质有磁盘、光盘、磁带、闪存等。

    ——一盘磁带、一个磁盘组或一张软盘都称为一。卷是存储介质的物理单位

    ——是存储介质上连续信息所组成的一个区域,也叫做物理记录。块是内存储器和辅助存储设备进行信息交换的物理单位,每次总是交换一块或整数块信息。块大小要考虑用户使用方式、数据传输效率和存储设备等因素。不同类型的存储介质块的大小常常不同,同一类型介质的块的大小也可能不同。

    文件的存储结构密切地依赖于存储设备的物理特性存储设备的特性也决定了文件的存取方法。

     

    顺序存储设备:

    ——什么是顺序存储设备?

    • 顺序存储存储设备是严格依赖信息的物理位置进行定位和读/写的存储设备。顺序存储设备只有在前面的物理块被访问之后,才能访问后续物理块的内容。

     

    我们以磁带机为例对顺序存储设备进行相关的介绍!

     

    磁带机是一种典型的顺序存储设备。

    ——磁带上的物理块没有确定的物理地址,只是由带上的物理标志来识别

    ——如果带速高,信息密度大,且所需块间隙小的话,则磁带存取速度和数据传输率高。

    • 什么间隙?为什要有它?
    • 块与块之间应当留有一定长度的间隙,用于磁带设备的启动与停止的缓冲。
    • 间隙是块之间不记录用户代码信息的区域。

    ——磁带的一个突出优点是物理块长的变化范围较大,块可以很小,也可以很大

    ——磁带作为顺序存储介质,具有存储容量大、稳定可靠、文件卷可拆卸、便于保存和块长变化范围较大等优点

    磁带的存储结构

     

    直接存储设备:

    ——什么是直接存储设备?

    • 直接存储设备又叫随机存储设备。允许文件系统直接存取对应存储介质上的任意物理块

     

    我们以磁盘机为例进行直接存储设备的介绍!

     

    磁盘机是一种典型直接存储存储设备。

    可移动磁头型磁盘

    ——各磁盘块的编号按柱面顺序(零号柱面开始,由外向里),每个柱面按磁道顺序(从上向下),每个磁道又按扇区顺序进行排序,假定用 t 表示每个柱面上的磁道数( 磁头/盘片),用 s 表示每个磁道上的扇区数,则第 i 柱面, j 磁头,k 扇区所对应的块号 b 可有如下公式确定:(位置决定块号)

    • b= (i×t+j)×s + k

    ——根据块号 p 也可确定该块在磁盘上的位置。每个柱面上有D =s×t个磁盘块,设M= p/D,N= p%D。于是,第P块在磁盘上位置为:(块号确定位置)

    • 柱面号= M= p/D= p/(s×t) 
    • 磁头号=N / s              
    • 扇区号=N % s

    磁盘机的特性与用途:

    ——磁盘具有直接读写的性质,并且物理块的大小固定不变,所以在这种介质上可以按照多种物理结构组织信息,并且不一定要求信息按逻辑记录的顺序存储。

    ——由于定位时间远远小于磁带设备的定位时间,因此广泛用于信息存储,并且作为虚拟存储器和虚拟设备使用。

    ——存储介质的容量逐渐增大,并且有些可像磁带一样随时更换,因而也作为保存档案材料之用,成为一种高速、大容量、可拆卸的海量存储器。


    文件的物理结构:

    文件的物理结构直接影响文件系统的性能。究竟采用哪种存储结构,需要根据存储设备类型、应用目标、响应时间和存储空间等多种因素进行权衡。

    文件的物理结构:

    ——磁带机是一种顺序存取的设备,一切组织在磁带上的文件都采用顺序结构,也就是将一个文件在逻辑上连续的信息存放到存储介质的依次相邻的块上,便形成顺序结构,磁带上的每个文件都有文件头标、文件信息和文件尾标三个组成部分。

    磁盘文件的组织形式

    文件的物理结构:

    顺序文件/连续文件:

    ——定义:将一个文件中逻辑上连续的信息存放到磁盘上的依次相邻的块上便形成顺序结构,这类文件叫顺序文件,又称连续文件。

    ——优点:顺序访问容易、速度快

    ——缺点:要求有连续的存储空间、必须事先知道文件的长度

     

    链接文件:

    ——定义:顺序的逻辑记录被存放在不连续的磁盘块上用指针把这些磁盘块按逻辑记录的顺序链接起来,则形成了文件的链接结构,链接结构的文件称为“链接文件”或“串联文件” 。

    ——特性:采取离散分配方式,从而消除了外部碎片,故可显著地提高辅存空间的利用率,且也无需事先知道文件的长度。磁盘上的所有空闲块都可以被利用。

    ——优点:消除了外部碎片、显著地提高外存空间的利用率、无需事先知道文件的长度 、插入删除记录容易。

    ——缺点:隐式链接,只适合于顺序访问、直接访问低效 、可靠性较差 ;显式连接,不能支持高效地直接存取、存放链接指针的FAT表会占用较大的内存空间。

    分类:

    • 隐式链接:在每个盘块中含有一个指向下一个盘块的指针。
    磁盘文件隐式链接示意图
    • 显式链接:把用于链接文件物理块的指针显式地存放在外存的一张链接表文件分配表(FAT)中。

    磁盘文件显式链接示意图

    和FAT表相关的计算:假定磁盘有n块,若2m-1≤n≤2m,则FAT表的每项至少有m位,但多数情况取整字节倍数,有时取半个字节倍数。

    计算举例:假定盘块的大小为1KB,硬盘的大小为500MB,采用显示链接分配方式时,该硬盘共有500K个盘块,故FAT中共有500K个表项;如果盘块从1开始编号,为了能保存最大的盘块号500K,该FAT表项最少需要19个比特位,将它扩展为半个字节的整数倍后,可知每个FAT表项需20位,即2.5个字节。因此,FAT需占用的存储空间的大小为:

    • 2.5×500K=1250KB。

     

    索引文件:

    ——定义:为每个文件分配一个索引块(用来存放索引的物理块),把分配给该文件的所有盘块号都记录在该索引块中,按照这种分配方式存储的文件就是索引文件。

    ——应用:一级索引、两级索引或多级索引结构。

    ——优点:支持直接访问,且不会产生外部碎片

    ——缺点:索引要花费较多的外存空间

    ——混合索引分配方式 :指将多种不同级的索引分配方式结合而形成的一种分配方式,有效且实用。

    混合索引分配方式

    相关计算题:索引文件的文件最大长度的计算

    • 题目:在UNIX中,其索引结构共有13个地址项,其中10项登记直接地址,1项一级索引,1项二级索引,1项三级索引。假如每个盘块的大小为4KB,一个盘块号占用4字节。计算支持的文件最大长度是多少。

    • 求解:直接地址项登记文件10个盘块,一级索引可登记1K个盘块,二级索引可登记1K×1K=1M个盘块,三级索引可登记1K×1K×1K =1G个盘块,允许文件长度=1G×4KB十1M×4KB十1K×4KB十40KB≥4TB。

     

    直接文件(散列/Hash):

    ——定义:在直接存取存储设备上,记录的关键字与其地址之间可以通过某种方式(函数)建立对应关系,利用这种关系实现记录存取的文件称为直接文件。

    ——“冲突”问题:地址的总数和记录的关键字之间并不存在一一对应的关系,不同的关键字经过变换可能会得到相同的地址。

    ——解决“冲突”方法:设计出好的变换函数,并且还要求有好的处理冲突的方法。

    ——优点:存取速度较快,存储空间不必连续,逻辑记录与物理记录之间不存在对应或顺序关系。

    ——缺点:对冲突的处理需要时间和空间的开销。

     

    设备、文件、存取方法之间的关系:

     

    三、文件目录:

    为什么引入文件目录?

    • 在现代计算机系统中,通常需要存储大量的文件。为了能有效地管理这些文件,必须对它们加以妥善的组织,以做到用户只需向系统提供所需访问文件的名字,系统就能快速、准确的找到指定文件
    • 这主要是以来文件目录来实现的,换句话说通过文件目录可以将文件名转换为改文件在外存上的物理位置。

    个人理解:就像日常生活中你去图书馆,书太多,找起来太费劲,所以才会有图书目录供你查询。

    文件目录管理应当达到的基本要求:

    ——实现“按名存取

    • 用户只需要提供文件名,就可以对文件进行存取。

    ——提高对目录的检索速度

    • 合理地组织目录结构,可以加快对于目录的检索速度,从而加快对于文件的存取速度。

    ——文件共享

    • 在多用户系统中,应当允许多个用户共享一个文件。

    ——允许文件重名

    • 系统应当允许不同用户对于不同文件用相同的名字,以便用户按照自己的习惯命名文件。

    文件控制块:

    概念:

    文件系统在创建每个文件时为其建立了一个文件目录,也称为文件说明文件控制块FCB。文件目录是为文件设置的用于文件描述和文件控制的数据结构,它与文件一一对应,它是随着文件的建立而诞生,随着文件的删除而消失,某些内容随着文件的使用而动态改变。

     

    文件控制块包括的内容:

    ——有关文件存取控制的信息:文件名、类型、文件属性等。

    ——有关文件结构的信息:逻辑结构、物理结构、存储位置。

    ——有关文件管理的信息:建立日期、修改日期等


    文件目录结构:

    文件系统把若干个文件的文件目录组织成一个独立的文件,这个全部由文件目录组成的文件称为目录文件。

    一级目录结构:

    ——实现方式:最简单的文件目录,在操作系统中,为每个磁盘设置一张线性表,每个文件的相关说明信息占用一个目录项。

    ——优点 :实现容易、管理简单、实现了按文件名存取 。

    ——缺点:搜索范围宽、不允许文件重名、 难于实现文件共享。

    二级目录:

    ——实现方式:第一级为主文件目录,用于管理所有用户的文件目录,它的目录项登记了系统用户的名字及该用户文件目录的地址。第二级为用户文件目录,它为该用户的每个文件保存一登记栏,其内容与一级目录的目录项相同。

    ——优点:实现了对文件的保密和保护、允许不同用户使用相同的文件名、可以实现文件共享。

    二级目录结构

    多级文件目录结构:

    ——实现方式:主文件目录演变为根目录。根目录项既可以表示一个普通文件,也可以是下一级目录的目录文件一个说明项。如此层层类推,形成了一个树型层次结构。

    ——优点:解决了文件重名问题、有利于文件的分类、便于制定保护文件的存取权限,有利于文件的保密。

    多级目录结构

    目录查找和目录的改进:

    目录的查找:即实现“按名存取”。

    线性检索法:

    ——一级目录结构采用顺序查找法,依次扫描文件目录的目录项,将目录项中的名字与欲查找的文件名相比较。

    ——在多级目录中,采用绝对路径和相对路径的查找方法,使用相对路径名查找速度要快于绝对路径

    • 绝对路径:由根目录沿各级子目录到达该文件的路径名。如:E:\BaiduNetdisk\skin\demo.java

    • 相对路径:就是从当前目录开始到文件的路径名。如:skin\demo.java

    ——查找举例:

    假设要查找绝对路径名为\usr\include\user.h的文件,从根目录查起,线性检索查找过程如下:

    • 第一步:从根目录查起,把根目录文件信息读到内存缓冲区。按给定的路径名中第一个分量usr依次与缓冲区中每个目录项比较,若找不到名为usr的目录项,则继续读入根目录文件的后续信息再比较,直到找到usr目录项或查完根目录都没有找到。

    • 第二步:找到usr后,再根据这个目录项内容把usr目录文件信息读到内存缓冲区。按第一步的过程,查找到include目录项。

    • 第三步:找到include后,再根据这个目录项内容把include目录文件信息读到内存缓冲区。按第一步的过程,查找到user.h目录项。

    哈希检索:

    ——目录项信息存放在一个哈希表中。进行目录检索时,首先根据目录名来计算一个哈希值,然后得到一个指向哈希表目录项的指针。

    ——哈希检索算法的难点,在于选样合适的哈希表长度和哈希函数的构造

    其他算法:

    ——除了上面的两种算法之外,还可以考虑其他算法,如B+树。

     

    目录的改进:目录文件只存储符号目录信息

    ——为何改进?

    • 一个文件目录项一般要占用很多空间,这样会导致目录文件往往很大。在查找目录时,为了找到所需的目录项,常常要将存放目录文件的多个物理块逐块读入内存进行查找,这就降低了查找速度。(个人理解:过大,多次调入,查找麻烦)

    ——如何改进?

    • 为加快目录查找可采用目录项分解法,即把目录项分为两部分符号目录项(包含文件名以及相应的文件号)和基本目录项(包含除了文件名外文件控制块的其余全部信息)。
    符号目录项和基本目录项

    计算举例:

    假设一个文件目录项占48个字节,符号目录项占8字节(文件名6字节,文件号2字节),基本目录项占48-6=42字节。设物理块大小512字节。假设目录文件有128个目录项。 若不分解目录项,一个盘块存放5l2/48 =10目录项,128个目录项需要13个盘块,查找一个文件的平均访问的盘块数:(1+13)/2=7次。

    分解后一个盘块存放5l2/8=64个符号目录项,128个符号目录项需要2个盘块,查找一个文件的平均访问的盘块数:(1+2)/2+1=2.5次。

     

    四、文件系统及其实现:

    文件系统的定义及其功能:

    文件系统的定义:

    文件系统是操作系统中负责管理和存取文件的程序模块。

     

    文件系统的功能:


    打开文件表:

    打开文件表有什么用?

    ——为了管理打开的文件

    系统打开文件表:

    ——该“系统打开文件表”放在内存,用于保存已打开文件的目录项。此外,还保存文件号、共享计数、修改标志等等。

    系统打开文件表

    用户打开文件表:

    ——每个进程一般都有一个“用户打开文件表”。该表的内容有文件描述符,打开方式、系统打开文件表入口等等。

    用户打开文件表

    用户打开文件表与系统打开文件表之间的关系:

    ——用户打开文件表指向了系统打开文件表。如果多个进程共享同一个文件,则多个用户打开文件表目对应系统打开文件表的同一入口


    外存空间的调度:

    主要讨论直接存储介质的空间分配。直接存储介质是分为若干个大小相等的物理块,并以块为单位来交换信息;因此存储空间管理实质上是空闲块的组织和管理问题(组织、分配、回收)。

    空闲块表法:

    ——数据结构:

    • 系统为每个磁盘建立一张空闲块表,表中每个登记项记录一组连续空闲块的首块号和块数,空闲块数为“0”的登记项为“空”登记项。
    空闲表块

    ——分配回收算法:

    • 这种管理方式适合采用顺序结构的文件 ,分配和回收算法类似内存储器的可变分区管理方式中采用的最先适应、最优适应和最坏适应算法。

    可变分区管理方式中采用的最先适应、最优适应和最坏适应算法。(相关详细介绍,👈点击直达!)

     

    空闲链表法:

    空闲盘块链:

    ——空闲盘块链以盘块为基本元素构成一条链

    ——分配时从链首开始依次摘下适当数目的空闲盘块分配给用户 ,回收时将回收的盘块依次链入空闲盘块链。

    ——优缺点:分配和回收一个盘块的过程非常简单,但是空闲盘块链可能很长。

    空闲盘区链:

    ——将磁盘上的所有空闲盘区(每个盘区可包含若干个盘块)拉成一条链。(与空闲块表相似)。

    ——分配方法与内存的动态分区分配类似,通常采用首次适应算法。在回收盘区时,同样也要将与回收区邻接的空闲盘区与之合并

    ——优缺点:分配和回收过程较复杂,但空闲盘区链较短。

     

    位示图法:

    ——磁盘块的组织:

    根据磁盘总块数决定位示图由多少字组成,位示图中的每一位与一个磁盘块对应,某位为“1”状态表示相应块已被占用,为“0”状态的位所对应的块是空闲块。

    • 一般公式为:块号=i×位示图中的字长+j 

    ——磁盘块的分配:

    当有文件要存放到磁盘上时,查位示图中为“0”的位,表示对应的磁盘块空闲可供使用。根据查到的位所在的字号和位号可计算出对应的块号,同时在该位填上占用标志“1”。(个人理解:查空闲、改标志!)

    ——磁盘块的回收:

    当删除文件归还存储空间时,可以根据归还块的块号推算出在位示图中的位置:

    • 块号=柱面号×每个柱面中的块数+磁头号×每个磁道的块数+扇区号
    • 字号=[块号/位示图中字长]
    • 位号=块号mod位示图中字长

    然后把这一位的“1”清成“0”,表示该块成为空闲块。

     

    成组链接法:

    ——空闲块的组织:

    把空闲块分成若干组,每组含有固定数目的空闲磁盘块;每一组的第一个空闲块中登记下一组空闲块的块号和空闲块数;余下不足100块的部分,登记在一个专用块中。

    空闲块成组链接示意图

    ——空闲块的分配:

    系统初始化时先把专用块内容读到内存储器,每分配一块后把空闲块数减1。但一组的第一个空闲块分配之前应把登记在该块中的下一组的块号及块数保存到专用块中。

    分配一个空闲块的算法:(假设专用块的内容已读到起始地址为L的内存区域中)

    分配一个空闲块的算法

    ——空闲块的回收:

    当归还一块时,只要把归还块的块号登记到当前组中空闲块数加1。如果当前组已满100块,则把内存中的内容写到归还的那块中,该归还块作为新组的第一块

    归还一块的算法:

    归还一块的算法

     

    五、文件的使用:

    主要操作:

    文件系统与用户的接口:

    • 第一类是与文件有关的操作命令作业控制语言中与文件有关的语句。这些构成了必不可少的文件系统的人机接口。
    • 第二类是提供给用户程序使用的文件类系统调用指令。通过这些指令用户能获得文件系统的各种服务。

    建立文件的过程:

    ——查文件目录表,看当前目录下有没有同名文件存在,有则拒绝建立,给出错误信息,否则分配给该文件一空目录项,并填入文件名和用户提供的参数。

    ——为要建立的文件分配存储空间

    ——将新建文件的目录项读入打开文件表中(即完成打开文件的工作),为以后写文件作好准备。

     

    打开文件的过程:

    ——根据文件路径名查目录。

    ——根据打开方式、共享说明和用户身份检查访问合法性

    ——根据文件号查系统打开文件表,看文件是否已被打开。如果是,共享计数加1,否则,信息填入系统打开文件表空表项,共享计数置为1。

    ——在用户打开文件表中取一空表项,填写打开方式等,并指向系统打开文件表对应表项

     

    关闭文件的过程:

    ——将打开文件表中该文件的“当前使用用户数”减1,若为0,则撤消此表目。

    ——若打开文件表目内容已被改过,则应先将表目内容写回辅存上相应表目中,以使文件目录保待最新状态;做卷定位工作。

     

    删除文件的过程:

    ——系统根据用户提供的文件名或文件描述符,检查此次删除的合法性

    ——查找文件目录。

    ——将该文件从目录中删除,并释放该文件所占用的存储空间

     

    读、写文件:

    ——核对所给参数的合法性

    ——按文件名从打开文件表中找到该文件的目录项

    ——按存取控制说明检查访问的合法性

    ——根据打开文件表中该文件的参数,确定读写的物理位置(确定块号、块数、块内位移与长度等)。

    ——向设备管理程序发I/O请求,完成数据交换工作

     

    为了保证对文件的正确管理和文件信息的安全可靠规定了用户请求文件的操作步骤:


    文件共享:

    文件共享可以提高文件的利用率避免存储空间的浪费,并能实现用户用自己的文件名去访问共享文件。实现文件共享通常有以下5种方法

    绕道法:

    ——用户对所有文件的访问都是相对于当前目录进行的,当所访问的共享文件不在当前目录下时,从当前目录出发向上返回到与共享文件所在路径的交叉点,再沿路径下行到共享文件

    ——绕道法要求用户指定到达被共享文件的路径,并要回溯访问多级目录,因此,共享其他目录下的文件的搜索速度较慢

    链接法:

    ——链接法是将一个目录中的链指针直接指向共享文件的目录项

    基本文件目录:

    ——文件目录分解为基本目录和符号目录,只要在不同文件符号目录中使用相同文件内部标识符,就可实现文件的共享。

    利用符号链实现文件共享:

    用户H为了共享用户C的—个文件f,可以由系统创建一个LINK类型的新文件,将新文件写入H的用户目录中,在新文件中只包含被链接文件f的路径名,称这样的链接方法为符号链接。当H要访问被链接的文件f且正要读LINK类新文件时,被操作系统截获,操作系统根据新文件中的路径名去读该文件,于是就实现了用户H对文件f的共享。

     

    基于索引结点的共享方式:

    采用索引结点,将诸如文件的物理地址及其它的文件属性等信息不再放在目录项中,而是放在索引结点中。在文件目录中只设置文件名及指向相应索引结点的指针,此时,由任何用户对文件进行追加操作或修改,所引起的相应索引结点内容的改变,例如,增加了新的盘块号和文件长度等,都是其他用户可见的,从而也就能提供给其他用户来共享。

    与基本文件目录类似。

    基于索引节点的共享图示

     

    六、文件系统的安全性和数据一致性:

    影响文件安全性主要因素:

    ——人为因素:由于人们有意或无意的行为,而使文件系统中的数据遭到破坏、丢失或窃取。

    ——系统因素:由于系统的部分出现异常情况而造成对数据的破坏或丢失,特别是作为数据存储介质的磁盘在出现故障或损坏时,会对文件系统的安全性造成影响。

    ——自然因素:存放在磁盘上的数据,随着时间的推移而发生溢出或逐渐消失


    防止人为因素造成的文件不安全性:

    隐蔽文件和目录:

    ——系统和用户将要保护的文件目录隐蔽起来,在显示文件目录信息时由于不知道文件名而无法使用。

    口令(密码):

    ——文件口令(文件密码):系统要求文件的建立者为他需要保密的文件设置一个口令。

    ——用户口令(用户密码):当用户利用计算机终端使用计算机时使用。

    文件加密:

    ——对于高度机密的文件,可采用加密码的措施。文件加密码是把文件中所有字符代码,按某种变换规则重新编码。文件的输入读出都经过编码程序和解码程序处理。

    制定访问权限:

    存取控制矩阵:

    ——由系统中的全部用户和全部文件组成的二维矩阵,称为存取控制矩阵,矩阵的每个元素表示用户对文件的使用权限

    存取控制表和用户权限表:

    ——存取控制表就是对存取控制矩阵中的一列进行压缩,可让每一个文件附加一个简单的表格,它规定了对该文件的可访问性(权限)

    ——用户权限表就是对存取控制矩阵中的一行进行压缩,该表中列出该用户对每个文件的访问权限


    防止自然因素或系统因素造成的文件不安全性:

    坏块管理:

    硬件方法:

    ——建立一个坏块表,在硬盘上为坏块表分配—个扇区,当控制器第一次被初始化时,它读坏块表并找一个空闲块(或磁道)代替有问题的块,并在坏块表中记录映射。

    软件办法:

    ——要求用户或文件系统构造一个包含全部坏块的文件

    磁盘容错技术,也称系统容错技术(System Fault Tolerance):

    通过在系统中设置冗余部件来提高系统可靠性的一种技术。

    • SFT-I是低级磁盘容错技术,主要用于防止磁盘表面发生缺陷所引起的数据丢失。
    • SFT-Ⅱ是中级磁盘容错技术,主要用于防止磁盘驱动器和磁盘控制故障所引起的系统不能正常工作。
    • SFT-Ⅲ是高级系统容错技术。提供了文件服务器镜像功能。在主服务器出现故障时能有备份服务器不间断地接替主服务器的工作。

    第一级容错技术(SFT-I):

    ——双份目录和双份文件分配表:建立两份目录表和FAT,一份称为主文件目录及FAT,另外一份则称为备份目录及备份FAT。

    ——热修复重定向:系统将一定的磁盘容量(例如2%~3%)作为热修复重定向区。用于存放当发现盘块有缺陷时的待写数据,并对写入该区的所有数据进行登记。以便于以后对数据进行访问。

    ——写后读校验:在每次从内存缓冲区向磁盘中写入一个数据块后,又立即从磁盘上读出该数据块,送至另一缓冲区中;再将该缓冲区中内容与内存缓冲区中在写后仍保留的数据进行比较,若两者一致,便认为此次写入成功,否则再重写。

    第二级容错技术(SFT-Ⅱ):

    ——磁盘镜像:磁盘镜像是在同一磁盘控制器下,再增设一个完全相同的磁盘驱动器

    磁盘镜像示意图

    ——磁盘双工:将两台磁盘驱动器分别接到两个磁盘控制器上,同样地使这两台磁盘机镜像。(完美的解决了磁盘控制器或者主机到磁盘控制器之间的通道发生故障的情况,这是磁盘镜像所没有解决的问题。)

    磁盘双工示意图

    独立磁盘冗余阵列(RAID):(因为相关的介绍过于庞大,会影响整篇文章的结构,故另外介绍,点击以下链接直达!)

    操作系统:独立磁盘冗余阵列(RAID)的相关介绍(👈)

    备份:

    ——建立副本:把同一个文件保存到多个存储介质上,当某个文件损坏或丢失时,就可用其他存储介质上的备用副本来替换。

    ——转储:海量转储、增量转储

    • 海量转储:把存储器中的全部文件定期复制到备用存储介质上。但是转储会浪费大量的时间和影响用户的工作,一个小小的故障就需要所有的用户文件进行转储,所以最好是在空闲时间进行转储。
    • 增量转储:在相当短的时间里把上一次转储以来改变过的文件(包括控制块)和新文件转储到备用存储介质上,关键性的重要文件也可以再次转储;这种方法克服了海量转储的缺点,但是转储到磁盘上的信息不紧凑,浪费存储空间。

    文件系统的数据一致性:

    许多文件系统在读取磁盘块进行修改之后,再写回磁盘。如果在修改过的磁盘块全部写回之前,系统崩溃,则文件系统很有可能会处于不一致的状态。如果一些未被写回的块是目录块或者包含空闲表的磁盘块,这个问题会尤为严重。

    为了解决文件系统的不一致问题,一些计算机会带有一个实用程序以检验文件系统的一致性。

    一致性检查分为两种块的一致性检查和文件的一致性检查。

    块的一致性检查:

    为了保证盘块数据结构的一致性,可利用软件方法构成一个计数器表,每个盘块对应一个表项,每一表顶中包含两个计数器,分别用作空闲盘块号计数器数据盘块号计数器。

    正常情况下,上述两组计数据中对应的一对计数器中的数据应互补,亦某个盘块在第一组计数器中数器值为1,则在第二组计数器中计数器内容必为0,反之亦然。但如果情况并非如此时,说明发生了某种错误。

    盘块一致性检查情况

    文件的一致性检查:

    ——重复文件的数据一致性 :在有重复文件时,如果—个文件拷贝修改了,则必须同时修改它的几个文件拷贝,保证该文件中数据的一致性。可以采用两种方法进行实现:

    • 当一个文件被修改之后,可以查找文件目录,得到其另外副本的物理位置,然后对他们进行同样的修改。(修改)
    • 为新修改的文件建立几个副本,并用它们替代原来的文件副本。(替代)

    ——共享文件的数据一致性 :文件的共享计数和当前共享该文件的用户个数相一致

     

    七、磁盘调度:

    提高文件系统的性能措施:

    块高速缓存:

    ——系统在内存中保存一些存储块,这些存储块在逻辑上它们属于磁盘。

    ——工作时,系统检查所有的读请求,看所需的文件块是否在高速缓存中。如果在,则可直接在内存中进行读操作。否则,首先要将块读到高速缓存中,再拷贝到所需的地方。

    磁盘空间的合理分配:

    ——在磁盘空间中分配块时,应该把有可能顺序存取的块放在一起,最好在同一柱面上。这样可以有效地减少磁盘臂的移动次数,加快文件的读写速度,提高性能。

    对磁盘调度算法进行优化


    磁盘I/O(输入输出)时间:

    采用移动磁头的磁盘要访问某特定的物理块时,所用时间一般包括三部分

    ——查找时间:

    • 按给定的柱面号(磁道号)将读写磁头移动指定的柱面或磁道上的时间。

    ——等待时间:

    • 等待磁盘旋转,使读写的块位于读写磁头之下的时间。

    ——传输时间:

    • 内存和磁盘之间数据的实际传送所用的时间。

    磁盘的移臂调度算法:

    先来先服务调度算法FCFS:

    ——算法:根据访问请求的先后次序选择先提出访问请求的为之服务。

    ——优缺点:是磁盘调度的最简单的一种形式,它既容易实现,又公平合理,缺点是效率不高

    最短查找时间优先算法SSTF:

    ——算法:以磁头移动距离的大小作为优先的因素,从当前磁头位置出发,选择离磁头最近的磁道为其服务。

    ——优缺点:减少了磁道平均查找时间,但没考虑磁头移动的方向,也没有考虑进程在队列中等待的时间。

    扫描算法:

    电梯调度算法SCAN:

    ——算法:是选请求队列中沿磁头臂前进方向最接近于磁头所在柱面的访问请求作为下一个服务对象。

    ——优缺点:算法简单、实用且高效,克服了最短寻道优先的缺点,既考虑了距离,同时又考虑了方向,但有时有的请求等待时间可能很长。

    例如,如果在为访问43号柱面的请求者服务后,当前正在为访问67号柱面的请求者服务,同时有若干请求者在等待服务,它们依次要访问的柱面号为186,47,9,77,194,150,10,135,110。

    • 按照先来先服务的策略,处理顺序:186→47→9→77→194→150→10→135→110。
    • 用最短查找时间优先算法服务的顺序为:     77→47→10→9→110→135→150→186→194。
    • 用电梯调度算法,服务次序为:     77→110→135→150→186→194→47→10→9。

     

    N步扫描策略:

    ——N步SCAN算法是将磁盘请求队列分成若干个长度为N的子队列,磁盘调度将按FCFS算法依次处理这些子队列。而每处理一个队列时又是按SCAN算法,对一个队列处理完后,再处理其他队列。

    ——当正在处理某子队列时,如果又出现新的磁盘I/O请求,便将新请求进程放入其他队列,这样就可避免出现粘着现象。

    循环扫描策略:

    ——磁盘单向移动。当移动臂向内移动时,它对本次移动开始前到达的各访问要求自外向内地依次给予服务,直到对最内柱面上的访向要求满足后,然后移动臂直接向外移动,停在所有新的访问要求的最外边的柱面上。然后再对本次移动前到达的各访问要求依次给予服务。

    FSCAN算法:

    ——FSCAN算法实质是N步SCAN算法的简化。

    ——将磁盘请求访问队列分成两个子队列,一是当前所有请求磁盘(I/O)的进程形成的队列,由磁盘调度按SCAN算法进行处理。另—个队列则是在扫描期间,新出现的所有请求磁盘I/O进程的队列,把它们排入另一个等待处理的请求队列。


    磁盘的优化分布:

    有些系统,对数据的存放位置进行优化分布可减少延迟时间,从而缩短了输入输出操作的时间。

    实际举例:

    某系统对磁盘初始化时把每个盘面分成8个扇区,今有8个逻辑记录被存放在同一个磁道上供处理程序使用,处理程序要求顺序处理这8个记录,每次请求从磁盘上读一个记录,然后对读出的记录要花5毫秒的时间进行处理,以后再读下一个记录进行处理,直至8个记录都处理结束。假定磁盘转速为20毫秒/周,现把这8个逻辑记录依次存放在磁道上,如图 (a)所示。

    (a)读一个记录要花2.5毫秒的时间。当花了2.5毫秒的时间读出第1个记录并花5毫秒时间进行处理后,读写磁头已经在第4个记录的位置,为了顺序处理第2个记录,必须等待磁盘把第2个记录旋转到读写磁头位置下面,即要有15毫秒的延迟时间。处理这8个记录所要花费的时间为:

    • 8×(2.5+5)+7×15=165(ms)  

    (b)是这8个逻辑记录的最优分布。当读出一个记录处理后,读写磁头正好位于顺序的下一个记录位置,可立即读出该记录,不必花费等待延迟时间。于是,处理这8个记录所要花费的时间为:

    • 8×(2.5+5)=60(ms)

     

    Ending... ...

    展开全文
  • 酒店管理系统(源码+数据库)

    千次阅读 2021-03-29 11:10:13
    刚做这个类型的管理系统可以学习下,有营业报表和统计图! 文件:590m.com/f/25127180-487341271-871696(访问密码:551685) 【实例截图】 以下内容无关: -------------------------------------------分割线--...

    【实例简介】S1的一个结业项目,有些细节还不够完善,总体来说还算是不错的!刚做这个类型的管理系统可以学习下,有营业报表和统计图!

    文件:590m.com/f/25127180-487341271-871696(访问密码:551685)

    【实例截图】
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    以下内容无关:

    -------------------------------------------分割线---------------------------------------------

    京东到家APP的引导页做的可圈可点,插画+动效,简明生动地说明了APP最吸引用户的几个亮点(商品多,价格低,配送快…)。本文主要分析拆解这些动画效果,并完成一个高仿Demo,完整的Demo代码可在文章结尾获取。

    先看一下京东到家APP引导页动画效果,如下:

    京东到家APP引导页

    功能分析
    分析结果基于对APP进行反编译和我个人的理解(不然还能怎么办呢?我太难了,哈哈哈)

    浅浅的背景图+四个引导页面,每一个页面动画播放完成后自动滑动到下一个页面。实现:用ViewPager+4个View实现,每一个页面对应一个View,一个View包含一个LottieAnimationView,在页面中监听Lottie动画的播放,播放完成后自动切换到下一个页面,ViewPager使用的是Alibaba开源的UltraViewPager
    背景图片 引导图1 引导图2 引导图3 引导图4
    background.png 1.png 2.png 3.png 4.png
    页面滑动切换时有一个旋转动画效果,可自定义ViewPager中的PageTransformer接口实现此效果,Title有透明度渐变效果,用属性动画ObjectAnimator实现
    switch.gif

    当滑动到最后一个页面时,出现一个带有“立即体验”文本的按钮,出现时从底部向上弹出并且透明度从0到1变化,当从最后一个页面向前滑动时,按钮从底部消失并且透明度从1到0变化,即位移+透明度变化动画,使用属性动画ObjectAnimator可以实现此效果
    last.webp

    布局分析
    使用uiautomatorviewer查看layout布局文件,如下所示:

    layout.webp

    根布局为ConstraintLayout,子节点为ViewPager,xml文件如下:

    <?xml version="1.0" encoding="utf-8"?>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”
    xmlns:app=“http://schemas.android.com/apk/res-auto”
    android:layout_width=“fill_parent”
    android:layout_height=“fill_parent”
    android:background="@android:color/white">

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottie_bg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />
    
    <com.tmall.ultraviewpager.UltraViewPager
        android:id="@+id/viewpager"
        android:layout_width="0.0dip"
        android:layout_height="0.0dip"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/lottie_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
    <ImageView
        android:id="@+id/ivJump"
        android:layout_width="46.0dip"
        android:layout_height="0.0dip"
        android:layout_marginRight="20.0dip"
        android:background="@drawable/pdj_guide_jump"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="63:28.5"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.07" />
    
    <ImageView
        android:id="@+id/iv_start"
        android:layout_width="104.29999dip"
        android:layout_height="30.669983dip"
        android:background="@drawable/pdj_guide_button"
        android:focusable="true"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />
    

    </androidx.constraintlayout.widget.ConstraintLayout>

    引导页总共有四个页面,每一个页面中LottieAnimationView对应一个Lottie文件,xml文件如下:

    <?xml version="1.0" encoding="utf-8"?>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”
    xmlns:app=“http://schemas.android.com/apk/res-auto”
    android:layout_width=“fill_parent”
    android:layout_height=“fill_parent”>

    <com.airbnb.lottie.LottieAnimationView
        android:id="@+id/pdj_guide_lottie_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />
    

    </androidx.constraintlayout.widget.ConstraintLayout>
    资源分析
    资源文件放在了src/main/assets目录下,配置文件为LottieConfig.json,如下:
    {
    “radius”: 2020,
    “totalPageNum”: 4,
    “lottieBgName”: “guide_lottie_bg”,
    “pageAnimTime”: 350,
    “buttonAnimTime”: 350,
    “lottieTitle”: [
    {
    “lottieName”: “title_lottie_0”
    },
    {
    “lottieName”: “title_lottie_1”
    },
    {
    “lottieName”: “title_lottie_2”
    },
    {
    “lottieName”: “title_lottie_3”
    }
    ],
    “lottieMain”: [
    {
    “lottieName”: “main_lottie_0”
    },
    {
    “lottieName”: “main_lottie_1”
    },
    {
    “lottieName”: “main_lottie_2”
    },
    {
    “lottieName”: “main_lottie_3”,
    “repeatInterval”: {
    “start”: 0.288,
    “end”: 1
    }
    }
    ]
    }
    radius --定义PageTransformer时会用到,用于确定最大旋转角度
    totalPageNum --引导页的数量
    lottieBgName --背景图片对应的Lottie文件名
    pageAnimTime --ViewPager各个页面之间切换的滑动时间
    buttonAnimTime --最后一个页面"立即体验"按钮做位移和透明度动画的时长
    lottieTitle --每个引导页标题对应的Lottie文件名
    lottieMain – 每个引导页内容对应的Lottie文件名
    代码实现
    基于以上分析,用代码实现就比较简单了,此处贴出部分实现代码

    加载本地Lottie zip文件,Lottie支持加载本地和远程json,zip文件,通常我们将Lottie文件放在src/main/assets目录下
    fun loadAssetsLottieZipFile(context: Context, lottieImageView:LottieAnimationView, fileName:String,repeatCount:Int= LottieDrawable.INFINITE,autoPlay:Boolean=true){
    val lottieCompose= if(fileName.endsWith(".zip")){
    LottieCompositionFactory.fromAssetSync(context, fileName).value
    }
    else{
    LottieCompositionFactory.fromAssetSync(context, fileName.plus(".zip")).value
    }
    lottieImageView.progress=0.0f
    lottieImageView.repeatCount=repeatCount
    lottieImageView.setComposition(lottieCompose!!)
    if(autoPlay){
    lottieImageView.playAnimation()
    }

    }
    

    添加圆点指示符
    viewpager.initIndicator()
    viewpager.indicator.setOrientation(UltraViewPager.Orientation.HORIZONTAL)
    .setNormalIcon(drawableToBitmap(ContextCompat.getDrawable(applicationContext, R.drawable.guide_white_dot)!!))
    .setFocusIcon(drawableToBitmap(ContextCompat.getDrawable(applicationContext, R.drawable.guide_dark_dot)!!))
    .setIndicatorPadding(ScreenHelper.dp2px(applicationContext, 5.0F))
    .setMargin(0, 0, 0, ScreenHelper.dp2px(applicationContext, 20.0F))
    viewpager.indicator.setGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
    viewpager.indicator.build()
    其中drawableToBitmap对应的代码为:

    /**
     * Drawable转换成Bitmap
     */
    private fun drawableToBitmap(drawable: Drawable): Bitmap {
        val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
        drawable.draw(canvas)
        return bitmap
    }
    

    自定义PageTransformer实现页面切换旋转效果

    position < -1 时,旋转到最大角度,旋转中心为右下角;
    -1 < position < 0 时,position 越靠近 0 ,旋转角度越小,旋转中心向下边缘中心靠拢;
    0 <= position <= 1 时,position 越靠近 0 ,旋转角度越小,旋转中心向下边缘中心靠拢;
    position > 1 时,旋转到最大角度,旋转中心为左下角。
    代码如下所示:

    import android.content.Context
    import android.view.View
    import androidx.viewpager.widget.ViewPager
    import com.kongpf.commonhelper.ScreenHelper
    import kotlin.math.atan2

    class GuideTransformer(context: Context, private val mRadius: Int) : ViewPager.PageTransformer {
    private var mMaxRotate = 0f

    init {
        if (mRadius > 0) {
            mMaxRotate = (2.0 * Math.toDegrees(atan2((ScreenHelper.getScreenWidth(context) / 2).toDouble(), mRadius.toDouble()))).toFloat()
        }
    }
    
    override fun transformPage(page: View, position: Float) {
        if (mRadius == 0) {
            return
        }
    
        when {
            position < -1.0f -> {
                page.rotation = -1.0f * mMaxRotate
                page.pivotX = page.width.toFloat()
                page.pivotY = page.height.toFloat()
            }
            position <= 1.0f -> {
                if (position < 0.0f) {
                    page.pivotX = page.width * (0.5f + 0.5f * -position)
                    page.pivotY = page.height.toFloat()
                    page.rotation = position * mMaxRotate
                } else {
                    page.pivotX = 0.5f * page.width * (1.0f - position)
                    page.pivotY = page.height.toFloat()
                    page.rotation = position * mMaxRotate
                }
            }
            else -> {
                page.rotation = mMaxRotate
                page.pivotX = 0f
                page.pivotY = page.height.toFloat()
            }
        }
    }
    

    }

    展开全文
  • 天人文章管理系统是asp+access/mssql架构网站系统,如对默认模板不满意,在后台可更换其他模板。电脑版,手机版,平板版无缝自动切换,一个后台同步管理,支持seo整站静态化及动态切换,一键更换模板、安装插件、...
  • 初探Linux系统

    千次阅读 2019-06-09 22:29:52
    初探Linux系统前言学习的框架认识Linux系统文件树流图文件树结构释义:电子书链接 前言 linux是一个很强大开源的系统,笔者作为一个嵌入式Linux学习者,同样被Linux的开源文化深深的吸引着。对于大部分职业可能...
  • 天人文章管理系统是asp+access/mssql架构网站系统,如对默认模板不满意,在后台可更换其他模板。电脑版,手机版,平板版无缝自动切换,一个后台同步管理,支持seo整站静态化及动态切换,一键更换模板、安装插件、...
  • Linux文件系统详解

    万次阅读 多人点赞 2019-05-29 16:07:53
    从操作系统的角度详解Linux文件系统层次、文件系统分类、文件系统的存储结构、不同存储介质的区别(RAM、ROM、Flash)、存储节点inode。本文参考: http://blog.chinaunix.net/uid-8698570-id-1763151.html ...
  • 无忧中英文PHP企业网站管理系统专业版(手机版和电脑端同步数据自适应界面浏览)是采用PHP MYSQL技术和MVC模式进行开发的,架构清晰,代码易于维护。支持静态功能,可生成google和百度地图, 支持自定义url、...
  • 内容管理系统CMS学习总结

    千次阅读 2016-09-01 14:17:28
    CMS (内容管理系统) CMS是Content Management System的缩写,意为"内容管理系统"。 内容管理系统是企业信息化建设和电子政务的新宠,也是一个相对较新的市场。对于内容管理,业界还没有一个统一的定义,不同的...
  • 目录 ...3.Linux下的文件管理  3.11文件的批处理命令(通配符与精确匹配) (Java学习记录)Linux部分-Linux的构成和基本操作指令 Linux安装好了就可以开始学习操作了,Linux是一个看起来很...
  • 无忧中英文PHP企业网站管理系统专业版(手机版和电脑端同步数据自适应界面浏览)是采用PHP+MYSQL技术和MVC模式进行开发的,架构清晰,代码易于维护。支持静态功能,可生成google和百度地图, 支持自定义url、...
  • 学生成绩管理系统(六):项目总结 一、项目实现情况 初期项目计划: 简单的图形界面登录功能。 对数据库的的信息的查询功能。 对数据库的的信息的修改功能。 对数据库的的信息的删除功能。 对数据库的的信息的添加...
  • Linux驱动开发_设备文件系统详解

    千次阅读 多人点赞 2021-05-11 14:09:24
    以上的前提下是你的设备是流行设备且被操作系统的设备管理器支持的情况下,倘若我们有一个未知的设备,或者是我自己开发的硬件产品,如我们自己写的键盘,我们不使用通用键盘通讯协议,我们非要自己创建一套我们键盘...
  • 操作系统(内存管理)

    热门讨论 2009-09-20 12:55:25
    主分配程序的伪代码 1. If our allocator has not been initialized, initialize it. 2. Add sizeof(struct mem_control_block) to the size requested. 3. start at managed_memory_start. 4. Are we at last_...
  • c++实现学生信息管理系统

    千次阅读 2020-06-01 19:10:36
    实验内容: 对学生信息管理系统,要求完成以下基本任务: 1.改写程序为良好程序风格(文档注释,函数注释,语句注释)。 2.将功能补充完全(基于文件处理,完成...概要设计(包括数据结构及算法绘制流程图或伪代码表示)
  • 蛋糕连锁店网站管理系统是海南赞赞网络公司针对甜品糕点连锁企业开发的建站系统。程序主要采用了 thinkphp5内核开发,拥有独立自主的标签系统、函数系统、极方便二次开发,网站设计人员可以在该系统基础上设计出漂亮...
  • 常用的静态规则文件在 temp/rewrite 文件夹里,IIS或者apache直接复制里面的文件到根目录即可 注:temp文件夹要有读写权限 TXTCMS内容管理系统 x1.2更新日志: 1.修复父栏目列表不显示栏目文章 2.后台编辑器...
  • 数据库修改了路径做了目录并且加了数据库:) 后台管理登陆也简化了我的其他站都这样的... 并且送上一个火狐的广告代码页很漂亮的. 网站后台:admin/admin.asp 后台ID/密码:admin610861887 由于新云的友情连接被...
  • 无忧PHP企业网站管理系统是采用PHP MYSQL技术和MVC模式进行开发的,架构清晰,代码易于维护。支持静态功能,可生成google和百度地图,支持自定义url、 关键字和描述,符合SEO标准。拥有企业网站常用的模块功能...
  • 天人文章管理系统(带手机版)v4.75 GB2312更新日志 优化静态插件的安装接口 程序支持目录,支持放到站点的下级,或多级目录中。 1、后台服务器信息查看功能能够快速、全面的查看服务器的软硬件状况。 2、站点...
  • 天人文章管理系统是asp access/mssql架构网站系统,如对默认模板不满意,在后台可更换其他模板。电脑版,手机版,平板版无缝自动切换,一个后台同步管理,支持seo整站静态化及动态切换,一键更换模板、安装插件、...
  • 天人文章管理系统是asp+access/mssql架构网站系统,如对默认模板不满意,在后台可更换其他模板。电脑版,手机版,平板版无缝自动切换,一个后台同步管理,支持seo整站静态化及动态切换,一键更换模板、安装插件、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 40,695
精华内容 16,278
关键字:

文件管理子系统伪代码