【Ruby学习笔记】6:模拟OS文件操作与管理
2018-01-29 00:47
435 查看
学到这里终于能用Ruby写点程序了,拿操作系统上机作业练习一下。
要求设计一个模拟的文件系统,有主文件目录(MFD)和用户文件目录(UFD)。我用一个文件去模拟磁盘,把这两项内容都写进磁盘里(这些断电不丢失的肯定需要在外存存着)。
不需要真的实现读写,只要更改文件读写指针,而且这些读写指针一断电自然就没有了(电子书’书签’那种不算),用一个Ruby数组(其实也可以只用后面的哈希表)作为打开文件目录,但是我只用这个记录文件名,保护码放在外存不会变的(这题不用做chmod这种命令),然后文件指针我用一个哈希表来存(这个比数组快很多吧),而且只在真正用到文件指针的时候才去往哈希表里添加东西。
Ruby的哈希表有一大好处就是能指定一个默认值,如果查询哈希表项不存在的时候会返回那个值,正好在这题里设置默认值是0,很方便。
Ruby的
假设只有10个用户,每个用户最多只能建立10个文件,每个文件的最大长度是99(这个长度其实很好加,但是懒得去作变长行尾的判断读入了)。
要求设计一个模拟的文件系统,有主文件目录(MFD)和用户文件目录(UFD)。我用一个文件去模拟磁盘,把这两项内容都写进磁盘里(这些断电不丢失的肯定需要在外存存着)。
不需要真的实现读写,只要更改文件读写指针,而且这些读写指针一断电自然就没有了(电子书’书签’那种不算),用一个Ruby数组(其实也可以只用后面的哈希表)作为打开文件目录,但是我只用这个记录文件名,保护码放在外存不会变的(这题不用做chmod这种命令),然后文件指针我用一个哈希表来存(这个比数组快很多吧),而且只在真正用到文件指针的时候才去往哈希表里添加东西。
Ruby的哈希表有一大好处就是能指定一个默认值,如果查询哈希表项不存在的时候会返回那个值,正好在这题里设置默认值是0,很方便。
Ruby的
case-when-..-else-end很好用,做保护码解析的时候太方便了。
假设只有10个用户,每个用户最多只能建立10个文件,每个文件的最大长度是99(这个长度其实很好加,但是懒得去作变长行尾的判断读入了)。
代码
#!/usr/bin/ruby #一开始打算把文件目录项做成class的,结果发现实际要用的就两个成员 #而且文件名(或者文件号)都是一种候选键 #所以完全可以用哈希表{key-value}即{文件名-指针位置} #打开文件目录项,一定是在内存中的 #所以不写进模拟磁盘的./MyFileSys里 #这个OpenFile类没有被使用 class OpenFile def initialize(name,pro,p=0) @name=name #打开文件号(名) @rw_point=p #读写指针,普通模式就是从头开始 end #设置读写指针 def setPoint(p) @rw_point=p end #获取读写指针 def getPoint() return @rw_point end end #登录的用户,为了OOP,方法都在这里 class USR #因为各个用户用的文件系统都一样,这里显然用类变量 @@ept="......................" #表示此处没有文件,删除用 #这两个就要用实例变量了,在类外定义才不是nil #但是我用实例变量总提示是nil(空)!!!这是个遗留问题 #没办法暂时只能用类变量 @@open_array=Array.new() #打开文件目录,初始为空 @@hash_tab=Hash.new(0) #哈希表,用来关联文件名->指针位置,默认值是0 #new是通过调用initialize产生了一个对象实例 def initialiaze() #定义一些和具体用户有关的需要及时用上的实例变量 @usr_name=nil #用户名 @UFD_point=nil #用户文件目录指针 end #设置用户名 def setName(name) @usr_name=name end #设置其用户文件目录的行号 def setPoint(p) @UFD_point=p end #获取其用户文件目录的行号 def getPoint() return @UFD_point end #展示文件目录 def showDic() puts("--下面是你的UFD(用户文件目录)--") puts("文件名 保护码 文件长度") file=File.open("./MyFileSys","r") #文件指针向后偏移的同时正好存下偏移量@bais file.seek(@bais=10*15+(@UFD_point-11)*23) @str=file.sysread(10*23) puts(@str) file.close() end #查找能放置新文件的表项 def findNew() file=File.open("./MyFileSys","r") file.seek(@bais) for i in 0..9 do line=file.sysread(23) if line[0..3]=="....": #说明这里有文件了 file.close() #return之前别忘了close()文件 return i end end file.close() return -1 end #在num位置创建文件filename的方法 def createFile(num,filename) ok=false until true==ok do ok=true puts(">>请输入新文件的保护码:") pro=gets().chomp() case pro when "rwx","111","7" puts("将被解析为#{pro="rwx"}") when "rw-","110","6" puts("将被解析为#{pro="rw-"}") when "r-x","101","5" puts("将被解析为#{pro="r-x"}") when "r--","100","4" puts("将被解析为#{pro="r--"}") when "-wx","011","11","3" puts("将被解析为#{pro="-wx"}") when "-w-","010","10","2" puts("将被解析为#{pro="-w-"}") when "--x","001","01","1" puts("将被解析为#{pro="--x"}") when "---","000","00","0" puts("将被解析为#{pro="---"}") else ok=false puts("[ERROR]不合法的保护码") end #end case end #end until #只往UFD用户文件目录里写 file=File.open("./MyFileSys","r+") #按文件指针写的读写模式 file.seek(@bais+23*num) file.syswrite(filename+" "*(10-filename.length)+pro+" "*(10-pro.length)+"00") #新建的文件大小是0字节 file.close() end #判断以及调用createFile(num)方法 def createJudge(num) ok=false until true==ok do ok=true #在判断中发现不符合条件的就置false puts(">>请输入文件的名称:") filename=gets().chomp() if filename.length==0: puts("[ERROR]未输入") ok=false elsif filename.length>9: puts("[ERROR]太长了") ok=false elsif filename.length>filename.gsub(' ','').length: puts("[ERROR]有空白字符") ok=false else #判断有没有文件重名 file=File.open("./MyFileSys","r") file.seek(@bais) for i in 0..9 do line=file.sysread(23) if /^#{filename} /.match(line): puts("[ERROR]存在文件重名") ok=false break #这里仅仅是跳出for end #end if end #end for file.close() end #end if-elsif-...-else end #end until createFile(num,filename) #出了循环体才在这里创建文件 puts("[SUCCESS]创建文件成功") end #end def #判断并删除文件,这个设计成不会一直循环要求 #而创建文件设计成这样的原因是 #如在图形界面下创建,在用户为文件命名之前就真的创建好了 def delFile() ok=-1 #表示还没有删除文件 puts(">>请输入要删除的文件的名称:") filename=gets().chomp() file=File.open("./MyFileSys","r+") file.seek(@bais) for i in 0..9 do line=file.sysread(23) if /^#{filename} /.match(line): #当发现这个文件时 puts(line) ok=i #在循环里不能做,传给ok拿到外面做 break #这里仅仅是跳出for end #end if end #end for if -1==ok: puts("[ERROR]不存在的文件") else #实在无奈!不知道为什么总是追加模式!只能重新打开文件 file.close() file=File.open("./MyFileSys","r+") file.seek(@bais+23*ok,IO::SEEK_SET) #指针到达该行行首 #puts(file.sysread(23)) file.syswrite(@@ept) #用一堆"."覆盖掉即可 #从打开目录表中删除(即考虑万一没关闭就删的情况) @@open_array.delete(filename) #哈希表中应删除之(不再存其读写指针位置) @@hash_tab.delete(filename) puts("[SUCCESS]删除成功") end file.close() end #打开文件,也设计成不会一直循环要求 def openFile() ok=-1 #表示还没有打开文件 puts(">>请输入你要打开的文件名:") filename=gets().chomp() file=File.open("./MyFileSys","r+") file.seek(@bais) for i in 0..9 do line=file.sysread(23) if /^#{filename} /.match(line): #当发现这个文件时 if @@open_array.include?(filename)==true: #如果已经打开了 puts("[ERROR]已经打开过了") ok=i #把i传到外面 break #这里仅仅是跳出for end @@open_array.push(filename) #添加进打开目录表中 puts("[SUCCESS]"+filename+"成功打开了") ok=i #把i传到外面 break #这里仅仅是跳出for end #end if end #end for if -1==ok: puts("[ERROR]不存在的文件") end file.close() end #关闭文件,也设计成不会一直循环要求 def closeFile() ok=-1 #表示还没有关闭文件 puts(">>请输入你要关闭的文件名:") filename=gets().chomp() file=File.open("./MyFileSys","r+") file.seek(@bais) for i in 0..9 do line=file.sysread(23) if /^#{filename} /.match(line): #当发现这个文件时 if @@open_array.include?(filename)!=true: #如果已经关闭了 puts("[ERROR]这个文件没有打开,不需关闭") ok=i #把i传到外面 break #这里仅仅是跳出for end @@open_array.delete(filename) #从打开目录表中删除 @@hash_tab[filename]=0 #关闭文件后,读写指针显然要清到0 puts("[SUCCESS]"+filename+"成功关闭了") ok=i #把i传到外面 break #这里仅仅是跳出for end #end if end #end for if -1==ok: puts("[ERROR]不存在的文件") end file.close() end #读文件 def readFile() ok=-1 #表示还没有读文件 puts(">>请输入你要读的文件名:") filename=gets().chomp() file=File.open("./MyFileSys","r") file.seek(@bais) for i in 0..9 do line=file.sysread(23) if /^#{filename} /.match(line): #当发现这个文件时 if @@open_array.include?(filename)!=true: #如果已经关闭了 puts("[ERROR]这个文件还没打开,不能读") ok=i #把i传到外面 break #这里仅仅是跳出for elsif line[10..10]=="-" #如果没有读权限 puts("[ERROR]你没有读取它的权限") ok=i #把i传到外面 break #这里仅仅是跳出for end puts(">>请输入你要读的字节数") readnum=gets().chomp().to_i() #把要读的字节数加到当前文件指针位置上 readnum+=@@hash_tab[filename] allnum=line[20..21].to_i() #在外存查总字节数 #(仅当第一次需要读或者写时)存进哈希表里 @@hash_tab[filename]=readnum>allnum ? allnum : readnum if readnum>allnum: puts("[SUCCESS]现在,已经读到文件尾(#{allnum})") else puts("[SUCCESS]现在,文件指针在#{readnum}处") end ok=i #把i传到外面 break #这里仅仅是跳出for end #end if end #end for if -1==ok: puts("[ERROR]不存在的文件") end file.close() end #写文件 def writeFile() ok=-1 #表示还没有写文件 puts(">>请输入你要写的文件名:") filename=gets().chomp() file=File.open("./MyFileSys","r+") file.seek(@bais) for i in 0..9 do line=file.sysread(23) if /^#{filename} /.match(line): #当发现这个文件时 if @@open_array.include?(filename)!=true: #如果已经关闭了 puts("[ERROR]这个文件还没打开,不能写") ok=i #把i传到外面 break #这里仅仅是跳出for elsif line[11..11]=="-" #如果没有写权限 puts("[ERROR]你没有写入它的权限") ok=i #把i传到外面 break #这里仅仅是跳出for end puts(">>请输入你要从哪个位置开始写") position=gets().chomp().to_i() allnum=line[20..21].to_i() #在外存查总字节数 if position>allnum or position<0: puts("[ERROR]非法的位置") ok=i #把i传到外面 break #这里仅仅是跳出for end #(仅当第一次需要读或者写时)存进哈希表里 @@hash_tab[filename]=position puts("[SUCCESS]现在,文件指针在#{allnum}处") puts(">>请输入你要写的内容") writenum=gets().chomp().length() #模拟,只记录长度 if writenum+@@hash_tab[filename]>99: #假定每个文件只能写99字节 puts("[ERROR]余下空间不允许你从#{position}位置写入这么多的内容") ok=i #把i传到外面 break #这里仅仅是跳出for end #更新写好后文件指针的位置 @@hash_tab[filename]=writenum+@@hash_tab[filename] if @@hash_tab[filename]>allnum: #写完超过原来的长度 #应该会和前面出现一样的bug!只能重新打开文件 file.close() file=File.open("./MyFileSys","r+") file.seek(@bais+23*i,IO::SEEK_SET) #指针到达该行行首 #更新UFD用户文件目录里的长度 file.syswrite(line[0..19]+@@hash_tab[filename].to_s()) puts("[SUCCESS]现在,文件指针在文件尾(#{@@hash_tab[filename]})") else puts("[SUCCESS]现在,文件指针在#{@@hash_tab[filename]}处") end ok=i #把i传到外面 break #这里仅仅是跳出for end #end if end #end for if -1==ok: puts("[ERROR]不存在的文件") end file.close() end end #end class #建立用户对象 usr=USR.new() #登录验证 find=false until true==find do #循环直到读入正确的姓名 print(">>请输入用户名: ") name=gets().chomp() #读进来的名字要去掉换行符 file=File.open("./MyFileSys","r") file.each do |line| #为了防止pika能登录pikachu这种bug,要在名字后接个空格 #为了防止kachu能登录pikachu这种bug,要在名字前匹配行首 if /^#{name} /.match(line): #正则匹配 puts line[10,4] #截取后面的目录区指针,字符串转换成整数再set usr.setPoint(line[10,4].to_i()) usr.setName(name) find=true break end end if false==find: puts("[ERROR]不存在叫这个名字的用户") end file.close() end #登录后展示一下 usr.showDic() #接收命令,作出响应 while true do print(">>请输入命令的名称: ") cmd=gets().chomp() #读进来的命令要去掉换行符 case cmd when "show" usr.showDic() when "bye" usr.showDic() puts("再见!") break when "create" if -1==(num=usr.findNew()): puts("[ERROR]你已经用完10个文件了") else usr.createJudge(num) end when "delete" usr.delFile() when "open" usr.openFile() when "close" usr.closeFile() when "read" usr.readFile() when "write" usr.writeFile() else puts("[ERROR]命令的名称不正确!") puts("必须是以下中的一个: create,delete,open(close,read,write),bye") end end
运行测试1
这个测试的是功能和逻辑限制。[lzh@hostlzh Ruby]$ ruby sy4.rb >>请输入用户名: pikachu 0051 --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 Pika1 rwx 11 Pika2 rwx 22 Pika3 --x 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... >>请输入命令的名称: read >>请输入你要读的文件名: Pika3 [ERROR]这个文件还没打开,不能读 >>请输入命令的名称: open >>请输入你要打开的文件名: Pika3 [SUCCESS]Pika3成功打开了 >>请输入命令的名称: read >>请输入你要读的文件名: Pika3 [ERROR]你没有读取它的权限 >>请输入命令的名称: open >>请输入你要打开的文件名: Pika2 [SUCCESS]Pika2成功打开了 >>请输入命令的名称: read >>请输入你要读的文件名: Pika2 >>请输入你要读的字节数 50 [SUCCESS]现在,已经读到文件尾(22) >>请输入命令的名称: delete >>请输入要删除的文件的名称: Pika2 Pika2 rwx 22 [SUCCESS]删除成功 >>请输入命令的名称: show --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 Pika1 rwx 11 ...................... Pika3 --x 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... >>请输入命令的名称: create >>请输入文件的名称: LiuSB >>请输入新文件的保护码: 101 将被解析为r-x [SUCCESS]创建文件成功 >>请输入命令的名称: show --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 Pika1 rwx 11 LiuSB r-x 00 Pika3 --x 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... >>请输入命令的名称: write >>请输入你要写的文件名: Pika3 [ERROR]你没有写入它的权限 >>请输入命令的名称: write >>请输入你要写的文件名: Pika1 [ERROR]这个文件还没打开,不能写 >>请输入命令的名称: open >>请输入你要打开的文件名: Pika1 [SUCCESS]Pika1成功打开了 >>请输入命令的名称: write >>请输入你要写的文件名: Pika1 >>请输入你要从哪个位置开始写 7 [SUCCESS]现在,文件指针在11处 >>请输入你要写的内容 wo shi da sha bi [SUCCESS]现在,文件指针在文件尾(23) >>请输入命令的名称: show --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 Pika1 rwx 23 LiuSB r-x 00 Pika3 --x 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... >>请输入命令的名称: bye --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 Pika1 rwx 23 LiuSB r-x 00 Pika3 --x 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... 再见! [lzh@hostlzh Ruby]$
运行测试2
这个测试的是对输入的鲁棒性。[lzh@hostlzh Ruby]$ ruby sy4.rb >>请输入用户名: dsaksafwk [ERROR]不存在叫这个名字的用户 >>请输入用户名: [ERROR]不存在叫这个名字的用户 >>请输入用户名: zhihao [ERROR]不存在叫这个名字的用户 >>请输入用户名: liuzhi [ERROR]不存在叫这个名字的用户 >>请输入用户名: liuzhihao 0011 --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 Liu1 rwx 11 Liu2 r-x 20 Liu3 r-- 17 WoShiSB r-x 00 ...................... ...................... ...................... ...................... ...................... ...................... >>请输入命令的名称: sb [ERROR]命令的名称不正确! 必须是以下中的一个: create,delete,open(close,read,write),bye >>请输入命令的名称: create >>请输入文件的名称: Liu1 [ERROR]存在文件重名 >>请输入文件的名称: Liu File [ERROR]有空白字符 >>请输入文件的名称: 666666666666666666666666 [ERROR]太长了 >>请输入文件的名称: [ERROR]未输入 >>请输入文件的名称: niubi >>请输入新文件的保护码: -10 [ERROR]不合法的保护码 >>请输入新文件的保护码: 1000 [ERROR]不合法的保护码 >>请输入新文件的保护码: dsa [ERROR]不合法的保护码 >>请输入新文件的保护码: 5 将被解析为r-x [SUCCESS]创建文件成功 >>请输入命令的名称: show --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 Liu1 rwx 11 Liu2 r-x 20 Liu3 r-- 17 WoShiSB r-x 00 niubi r-x 00 ...................... ...................... ...................... ...................... ...................... >>请输入命令的名称: delete >>请输入要删除的文件的名称: WoShi [ERROR]不存在的文件 >>请输入命令的名称: delete >>请输入要删除的文件的名称: WoShiSB WoShiSB r-x 00 [SUCCESS]删除成功 >>请输入命令的名称: delete >>请输入要删除的文件的名称: Liu1 Liu1 rwx 11 [SUCCESS]删除成功 >>请输入命令的名称: show --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 ...................... Liu2 r-x 20 Liu3 r-- 17 ...................... niubi r-x 00 ...................... ...................... ...................... ...................... ...................... >>请输入命令的名称: open >>请输入你要打开的文件名: Liu1 [ERROR]不存在的文件 >>请输入命令的名称: open >>请输入你要打开的文件名: niubi [SUCCESS]niubi成功打开了 >>请输入命令的名称: read >>请输入你要读的文件名: niubi >>请输入你要读的字节数 999999999999999999 [SUCCESS]现在,已经读到文件尾(0) >>请输入命令的名称: open >>请输入你要打开的文件名: Liu2 [SUCCESS]Liu2成功打开了 >>请输入命令的名称: read >>请输入你要读的文件名: Liu2 >>请输入你要读的字节数 0 [SUCCESS]现在,文件指针在0处 >>请输入命令的名称: read >>请输入你要读的文件名: Liu2 >>请输入你要读的字节数 17 [SUCCESS]现在,文件指针在17处 >>请输入命令的名称: bye --下面是你的UFD(用户文件目录)-- 文件名 保护码 文件长度 ...................... Liu2 r-x 20 Liu3 r-- 17 ...................... niubi r-x 00 ...................... ...................... ...................... ...................... ...................... 再见! [lzh@hostlzh Ruby]$
文件系统格式
即MyFileSys文件的格式,前面短的是MFD主文件目录,后面每行23个字符(算上换行)的是UFD用户文件目录。
liuzhihao 0011 tom 0021 jerry 0031 john 0041 pikachu 0051 eclipse 0061 lzh 0071 kati 0081 apache 0091 yast 0101 Liu1 rwx 11 Liu2 r-x 20 Liu3 r-- 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... Tom1 rwx 18 Tom2 r-x 10 Tom3 r-- 27 ...................... ...................... ...................... ...................... ...................... ...................... ...................... Jry1 r-x 13 Jry2 rwx 10 Jry3 r-- 14 ...................... ...................... ...................... ...................... ...................... ...................... ...................... John1 rwx 11 John2 r-x 20 John3 r-- 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... Pika1 rwx 11 Pika2 rwx 22 Pika3 --x 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... Ecl1 r-x 11 Ecl2 r-x 20 Ecl3 r-- 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... Lzh1 rwx 11 Lzh2 r-x 20 Lzh3 -w- 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... Kati1 rwx 11 Kati2 r-x 20 Kati3 r-- 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... Apache1 rwx 11 Apache2 r-x 20 Apache3 r-- 17 ...................... ...................... ...................... ...................... ...................... ...................... ...................... Yast1 rwx 11 Yast2 r-x 20 Yast3 r-- 17 ...................... ...................... ...................... ...................... ...................... ...................... ......................
相关文章推荐
- Python学习笔记11:标准库之文件管理(os包,shutil包)
- Ubuntu操作系统学习笔记之-----文件基本操作管理
- python学习笔记25(文件管理 os包)
- linux系统管理操作指令学习笔记(二)管理好文件
- python学习笔记25(文件管理 os包)
- Java学习笔记——File类之文件管理和读写操作、下载图片
- 【学习笔记】Linux基本操作(3)--- Linux文件基本操作管理
- Java学习笔记——File类文件管理及IO读写、复制操作
- Python学习笔记11:标准库之文件管理(os包,shutil包)
- Java学习笔记——File类之文件管理和读写操作、下载图片
- Linux学习笔记之--常用文件操作及目录管理命令
- linux系统管理操作指令学习笔记(三)管理好文件
- Java学习笔记——File类文件管理及IO读写、复制操作
- Python学习笔记(15)- os\os.path 操作文件
- linux & C++Primer 学习笔记--fstream 非常好用的文件操作流
- Linux程序设计-学习笔记-第三章文件操作
- GNU/Linux应用程序开发学习笔记(一) 文件操作
- 【学习笔记】Linux平台的文件,目录及操作
- Shell脚本学习笔记(十)--文件操作
- Linux基础知识学习笔记(一)--文件系统的权限管理