双向链表与DFS的Unix文件储存程序

news2025/1/11 9:54:56

title: 双向链表与DFS的Unix文件储存程序 date: 2021-11-28 12:39:26 tags:

  • [链表]
  • [DFS] categories:
  • [码农日常]

写在前面

这是一篇关于python编写的小型文件储存程序,旨在于模拟Unix下lscd等的命令,在整一个中文互联网世界中,很难找到这样的实现方式,但是从数据结构和算法实现的角度来说存在许多价值。

题目

开篇一个题,不得不佩服英文的作业阅读,能够很细节引导学生去实现某一样计算机程序,有一个循序渐进的过程,能够相当于指引一样,并且十分易懂。 onDJDe.md.png

This exercise is about object oriented programming in Python. Your task is to use objects to implement a representation of a simple file system. In computer science, a file system is a data structure that the Operating System uses to control how data is stored and retrieved from a hard (or solid state) drive. A file system could be represented as a tree, in which files and directories may be organised as a hierarchy, so that, directories may contain subdirectories. For example, a file gatos.jpg may be under Isaac directory, but that is a subdirectory of the home folder. In file systems, a directory is just a file, but it is a special kind of file that contains a list of files. Here is an example:

Figure 1: An example of a file system as a tree. Directories are represented in circles, plain files in squared boxes


You can test your code with the test in test-fs.py .
1.Implement the following classes to represent a simple file system:
File: everything is a file
PlainFile: a plain file has a name (we are ignoring its contents)
Directory: has a name and a list of files
with constructors (i.e.     init     methods), so that, we can define the following directory tree (i.e. file system) based on the image above:

>> root = Directory("root",
[PlainFile("boot.exe"), Directory("home",[
Directory("thor", [PlainFile("hunde.jpg"), PlainFile("quatsch.txt")]),
Directory("isaac",   [PlainFile("gatos.jpg")])])])

2.Add methods that print (recursively) the entire file system tree (i.e. define appropriate str methods). You don’t need to produce a pretty output
- it is ok if it looks like this:

Directory(root,[PlainFile(boot.exe),Directory(home, [Directory(thor,[PlainFile(hunde.jpg),PlainFile( quatsch.txt)],Directory(isaac,[PlainFile(gatos.jpg)]]]

3.A File may have other attributes such as owner. If not indicated, the owner will be set to “default”. Implement a method chown(new_owner) that will allow you to modify the owner of a file or directory.

>> file = PlainFile("boot.exe")
>> folder = Directory("Downloads",[])
>> print(f'file.owner: {file.owner}; folder: {folder.owner}') file.owner: default; folder: default
>> file.chown("root")
>> folder.chown("isaac")
>> print(f'file.owner: {file.owner}; folder: {folder.owner}') file.owner: root; folder: isaac

4.Implement a method ls() that recursively prints the content of the direc- tory and all the subdirectories, using indentation to represent how deep in the tree structure the file/directory is.

# if we run ls() on the previous object root:
>> root.ls() root
boot.exe home
thor
hunde.jpg quatsch.txt
isaac
gatos.jpg    
5.Implement a new class, FileSystem , which will allow us to navigate and manipulate a file system as if it was a UNIX file system. In particular, this class will allow us to keep track of the working directory. It should be initialised as follows:

>> fs = FileSystem(root)
(a)Implement a method pwd() that tells you the current working direc- tory. This might be useful later when moving across directories. It should work like this:
>> fs.pwd() 'root'
(b)Implement ls() for the FileSystem class, so that, fs.ls() would work as question 4, but only printing from the current directory.
(c)Implement a method cd() that will allow you to move to a different directory (changing the working directory). It should work as follows:
# if you try to move to a non existing directory or to a file, # the method should complain:
>> fs.cd("casa")
The directory does not exist!
# But you can move to an existing directory in the working directory.
>> fs.cd("home")
# if we now do ls(), you should only see the content in home:
>> fs.ls() home
thor
hunde.jpg quatsch.txt
isaac
gatos.jpg
Note that our filesystem is case sensitive, if the user searches for “Home”, the method won’t find the folder, because “home” is a dif- ferent folder.    
(d)Implement methods to create files create_file(name) and directo- ries mkdir(name) within the working directory. Both methods should make sure that the file or directory to be created doesn’t already ex- ist within the working directory. Directories must be empty when creating them with mkdir(name). The method mkdir may allow you to indicate the owner when creating it, but files will share the owner of the working directory.
(e)Modify the method cd() to allow us to go back to a parent directory. We will indicate the parent directory as “..”. For example:
>> fs.cd("home")
>> fs.pwd() 'home'
>> fs.cd("..")
>> fs.pwd() 'root'
Note that applying fs.cd("..") in a root node with no parent di- rectory will have no effect, but won’t return an error. 
(f)Implement a method rm(name) that will allow you to remove a file from the current working directory. A directory can only be deleted if it is empty.
>> fs.rm("home")
Sorry, the directory is not empty    
(g)Implement a method find(name) which tries to find a file name in a file system and returns the path to the first occurrence of the file if it finds it but False otherwise. For example:
>> fs.find("gatos.jpg") 'root/home/isaac/gatos.jpg'
>> fs.find("thor") 'root/home/thor'
>> fs.find("unix") False
Note that if you moved deeper in the directory tree using cd(), find(name) should only look from the current working directory.
(h)The UNIX file system has many other operations that you could  implement here. Here are some ideas, but feel free to implement any functionality you find useful. Discuss ideas with us, but please add enough comments to understand what you are aiming to achieve.
•chown -R: we have implemented chown() to change the owner of a single file or directory. Add an efficient way to apply this function recursively to all files and sub directories of a folder.
•Files and directories usually have permissions (read, write, and execution). Can you add that and functions to manipulate the permissions? (e.g. chmod).
•Improve the ls() to show the owner, permissions (similar to what ls -l would do in UNIX.
•In UNIX we can also move files from one directory to another using the command mv, indicating the destination PATH.

通过方法

想通过测试,需要走下面的代码并且全部pass才能完成通过程序

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""

"""
from file_system import Directory, PlainFile, FileSystem
print("Testing question 1")
# question 1 should allow to create simple files and folders:
file = PlainFile("boot.exe")
folder = Directory("Downloads",[])

root = Directory("root",[PlainFile("boot.exe"),
               Directory("home",[
                   Directory("thor",
                      [PlainFile("hunde.jpg"),
                       PlainFile("quatsch.txt")]),
                   Directory("isaac",
                      [PlainFile("gatos.jpg")])])])

print("Testing question 2")
# question 2: implement the str
print(root)
"""
Directory(root,[PlainFile(boot.exe),Directory(home,[Directory(thor,[PlainFile(hunde.jpg),PlainFile(quatsch.txt)],Directory(isaac,[PlainFile(gatos.jpg)]]]
"""
print("Testing question 3")
# question 3: test chown()
file = PlainFile("boot.exe")
folder = Directory("Downloads",[])
print(f'file.owner: {file.owner}; folder: {folder.owner}')
file.chown("root")
folder.chown("isaac")
print(f'file.owner: {file.owner}; folder: {folder.owner}')
print("Testing question 4")
#question 4: ls() doesn't return anything but prints.
root.ls() 
"""
root
    boot.exe
    home
        thor
            hunde.jpg
            quatsch.txt
        isaac
            gatos.jpg
"""
# question 5: create FileSystem
print("Testing question 5a: basic filesystem and pwd")
fs = FileSystem(root)
# 5a:      
print(fs.pwd())
print("Testing question 5b: ls in working directory")
# 5b: 
fs.ls()
# 5c:  
print("Testing question 5c: cd")
# if you try to move to a non existing directory or to a file, 
# the method should complain:
fs.cd("casa")
# But you can move to an existing directory in the working directory.
fs.cd("home")
# if we now do ls(), you should only see the content in home:
fs.ls()
# you can't go backwards yet...
print("Testing question 5d:  mkdir and create file")
fs = FileSystem(root) # re-initialise fs
fs.mkdir("test") # the owner of the directory should be 'default' as not indicated.  fs.mkdir("test","isaac") would set the owner to isaac
fs.cd("test")
fs.create_file("test.txt")
fs.ls()
print("Testing question 5e:  dot dot"
# to test this properly, let's create the entire file system using our previous functions!
root = Directory("root",[],owner="root")
fs = FileSystem(root)
fs.create_file("boot.exe")  # when creating a file we do not need to indicate owner, it will be the same as the working directory
fs.mkdir("test")
fs.mkdir("home",owner="root")
fs.cd("home")
fs.mkdir("thor",owner="thor")
fs.mkdir("isaac",owner="isaac")
fs.cd("thor")
fs.create_file("hunde.jpg")
fs.create_file("quatsch.txt")
fs.cd("..")
fs.cd("isaac")
fs.create_file("gatos.jpg")
fs.cd("..")
fs.cd("..")
fs.ls()
print("Testing question 5f:  rm")

fs.rm("test") # shouldn't work!
fs.cd("test")
fs.rm("test.txt")
fs.cd("..")
fs.rm("test")
fs.ls()

print("Testing question 5e:  find")

print(fs.find("gatos.jpg"))
fs.cd("home")
print(fs.find("boot.exe")) # shouldn't find it!

程序编写

初始化PlainFile和Directory类

初始化两个类利用了基础的__init__方法进行

class File(object):
    """
    Everything is a file
    """
    def __init__(self, name, owner) -> None:
        super().__init__()
        self.name = name
        self.owner = "default"

class PlainFile(File):
    """
    A plain file has a name ignoring its contents
    """
    def __init__(self, name, owner="default") -> None:
        super().__init__(name, owner)
        pass

    def chown(self, new_owner) -> None:
        """
        Allow to modify the owner of a file or directory.
        """
        self.owner = new_owner
class Directory(object):
    """
    Includes a name and a list of files, recursively store the folder
    """
    def __init__(self, root, args, owner="default") -> None:
        super().__init__()
        self.root = root
        self.sub = args
        self.owner = owner

显然这些初始化的过程并不困难,而是在后面的一些查找、遍历、递归当中。

列出文件

 def _ls(self, subs, level) -> None:
        """
        :params subs, the root Directory.
        :return None, print (recursively) the entire file system tree.
        """
        iter_text = "".join(["    " for _ in range(level)])
        _type = type(subs)
        if _type == Directory:
            print("{}{}".format(iter_text, subs.root))
            level += 1
            self._ls(subs.sub, level)
        elif _type == PlainFile:
            print("{}{}".format(iter_text, subs.name))
        elif _type == list:
            for i in subs:
                self._ls(i, level)

        # for sub in subs:
        #     if type(sub) == list:
        #         self.getrecursive_tree(sub)

文件列出需要定义level层数,表示递归的层级,并且根据不同数据类型的字典子集,输出不同的数据结果。

文件查找

在文件查找当中,使用到DFS深度优先搜索的方式进行,以递归的方式进行实现。

def _find(self, name, workspace):
        """
        Using DFS to find the File or Directory
        If found ,return path otherwise return False
        """
        subs = workspace.sub

        namelist = []
        for file in subs:
            if type(file) == PlainFile:
                namelist.append(file.name)
            elif type(file) == Directory:
                namelist.append(file.root)

        for file in subs:
            if name in namelist:
                return workspace.root + "/" + name
            else:
                if type(file) == Directory:
                    if self._find(name, file):
                        return workspace.root + "/" + self._find(name, file)

FileSystem文件系统类

整片代码的精华就在于此文件系统类,一开始是根据指引进行编写,根据引导来构成代码程序,后面逐渐弄清楚的文件系统与其内部成员之间的关系,相当于一个双向链表(也类似于一个树形结构)

def __init__(self, workspace:Directory, parentstate = None) -> None:
        super().__init__()
        self._pwd = workspace.root
        self._workspace = workspace
        self._parentstate = parentstate
        #Use parents state to store "father" status

可见,其内部数据结构由三个成员组成:_pwd当前目录名称,_wordspace当前工作目录,_parentstate父目录,其中当前工作目录的数据类型为字典,用于储存当前环境下的工作路径,而_parentstate数据类型为FileSystem,那么文件系统直接的目录,怎么控制cd进入下级目录和进入上层目录呢?

由于是第一次在类内写链表,也折腾了很久,而且这个并不像是一般类型的链表,比如说Directory下的数组就不一定都是一个数据类型,其内部还有PlainFile的数据类型。

cd用于控制当前目录的代码为

def cd(self, filename) -> None:
        """
        Change the workspace.
        """
        if filename == ".." and self._parentstate:
            self._workspace = self._parentstate._workspace
            self._pwd = self._parentstate._pwd
            self._parentstate = self._parentstate._parentstate
        else:
            subs = self._workspace.sub
            namelist = []
            for i in subs:
                if type(i) == PlainFile:
                    namelist.append(None)
                elif type(i) == Directory:
                    namelist.append(i.root)

            if filename in namelist:
                for index, name in enumerate(namelist):
                    if filename == name:
                        # self._parentstate = FileSystem()
                        new_filesys = FileSystem(self._workspace, self._parentstate)
                        self._parentstate = new_filesys
                        self._workspace = self._workspace.sub[index]
                        self._pwd = self._workspace.root
            else:
                print("The directory does not exist!")

cd ..则代表进入上层目录,而cd加文件夹则代表进入下级目录,那么最关键的问题在于:

进入下级目录之后在目录当中新建文件,再返回上级目录,上级目录是否会包含下级目录的信息呢?还是单单一个新建的对象(地址不同)直接没有联系。

因此需要处理好状态控制,处理好对象与对象之间互相的联系

仔细阅读代码,在查找到下级目录的时候,先新建一个FileSystem对象,此对象的_parentstate就是当前目录下的父目录,然后再更新_parentstate为当前的父目录。

因为FileSystem_workspace当中,其指针地址一致,因此不会出现刚刚那样的问题,而如果要作出简短的总结,则是

FileSystem是用于控制状态的类, 里面含有指向固定地址的指针。

onc30U.md.png

其他示例

#模拟案例
class Content(object):
    def __init__(self, data) -> None:
        super().__init__()
        self.data = data


class Link(object):
    def __init__(self,data , pre = None, next = None) -> None:
        super().__init__()
        self.pre = pre
        self.next = next
        self.data = data

    def ls(self):
        self.data = self.pre.data
        self.pre = self.pre.pre


    def cd(self):
        new = Link(self.data, self.pre)
        self.pre = new
        self.data = self.data.data[2]




link = Link(Content([1,2, Content([3, 4])]))
print(link.data.data)
link.cd()
link.data.data.append(8)
link.ls()
print(link.data.data[2].data)

写在后面

虽然这只是使用python语言实现的一个很简单的文件系统,但是里面包含了如DFS双向链表以及含有使用__str__重写函数的点,

参考

  1. 《回溯算法实现在特定路径下查找文件》

    https://blog.csdn.net/leviopku/article/details/121499215

  2. 《Python-深入理解递归函数中的return返回值》

​ https://blog.csdn.net/weixin_40476348/article/details/98602498#:~:text=python%20

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/76566.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为云服务-运维篇-应用健康状况追踪-性能监测

文章目录前言性能监测意义应用性能监控Java 应用探针步骤一、登录虚拟机步骤二 、Java应用启动添加配置项步骤三、 APM步骤四、应用性能管理 APM步骤五、查看监控的应用性能管理相关的指标总结前言 之前的文章我们已经介绍过了华为云平台下 微服务日常如何运维。 这次我们介绍…

【响应式四端自适应】红色系网络公司网站 v2.6.1.3

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 四网合一企业网站管理系统支持在线升级(支持跨版本)、插件在线安装、系统内置严格的过滤体系、可以有效应对安全检测报告。 四网合一: 电脑网站、手机…

APIcat更新阿里云日志分析和自动拦截功能

基于OpenAPI定义进行增强HTTP日志分析的开源工具APIcat(项目主页)本周更新了阿里云相关功能,构建了从日志分析到实时拦截规则创建的整体流程。 APIcat通过阿里云Logstore功能读取日志,并通过SLB拦截规则创建接口实现拦截规则的自…

Qt学习之路之QMovie动画

QMovie类是一个很方便的类,用于播放动画。在刷新页面的时候,可以尝试用QMovie 来实现等待界面。 QMovie类用于显示简单的动画,没有声音。 首先,通过将一个文件的名称或者一个指针传递给QMovie的构造函数构建一个QMovie对象。传递…

[附源码]计算机毕业设计的黄河文化科普网站Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

@Transactional 事务获取数据源的源码解析

spring在开启事务的时候是去拿数据源的,今天我们详细分析一下,Transactional 事务获取数据源的源码解析: 1、从业务代码声明式事务开始: 接口调用到这里,原理是生成了动态代理类,默认是通过cglib实现的类…

《Linux运维实战:MongoDB数据库逻辑备份恢复(方案三)》

一、备份与恢复方案 Percona Backup for MongoDB 是一个开源、分布式和低影响的解决方案,用于MongoDB分片集群和副本集的一致备份,不支持单实例mongodb服务。从版本1.7.0开始,Percona Backup for MongoDB支持物理和逻辑备份和恢复&#xff0…

计算机网络—各层协议极其作用

文章目录应用层传输层网络层链路层物理层————————————————————————————————应用层 (1)应用层:直接为用户的应用进程提供服务。第三方自定义协议(HTTP协议,支持电子邮件发送的SMTP协议…

Metal每日分享,LUT查找滤镜效果

本案例的目的是理解如何用Metal实现LUT颜色查找表滤镜,通过将颜色值存储在一张表中,在需要的时候通过索引在这张表上找到对应的颜色值,将原有色值替换成查找表中的色值; 总结就是一种针对色彩空间的管理和转换技术,LUT 就是一个 …

【MySQL】深入理解隔离性

文章目录多版本并发控制(MVCC)如何解决读-写并发undo 日志模拟MVCC过程select读取版本隔离性的实现为什么要有隔离级别快照(read view)可重复读(RR)与读提交(RC)的本质区别多版本并发控制(MVCC) 多版本并发控制(MVCC)是一种用来解决读写冲突的无锁并发控…

[附源码]计算机毕业设计教务管理系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java银行管理系统275d1

要开始我们毕业设计的第一步的关键就是选好我们的课题,有的同学开始选题的时候想着按照传统的课题延续下去,在设计题目时,不要过于笼统广泛,选择题目其实并不难,要多从自身的角度出发,要结合你们当前所处的…

Briefings in Bioinformatics2021 | DLGN+:基于GAN和强化学习的分子从头双目标性质生成

论文标题:De novo generation of dual-target ligands using adversarial training and reinforcement learning 论文地址:https://academic.oup.com/bib/article/22/6/bbab333/6354720 代码:https://github.com/lllfq/DLGN 一、模型结构 …

数学基础从高一开始3、集合的基本运算

目录 复习内容: 并集的概念 你能用符号语言和图形语言表示并集这个集合吗? 例1:求并集 例2:求并集 符号解析: 例3: 交集的概念 例4: 例5: 例6: 思考题: 作业&#xff…

20221209在Ubuntu22.04下读取苹果分区APFS的步骤

20221209在Ubuntu22.04下读取苹果分区APFS的步骤 缘起:公司的新来的美工要清理MAC电脑。 由于忘记管理员密码?于是备份文件,重装系统! 于是通过固态硬盘盒子将2TB的M2接口的固态硬盘SSD格式化为APFS,这样MAC电脑就可…

2022下半年软考成绩即将公布,预约查分提醒,查分快人一步

距离2022下半年考试已经过去一个多月了,大家都在焦急的等待软考成绩查询。根据往年情况来看,软考成绩查询时间并不是固定的一个时间点,不过可以大致预测下应该是在12月中/下旬左右开放成绩查询,具体情况以官方公告为准。 历年软考…

玩以太坊链上项目的必备技能(类型-引用类型-Solidity之旅三)

在前文我们讲述了值类型,也就说再修改值类型的时候,每次都有一个独立的副本,如:string 类型的状态变量,其值是无法修改,而是拷贝出一份该状态的变量,将新值存起来。对于处理稍微复杂地值类型时&…

2022最新性能测试面试题(带答案)

一、性能测试开展过程: 答:第一步:找产品沟通哪些接口需要压测,需要达到什么样的预期值(TPS和响应时间) 第二步:编写测试计划,人员、时间周期、工具 第三步:环境搭建 第四步:造数…

计算机操作系统

并行和并发的区别与联系? 【并发】 多个任务交替执行 计算机在运行过程中,有很多指令会涉及 I/O 操作,而 I/O 操作又是相当耗时的,速度远远低于 CPU,这导致 CPU 经常处于空闲状态,只能等待 I/O 操作完成后…

springboot项目如何启用arthas

Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?我改的代码为什么没有执行到&#xff…