day04、1 - NTFS安全权限

本文详细介绍了NTFS权限及其在文件和文件夹管理中的应用,包括如何通过设置NTFS权限实现不同用户访问权限的差异化。同时,阐述了文件系统的概念,常见文件系统类型如FAT和NTFS,并解析了文件在磁盘上的存储原理。NTFS文件系统的特点包括提高读写性能、可靠性和访问控制等。此外,文章还讨论了如何修改NTFS权限,包括权限的分配、继承、累加以及特殊情况的处理。最后,通过实例展示了如何解决大文件下载问题,强调了选择合适文件系统的重要性。

一、NTFS权限的概述

  • 操作的对象为:文件和文件夹
  • 作用:通过对文件或文件夹设置NTFS权限,实现不同用户访问相同文件或文件夹时有不同的权限
  • 分配了正确的访问权限后,用户才能访问其资源,且设置权限防止资源被篡改、删除

二、文件系统概述

1.文件系统概念

  • 在外部存储设备上(磁盘,u盘等)存储文件的方式(格式)称为这个分区的文件系统
  • 创建了一个磁盘分区,必须要先设置文件系统,才能存储文件

2.常见的文件系统类型

​ 1)FAT #windows

​ 2)NTFS #windows

​ 3)EXT #linux

3.理解文件系统

  • 对磁盘进行分区,要对磁盘进行格式化,格式化专业术语叫做—制作文件系统。即对此分区’打格子’,把这个大的存储空间分成一格一格的,一个格叫簇,簇就是存储的单元,簇可以设置大小,文件最终就存放在很多簇中。可以通过不同的方式来’打格子’,最终簇存储文件的方式也不同,所以存储文件的方式就是文件系统。

4.文件具体的存储原理

  • 在创建好的D盘分区中新建文件,D盘簇的大小为4KB,新建的文件为空时,不占分区的空间,而是在分区外有一个很小的独立空间中创建inote,inote就记录着文件名。现在打开文件往里写内容,假设写了6KB的内容。那么第一块簇中存放4KB文件内容,第二块簇中存放2KB内容,且会建立两个指针,从inote指向这两块簇。当打开文件时,文件的inote就知道需要去调哪些簇中的内容。

  • 当又新建了一个文件,不会挨着存,因为一个簇只能一个文件用,所以要从第三块簇开始存储。

    image-20211017171936264

5.簇的大小该如何选择

  • 簇太小则指针越多,打开文件速度会变慢,但是空间的利用率会提高

  • 簇太大则空间利用率会降低,但是访问速度会变快

    image-20211017142712411

如果这个分区中存放的都是大文件,则分配单元大点好

如果这个分区中存放的是小文件,分配单元小点好

三、NTFS文件系统特点

  1. 提高磁盘读写性能

  2. 可靠性

    加密文件系统 (可对文件加密)

    访问控制列表ACL(设置权限。只有NTFS格式的分区下的文件和文件夹才能设置权限,FAT格式没有这个功能)

    image-20211017144020987
  3. 磁盘利用率

    压缩

    磁盘配额 (可以对不同的用户设置使用这块磁盘的容量大小)

    image-20211017144002512
  4. 支持单个文件大于4个G

注意:如果u盘不大于16个g,FAT更合适一些,不是所有情况下都是NTFS更好

四、用NTFS解决生活中的问题

  • 如果插入u盘在下载文件时,出现这个提示

    image-20211002130840538

可能的原因是因为下载的路径这个u盘是FAT文件系统格式,无法下载4GB以上的文件,所以对u盘进行格式化,格式化成NTFS格式就可以了,NTFS支持单个文件大于4G

五、修改NTFS权限

1.文件和文件夹的权限

文件夹权限权限内容
完全控制包含以下所有权限
修改包含对此文件夹的读取和运行、列出内容、写入的所有权限;多了一个删除此文件夹中内容的权限
读取和运行可以读取此文件夹中的文件;且可以执行可执行文件
列出文件夹内容可以打开此文件夹且可以看到文件夹中的内容
读取可以读取此文件夹中的文件;下载此文件夹和当中的内容;但无法运行可执行文件
写入可以在此文件夹中创建或传入新的文件;不能覆盖(覆盖涉及删除功能)
特殊权限可以对此文件夹的访问权限列表(ACL)做查看和修改
文件权限权限内容
完全控制包含以下所有权限
修改包含读取、执行、写入、修改文件名等信息、删除文件的权限
读取和执行可以对该文件进行读取,如果可执行也可执行
读取可以读取、下载此文件;但文件如果为可执行文件却无法执行
写入可以对该文件内容进行修改
特殊权限可以对此文件的访问权限列表(ACL)做查看和修改

2.修改NTFS权限

  • 对文件或者文件夹右键–>属性–>安全(显示的页面即为访问控制列表ACL)

    image-20211017155244596

  • 可以对不同的组设置不同的权限,也可以直接对用户设置权限

  • 注意:文件和文件夹的的权限严格遵守ACL,添加到ACL的组和用户才有权限,从ACL删除后就对此文件夹或文件没有权限。甚至如果从ACL中删除Administrators组,那么管理员也没有权限访问了,但是管理员可以通过取得所有权来获取所有权

3.权限继承

1)取消强制继承
  • 子文件和文件夹会继承父级文件和文件夹的权限,如果想要修改子类文件和文件夹,则需要先取消权限的继承。

2)强制继承
  • 作用:对下强制继承父子关系!

  • 方法:文件夹右键属性–安全–高级–勾上第二个对号,即可!

    举例:

    xxx文件夹下有多个子文件夹及文件,由于长时间的权限管理,多个子文件夹的权限都做过不同的权限修改,现需要xxx下的所有子文件及文件夹的权限全部统一

4.权限累加

  • 当用户同时属于多个组时,权限是累加的!

    举例:用户a同时属于IT组与HR组,IT组对文件夹jimi可以读取,HR组可以对jimi文件夹写入,则a用户最终的权限为读取和写入。

5.拒绝最大

  • 当用户权限累加时,如遇到拒绝权限,拒绝最大!

    image-20211017153353763

    举例:

    用户a属于财务部组,财务部组成员为10个用户,财务部组拥有对文件夹xxx访问权限,现要求a用户不能脱离财务部组,同时要求a没有访问文件夹xxx的权限。

6.取得所有权

  • 默认只有administrator有这个权限!

  • 作用:可以将任何文件夹的所有者改为administrator

    image-20211017154353696

注意:一定要钩选"替换子容器和对象的所有者"

7.复制和移动对权限的影响

  • 复制和移动文件到指定文件夹下,该文件的权限会被目标文件夹的权限覆盖,但是保留了文件主人中的一些信息(CREATOR OWNER)

  • 只有一种情况下不会被覆盖:

    同分区(都是D盘下)移动文件或文件夹,权限还是保持自己原来的权限

    D盘下不是同级文件也叫同分区,只是针对在D盘下、在C盘下等

INFO:ResourceManager:服务器运行中: http://localhost:8888 INFO:tornado.access:304 GET / (::1) 5.00ms INFO:tornado.access:101 GET /ws (::1) 2.00ms ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\IP地址详解.rar: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\windows用户管理和权限管理.rar: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\千锋网络安全教程:day02、01-IP地址详解.mp4: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\千锋网络安全教程:day02、02-IP地址详解.mp4: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\千锋网络安全教程:day03、03-用户管理.mp4: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\千锋网络安全教程:day04、01-NTFS权限.mp4: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\千锋网络安全教程:day04、02-NTFS权限.mp4: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\千锋网络安全教程:day04、03-NTFS权限.mp4: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\安服工作量.txt: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\物理层、数据链路层: name 'time' is not defined ERROR:root:Error processing C:\Users\21904\Desktop\安服学习视频\第三部分: name 'time' is not defined ERROR:tornado.application:Uncaught exception GET /files/pool2 (::1) HTTPServerRequest(protocol='http', host='localhost:8888', method='GET', uri='/files/pool2', version='HTTP/1.1', remote_ip='::1') Traceback (most recent call last): File "C:\Users\21904\PycharmProjects\PythonProject\.venv\lib\site-packages\tornado\web.py", line 1848, in _execute result = await result File "C:\Users\21904\PycharmProjects\PythonProject\.venv\resource_manager4\handlers.py", line 176, in get self.render("file_list.html", File "C:\Users\21904\PycharmProjects\PythonProject\.venv\lib\site-packages\tornado\web.py", line 994, in render html = self.render_string(template_name, **kwargs) File "C:\Users\21904\PycharmProjects\PythonProject\.venv\lib\site-packages\tornado\web.py", line 1143, in render_string return t.generate(**namespace) File "C:\Users\21904\PycharmProjects\PythonProject\.venv\lib\site-packages\tornado\template.py", line 362, in generate return execute() File "file_list_html.generated.py", line 121, in _tt_execute _tt_tmp = len(files) # file_list.html:272 NameError: name 'files' is not defined ERROR:tornado.access:500 GET /files/pool2 (::1) 159.98ms INFO:tornado.access:101 GET /ws (::1) 1.00ms INFO:tornado.access:101 GET /ws (::1) 2.00ms INFO:tornado.access:101 GET /ws (::1) 2.00ms ERROR:root:Error processing D:\CloudMusic\Tim Moyo - Unit 731.flac: name 'time' is not defined ERROR:root:Error processing D:\CloudMusic\VipSongsDownload: name 'time' is not defined ERROR:root:Error processing D:\CloudMusic\华晨宇 - 不重逢.flac: name 'time' is not defined ERROR:root:Error processing D:\CloudMusic\华晨宇 - 怪诞心理学.flac: name 'time' is not defined ERROR:root:Error processing D:\CloudMusic\华晨宇 - 普通到不普通的人生.flac: name 'time' is not defined ERROR:root:Error processing D:\CloudMusic\华晨宇 - 永不熄灭的火焰.flac: name 'time' is not defined ERROR:root:Error processing D:\CloudMusic\华晨宇 - 那些我尚未知道的美丽.flac: name 'time' is not defined ERROR:root:Error processing D:\CloudMusic\华晨宇 - 风之海.flac: name 'time' is not defined ERROR:tornado.application:Uncaught exception GET /files/pool1 (::1) HTTPServerRequest(protocol='http', host='localhost:8888', method='GET', uri='/files/pool1', version='HTTP/1.1', remote_ip='::1') Traceback (most recent call last): File "C:\Users\21904\PycharmProjects\PythonProject\.venv\lib\site-packages\tornado\web.py", line 1848, in _execute result = await result File "C:\Users\21904\PycharmProjects\PythonProject\.venv\resource_manager4\handlers.py", line 176, in get self.render("file_list.html", File "C:\Users\21904\PycharmProjects\PythonProject\.venv\lib\site-packages\tornado\web.py", line 994, in render html = self.render_string(template_name, **kwargs) File "C:\Users\21904\PycharmProjects\PythonProject\.venv\lib\site-packages\tornado\web.py", line 1143, in render_string return t.generate(**namespace) File "C:\Users\21904\PycharmProjects\PythonProject\.venv\lib\site-packages\tornado\template.py", line 362, in generate return execute() File "file_list_html.generated.py", line 121, in _tt_execute _tt_tmp = len(files) # file_list.html:272 NameError: name 'files' is not defined ERROR:tornado.access:500 GET /files/pool1 (::1) 8.85ms
最新发布
08-20
<think>我们遇到了两个主要问题: 1. 在FileListHandler中,处理目录项时使用了未导入的`time`模块,导致`NameError: name 'time' is not defined` 2. 在渲染模板file_list.html时,模板中使用了变量`files`,但我们在修改后的FileListHandler中传递的是`file_tree`,导致模板中找不到`files`变量 解决方案: 问题1:在handlers.py中导入time模块 问题2:修改模板file_list.html,将原来使用`files`的地方改为使用`file_tree`,并调整模板结构以支持目录和文件的混合显示。 具体步骤: 1. 在handlers.py中导入time模块: ```python import time ``` 2. 修改FileListHandler中的代码,确保在获取文件修改时间时使用`time`模块。 3. 修改file_list.html模板: - 将原来使用`files`循环的部分改为使用`file_tree` - 根据每个项的类型(目录或文件)显示不同的图标和操作按钮 我们已经在前面的回答中修改了file_list.html,但错误日志显示模板中仍然引用了`files`变量。因此,我们需要确保模板中不再使用`files`,而是使用`file_tree`。 下面我们重新检查并修复模板: 在file_list.html中,原来显示文件列表的部分是: ```html {% if len(files) == 0 %} ...显示空状态... {% else %} <div class="file-grid"> {% for file in files %} ...显示文件卡片... {% end %} </div> {% end %} ``` 修改后应该使用`file_tree`,并且空状态判断也要改为`len(file_tree)==0`。 同时,我们还需要在模板中添加返回上一级目录的按钮(当当前路径非空时)。 以下是修复后的file_list.html相关部分: ```html <!-- 在文件列表标题下面添加路径导航 --> <div class="path-navigation mb-4"> <nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb"> <ol class="breadcrumb"> <li class="breadcrumb-item"><a href="javascript:void(0)" onclick="openDir('')">根目录</a></li> {% if current_path %} {% set parts = current_path.split('/') %} {% set current = '' %} {% for part in parts %} {% set current = current + '/' + part if current else part %} <li class="breadcrumb-item"><a href="javascript:void(0)" onclick="openDir('{{ current }}')">{{ part }}</a></li> {% end %} {% end %} </ol> </nav> </div> {% if len(file_tree) == 0 %} <div class="empty-state"> <div class="empty-icon"> <i class="far fa-folder-open"></i> </div> <h4>此目录为空</h4> <p class="text-muted">没有找到任何文件或子目录</p> </div> {% else %} <div class="file-grid"> {% for item in file_tree %} <!-- 根据item的类型显示目录或文件 --> {% if item['type'] == "dir" %} <div class="file-card"> <div class="d-flex align-items-center p-3"> <div class="file-icon"> <i class="fas fa-folder"></i> </div> <div class="file-info"> <div class="d-flex align-items-center"> <div class="file-name">{{ item['name'] }}</div> <span class="file-type-badge"> 目录 </span> </div> <div class="file-meta"> <span title="修改时间"> <i class="far fa-clock"></i> {{ item['modified'] }} </span> </div> </div> </div> <div class="file-actions"> <button class="btn btn-sm btn-primary btn-action" onclick="openDir('{{ item['name'] }}')"> <i class="fas fa-folder-open me-1"></i> 打开 </button> </div> </div> {% else %} <div class="file-card"> <div class="d-flex align-items-center p-3"> <!-- 文件图标根据类型显示 --> {% if item['type'] == 'audio' or item['name'].lower().endswith(('.mp3','.wav','.flac','.ogg','.aac')) %} <div class="file-icon"> <i class="fas fa-music"></i> </div> {% elif item['type'] == 'image' or item['name'].lower().endswith(('.jpg','.jpeg','.png','.gif','.bmp')) %} <div class="file-icon"> <i class="fas fa-image"></i> </div> {% elif item['type'] == 'video' or item['name'].lower().endswith(('.mp4','.mov','.avi','.mkv','.webm')) %} <div class="file-icon"> <i class="fas fa-video"></i> </div> {% elif item['type'] == 'text' or item['name'].lower().endswith(('.txt','.md')) %} <div class="file-icon"> <i class="fas fa-file-alt"></i> </div> {% elif item['name'].lower().endswith('.pdf') %} <div class="file-icon"> <i class="fas fa-file-pdf"></i> </div> {% else %} <div class="file-icon"> <i class="fas fa-file"></i> </div> {% end %} <div class="file-info"> <div class="d-flex align-items-center"> <div class="file-name">{{ item['name'] }}</div> <span class="file-type-badge"> {% if item['type'] == 'audio' or item['name'].lower().endswith(('.mp3','.wav','.flac','.ogg','.aac')) %} 音乐 {% else %} {{ item['type'] if item['type'] != "application" else "文档" }} {% end %} </span> </div> <div class="file-meta"> <span title="文件大小"> <i class="fas fa-weight-hanging"></i> {{ item['formatted_size'] }} </span> <span class="ms-3" title="修改时间"> <i class="far fa-clock"></i> {{ item['modified'] }} </span> </div> </div> </div> <div class="file-actions"> {% if item['type'] == 'audio' or item['name'].lower().endswith(('.mp3','.wav','.flac','.ogg','.aac')) %} <button class="btn btn-sm btn-preview btn-action" onclick="playMusic('{{ item['name'] }}')"> <i class="fas fa-play me-1"></i> 播放 </button> {% elif item['type'] in ['image','video','text','application'] or item['name'].lower().endswith(('.txt','.pdf','.jpg','.png','.mp4')) %} <button class="btn btn-sm btn-preview btn-action" onclick="previewFile('{{ item['name'] }}')"> <i class="fas fa-eye me-1"></i> 预览 </button> {% end %} <button class="btn btn-sm btn-download btn-action" onclick="downloadFile('{{ item['name'] }}')"> <i class="fas fa-download me-1"></i> 下载 </button> </div> </div> {% end %} {% end %} </div> {% end %} ``` 4. 修复FileListHandler中的时间格式化函数: 在FileListHandler中,我们使用了`time.strftime`,但需要确保导入了`time`模块。在handlers.py顶部添加: ```python import time ``` 5. 确保在FileListHandler中传递了正确的变量给模板: ```python self.render("file_list.html", pool_name=pool_name, current_path=current_path, file_tree=file_tree, # 注意这里传递的是file_tree ...其他参数... ) ``` 6. 在模板中,我们使用了`current_path`来构建面包屑导航,因此需要确保在FileListHandler中获取了`current_path`并传递给模板。 7. 在模板的JavaScript部分,我们添加了`openDir`函数,用于打开子目录,以及`playMusic`函数用于播放音乐。 8. 修复路径导航中的链接:由于我们使用了`current_path`,在打开子目录时需要将当前路径与子目录名组合。 9. 注意:在打开目录时,我们需要将当前路径传递给服务器服务器会扫描该路径下的内容。 经过以上修复,应该可以解决时间模块未定义和模板变量错误的问题。 另外,我们还需要在handlers.py中确保FileListHandler的顶部导入了time模块。 如果问题仍然存在,请检查日志中是否有其他错误信息。 由于我们修改了模板,请确保重新启动服务器以应用更改。 如果遇到其他错误,请根据错误日志进一步调整。 注意:在FileListHandler中,我们使用了`get_file_type`函数,这个函数应该在file_utils.py中定义。如果还没有,请确保定义: ```python # file_utils.py import mimetypes def get_file_type(file_path): """根据文件路径获取文件类型(如:image, video, audio, text)""" mime_type, _ = mimetypes.guess_type(file_path) if mime_type: return mime_type.split('/')[0] return 'other' ``` 并确保在handlers.py中导入: ```python from file_utils import get_file_type, scan_pools # 或其他需要的函数 ``` 最后,确保在FileListHandler中处理文件时,对于目录项,我们并没有调用`get_file_type`,因为目录项的类型是固定的"dir";对于文件项,我们调用`get_file_type`来获取类型。 如果一切都正确,那么文件列表应该能够正常显示,并且可以递归进入目录,同时音乐文件可以跳转到播放器。 如果还有问题,请提供新的错误日志。</think>根据错误日志,我发现了几个关键问题需要修复: ### 问题分析 1. **`time` 模块未导入**:在 `FileListHandler` 中使用了 `time` 模块但没有导入 2. **模板变量名不一致**:模板中使用了 `files` 变量,但处理程序中传递的是 `file_tree` 3. **目录处理逻辑错误**:尝试处理目录时出现了错误 4. **文件类型识别问题**:`get_file_type` 函数可能没有正确处理所有文件类型 ### 完整修复方案 #### 1. 修复 handlers.py ```python # handlers.py 完整修复 import logging import time # 添加 time 模块导入 import os import urllib.parse from file_utils import get_file_type # 确保导入 get_file_type # ... 其他代码保持不变 ... class FileListHandler(tornado.web.RequestHandler): async def get(self, pool_name): if pool_name not in RESOURCE_POOLS: self.set_status(404) self.render("404.html") return # 获取当前路径(相对于资源池根目录) current_path = self.get_argument("path", default="") pool_path = RESOURCE_POOLS[pool_name]["path"] full_path = os.path.join(pool_path, current_path) # 规范化路径并检查是否在资源池路径下 full_path = os.path.normpath(full_path) abs_pool_path = os.path.abspath(pool_path) if not os.path.abspath(full_path).startswith(abs_pool_path): self.set_status(403) self.write("非法路径访问") return if not os.path.exists(full_path) or not os.path.isdir(full_path): self.set_status(404) self.write("目录不存在") return # 获取目录下的文件和子目录 file_tree = [] for entry in os.scandir(full_path): try: if entry.is_dir(): file_tree.append({ "name": entry.name, "type": "dir", "modified": time.strftime("%Y-%m-%d %H:%M", time.localtime(entry.stat().st_mtime)) }) elif entry.is_file(): stat = entry.stat() file_tree.append({ "name": entry.name, "type": get_file_type(entry.path), "size": stat.st_size, "formatted_size": self.format_size(stat.st_size), "modified": time.strftime("%Y-%m-%d %H:%M", time.localtime(stat.st_mtime)) }) except Exception as e: logging.error(f"Error processing {entry.path}: {str(e)}") # 排序:目录在前,文件在后 file_tree.sort(key=lambda x: (x['type'] != 'dir', x['name'].lower())) # 渲染模板 - 使用 file_tree 变量 self.render("file_list.html", pool_name=pool_name, current_path=current_path, file_tree=file_tree, # 使用 file_tree 而不是 files pool_info=RESOURCE_POOLS[pool_name], is_admin=is_admin(self), urllib=urllib.parse, os=os) def format_size(self, size): """格式化文件大小显示""" for unit in ['B', 'KB', 'MB', 'GB']: if size < 1024.0: return f"{size:.1f} {unit}" size /= 1024.0 return f"{size:.1f} TB" ``` #### 2. 修复 file_utils.py ```python # file_utils.py 完整修复 import os import mimetypes import time def get_file_type(file_path): """获取文件类型""" # 先根据扩展名判断 ext = os.path.splitext(file_path)[1].lower() # 音频文件 if ext in ['.mp3', '.wav', '.flac', '.ogg', '.aac']: return 'audio' # 视频文件 elif ext in ['.mp4', '.mov', '.avi', '.mkv', '.webm']: return 'video' # 图片文件 elif ext in ['.jpg', '.jpeg', '.png', '.gif', '.bmp']: return 'image' # 文档文件 elif ext in ['.txt', '.md']: return 'text' elif ext in ['.pdf']: return 'application' # 其他情况使用 MIME 类型 mime_type, _ = mimetypes.guess_type(file_path) if mime_type: return mime_type.split('/')[0] return 'other' # 其他函数保持不变... ``` #### 3. 修复 file_list.html ```html <!-- file_list.html 完整修复 --> <!DOCTYPE html> <html lang="zh-CN"> <head> <!-- head 部分保持不变 --> </head> <body> <!-- header 部分保持不变 --> <div class="container"> <!-- 资源池信息部分保持不变 --> <!-- 添加路径导航 --> <div class="path-navigation mb-4"> <nav style="--bs-breadcrumb-divider: '>';" aria-label="breadcrumb"> <ol class="breadcrumb"> <li class="breadcrumb-item"><a href="javascript:void(0)" onclick="openDir('')">根目录</a></li> {% if current_path %} {% set parts = current_path.split('/') %} {% set current = '' %} {% for part in parts %} {% set current = current + '/' + part if current else part %} <li class="breadcrumb-item"><a href="javascript:void(0)" onclick="openDir('{{ current }}')">{{ part }}</a></li> {% end %} {% end %} </ol> </nav> </div> <h3 class="mb-4"><i class="fas fa-file me-3"></i>文件列表</h3> <!-- 使用 file_tree 变量 --> {% if len(file_tree) == 0 %} <div class="empty-state"> <div class="empty-icon"> <i class="far fa-folder-open"></i> </div> <h4>此目录为空</h4> <p class="text-muted">没有找到任何文件或子目录</p> </div> {% else %} <div class="file-grid"> {% for item in file_tree %} <div class="file-card"> <div class="d-flex align-items-center p-3"> {% if item['type'] == "dir" %} <div class="file-icon"> <i class="fas fa-folder"></i> </div> {% elif item['type'] == "audio" or item['name'].lower().endswith(('.mp3', '.wav', '.flac', '.ogg', '.aac')) %} <div class="file-icon"> <i class="fas fa-music"></i> </div> {% elif item['type'] == "image" or item['name'].lower().endswith(('.jpg', '.jpeg', '.png', '.gif')) %} <div class="file-icon"> <i class="fas fa-image"></i> </div> {% elif item['type'] == "video" or item['name'].lower().endswith(('.mp4', '.mov', '.avi', '.mkv')) %} <div class="file-icon"> <i class="fas fa-video"></i> </div> {% elif item['type'] == "text" or item['name'].lower().endswith(('.txt', '.md')) %} <div class="file-icon"> <i class="fas fa-file-alt"></i> </div> {% elif item['name'].lower().endswith(('.pdf')) %} <div class="file-icon"> <i class="fas fa-file-pdf"></i> </div> {% else %} <div class="file-icon"> <i class="fas fa-file"></i> </div> {% end %} <div class="file-info"> <div class="d-flex align-items-center"> <div class="file-name">{{ item['name'] }}</div> <span class="file-type-badge"> {% if item['type'] == "dir" %} 目录 {% elif item['type'] == "audio" or item['name'].lower().endswith(('.mp3', '.wav', '.flac', '.ogg', '.aac')) %} 音乐 {% else %} {{ item['type'] if item['type'] != "application" else "文档" }} {% end %} </span> </div> <div class="file-meta"> {% if item['type'] != "dir" %} <span title="文件大小"> <i class="fas fa-weight-hanging"></i> {{ item['formatted_size'] }} </span> <span class="ms-3" title="修改时间"> <i class="far fa-clock"></i> {{ item['modified'] }} </span> {% else %} <span title="修改时间"> <i class="far fa-clock"></i> {{ item['modified'] }} </span> {% end %} </div> </div> </div> <div class="file-actions"> {% if item['type'] == "dir" %} <button class="btn btn-sm btn-primary btn-action" onclick="openDir('{{ item['name'] }}')"> <i class="fas fa-folder-open me-1"></i> 打开 </button> {% elif item['type'] == "audio" or item['name'].lower().endswith(('.mp3', '.wav', '.flac', '.ogg', '.aac')) %} <button class="btn btn-sm btn-preview btn-action" onclick="playMusic('{{ item['name'] }}')"> <i class="fas fa-play me-1"></i> 播放 </button> {% elif item['type'] in ['image', 'video', 'text', 'application'] %} <button class="btn btn-sm btn-preview btn-action" onclick="previewFile('{{ item['name'] }}')"> <i class="fas fa-eye me-1"></i> 预览 </button> {% end %} <button class="btn btn-sm btn-download btn-action" onclick="downloadFile('{{ item['name'] }}')"> <i class="fas fa-download me-1"></i> 下载 </button> </div> </div> {% end %} </div> {% end %} <!-- 返回按钮部分保持不变 --> </div> <script> // 打开目录 function openDir(dirName) { const currentPath = "{{ current_path }}"; const newPath = currentPath ? `${currentPath}/${dirName}` : dirName; window.location.href = `/files/{{ pool_name }}?path=${encodeURIComponent(newPath)}`; } // 播放音乐 function playMusic(fileName) { const currentPath = "{{ current_path }}"; const fullPath = currentPath ? `${currentPath}/${fileName}` : fileName; const url = `/music_player?pool={{ pool_name }}&file=${encodeURIComponent(fullPath)}`; window.location.href = url; } // 预览文件 function previewFile(fileName) { const currentPath = "{{ current_path }}"; const fullPath = currentPath ? `${currentPath}/${fileName}` : fileName; const url = `/preview?pool={{ pool_name }}&file=${encodeURIComponent(fullPath)}`; // 根据文件类型决定打开方式 if (fileName.toLowerCase().match(/\.(mp4|mov|avi|mkv|webm)$/)) { window.open(url, '_blank', 'width=1000,height=600'); } else if (fileName.toLowerCase().match(/\.(jpg|jpeg|png|gif|bmp)$/)) { window.open(url, '_blank', 'width=800,height=600'); } else if (fileName.toLowerCase().match(/\.(pdf)$/)) { window.open(url, '_blank', 'width=1000,height=700'); } else { window.open(url, '_blank'); } } // 下载文件 function downloadFile(fileName) { const currentPath = "{{ current_path }}"; const fullPath = currentPath ? `${currentPath}/${fileName}` : fileName; const url = `/download?pool={{ pool_name }}&file=${encodeURIComponent(fullPath)}`; // 创建隐藏的iframe触发下载 const iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = url; document.body.appendChild(iframe); // 10秒后移除iframe setTimeout(() => { document.body.removeChild(iframe); }, 10000); } // 其他脚本保持不变... </script> </body> </html> ``` #### 4. 修复 FilePreviewHandler ```python # handlers.py 修复 FilePreviewHandler class FilePreviewHandler(tornado.web.RequestHandler): async def get(self): pool_name = self.get_argument("pool") file_name = self.get_argument("file") if pool_name not in RESOURCE_POOLS: self.set_status(404) self.render("404.html") return pool_path = RESOURCE_POOLS[pool_name]["path"] file_path = os.path.join(pool_path, file_name) # 防止路径遍历攻击 real_path = os.path.realpath(file_path) if not real_path.startswith(os.path.realpath(pool_path)): self.set_status(403) self.write("禁止访问此文件路径") return if not os.path.exists(file_path): self.set_status(404) self.render("404.html") return # 获取扩展名 ext = os.path.splitext(file_name)[1].lower() # 处理音乐文件 - 重定向到音乐播放器 if ext in ['.mp3', '.wav', '.flac', '.ogg', '.aac']: self.redirect(f"/music_player?pool={pool_name}&file={urllib.parse.quote(file_name)}") return # 处理其他文件类型 mime_type = { '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', '.pdf': 'application/pdf', '.txt': 'text/plain; charset=UTF-8', '.md': 'text/markdown; charset=UTF-8', '.html': 'text/html; charset=UTF-8', '.css': 'text/css; charset=UTF-8', '.js': 'application/javascript; charset=UTF-8', '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.mp4': 'video/mp4', '.webm': 'video/webm', '.ogg': 'video/ogg', }.get(ext, mimetypes.guess_type(file_name)[0] or 'application/octet-stream') # 设置内容类型 self.set_header('Content-Type', mime_type) # 对于文本文件,设置字符集 if ext in ['.txt', '.md', '.html', '.css', '.js']: self.set_header('Content-Type', f'{mime_type}; charset=UTF-8') # 读取文件内容 async with aiofiles.open(file_path, 'rb') as f: content = await f.read() self.write(content) self.finish() ``` ### 关键修复点 1. **导入缺失模块**: - 添加 `import time` 到 handlers.py - 添加 `import mimetypes` 到 file_utils.py 2. **变量名一致性**: - 在模板中使用 `file_tree` 替代 `files` - 在 FileListHandler 中传递 `file_tree` 变量 3. **文件类型识别**: - 增强 `get_file_type` 函数,优先根据扩展名判断文件类型 - 为各种文件类型添加明确的处理逻辑 4. **路径处理**: - 在 JavaScript 函数中正确处理当前路径 - 在打开目录和播放音乐时拼接完整路径 5. **错误处理**: - 添加更详细的错误日志 - 确保所有路径操作都进行安全检查 ### 验证步骤 1. 确保所有文件都已保存 2. 重启服务器 3. 访问文件列表页面,验证: - 目录可以正常打开 - 文件可以预览 - 音乐可以播放 - 没有出现 500 错误 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值