Python文件进行写操作后立即读出的结果、原因分析、解决方法

本文深入探讨了Python中文件的读写操作,对比了read()和readlines()的区别,解析了文件指针的位置如何影响读写结果,并介绍了seek()函数的使用方法,帮助读者理解并掌握Python文件操作的关键细节。
  1. 问题引出
with open('***.txt','r+') as f:    #读操作与写操作
    f.write(‘Hello, world!’)    #写入
    cNames = f.readlines()    #读出语句,可用read()也可用readlines(),下表就两种情况进行了区别
    print(cNames)    
读出语句readlinesread
前提准备先新建一个文件***.txt内容为空,否则模式为‘r+’会报错找不到文件同readlines
运行结果与运行次数关系第一次运行,输出结果为空;第二次运行,结果为一个[Hello, World!];第三次运行,结果为[Hello, World!Hello, World!];…;第n次运行,结果为n-1个Hello, World!的列表每次运行结果均为空
文件内容与运行次数关系运行n次,文件中有n个Hello, World!无论运行多少次,文件中只有一个Hello,World!

原因分析:读写时有一个文件指针,数据从文件指针所在位置开始读写。上述程序通过write对文件进行写操作,此时文件指针已经在文件的尾部。

那为什么使用read和readlines会有不一样的运行结果呢?

read()在当前指针处开始读,而当前指针在文件尾部,其后为空,故read()每次运行均为空;写的时候从文件开头写,实行覆盖机制,故不论运行多少次文件内容均为一个Hello,World!

readlines()是回文件开头读取内容,但是刚刚写入的还没有保存故只能读出写入操作之前的文件内容,故readlines()每次运行得到的‘Hello,World!’个数比运行次数少1;写的时候在文件尾部写,故运行多少次,文件内容有多少个Hello,World!

  1. 解决办法

为了解决上述问题,让文件指针指向需要的位置,Python提供了seek()函数
语法:file_obj.seek(offset,whence = 0)
[offset: 偏移量]
[whence: 起始位置 0——文件头部(默认值);1——当前位置;2——文件尾部]

例如: seek(0) # 指针移到文件头部
seek(50,1) #指针向后移动50字节

将seek函数运用于上述代码:

with open('***.txt','r+') as f:    #读操作与写操作
    f.write(‘Hello, world!’)    #写入
    f.seek(0)    #读出前将指针移到文件开头
    cNames = f.readlines()    #文件所有行读出,此处也可以使用read()函数,结果一样
    print(cNames)  

运行结果分析
每一次运行结果均为[Hello, World!]

<think>我们被要求编一个Web目录扫描器,针对特定URL(yky.com)仅读取目录结构,不需要获取页面内容。这意味着我们只需要发送HTTP请求并分析响应,以发现存在的目录。思路:1.我们可以通过发送HTTP请求(如GET)到目标URL的各个路径,然后根据HTTP状态码来判断目录是否存在(例如状态码200表示成功,403表示禁止访问,但存在;404表示不存在)。2.但是,注意:我们不需要读取文件内容,所以只需要关注响应头即可,尤其是状态码。另外,有些服务器可能会对不存在的路径返回200(比如跳转到自定义404页面),所以我们需要谨慎处理。3.为了提高效率,我们可以使用多线程或异步IO。然而,用户要求的是“目录结构”,所以我们可能需要一个目录字典,尝试常见的目录名(如admin, images, css等)来检查是否存在。步骤:a)准备一个目录名字典(可以从文件读取,或者内置一个简单的列表)b)拼接URL:base_url(如http://yky.com) +目录名c)发送HTTP请求(HEAD方法可能更合适,因为HEAD只获取响应头,不获取内容,节省带宽和时间) d)根据响应状态码判断目录是否存在(通常2xx和3xx表示存在,4xx表示不存在,但403可能表示存在但无权访问,所以我们可以将403也视为存在) e)输出存在的目录注意:我们只关注目录,所以需要在目录名后面加上斜杠(/)?但有些服务器即使不加斜杠也会重定向到带斜杠的目录。我们可以先尝试不加斜杠,然后根据重定向来判断。但为了简单,我们可以直接尝试带斜杠的路径。但是,用户要求是“目录结构”,所以我们的目标应该是发现像http://yky.com/admin/这样的路径。实现:我们将使用requests库,并采用多线程来提高速度。由于用户指定了目标URL为yky.com,但注意yky.com可能没有协议,我们可以假设为http(或者https?)。为了安全,我们可以尝试https,如果失败再尝试http?但用户没有指定,我们最好让用户指定或者同时尝试两种协议?不过题目要求是特定URL,所以我们可以直接使用http://yky.com/作为基础URL。但是,为了程序的通用性,我们可以让用户输入URL,不过题目要求是yky.com,所以我们可以死,但最好还是作为参数。根据要求,我们只输出目录结构,所以我们将发现的目录打印出来。由于我们不需要读取内容,所以使用HEAD请求。但是,有些服务器可能不支持HEAD,那么我们可以用GET,但是不读取响应体(stream=True,然后立即关闭连接)。不过,HEAD是标准方法,大多数服务器支持。代码结构:1.读取字典文件(如果没有,则使用内置的常见目录列表)2.创建线程池,对每个目录进行扫描3.发送HEAD请求(如果HEAD不被支持,则改用GET,但只取头部)4.分析状态码,如果状态码是200、301、302、307、403等,我们认为目录存在(注意:301、302是重定向,可能重定向到登录页等,所以存在)5.打印存在的目录注意:要处理异常(如连接超时、SSL错误等)由于用户没有提供字典,我们可以使用一个简单的内置列表,但最好是从文件读取,这样方便扩展。这里我们假设字典文件名为"dir_list.txt",每行一个目录名。但是,用户要求是“仅读取目录结构”,所以我们扫描的深度只有一层?还是多层?题目没有明确。根据要求,我们只做一层目录扫描(即基础URL下一级目录)。因此,我们只扫描base_url +directory+'/',然后检查。代码实现:我们将使用内置的常见目录列表作为默认,同时允许从文件加载。由于我们不知道yky.com的协议,我们可以先尝试http,如果遇到重定向到https,则自动跳转(requests默认会处理重定向)。但是,我们只关心最终状态码。不过,我们也可以设置不允许重定向,然后自己判断。但为了简单,我们允许重定向,并检查最终状态码。但是,注意:如果我们允许重定向,那么对于301/302,最终可能会重定向到一个存在的页面,状态码200。所以我们允许重定向,然后检查最终的URL和状态码。然而,我们只关心目录是否存在,所以允许重定向并检查200也是可以的。但是,有些目录重定向到登录页,那也是存在的。因此,我们允许重定向(requests默认允许),然后检查状态码。步骤:1.构造URL:base_url +dir_name +'/'(加斜杠表示目录)2.发送HEAD请求(允许重定向)3.如果状态码在200-399之间,或者403,我们认为目录存在。4.注意:避免重复扫描(比如base_url本身可能会重定向到某个目录,但我们扫描的是子目录)但是,我们也可以不加斜杠,因为有些服务器会自动补全斜杠。我们这里先尝试不加斜杠,然后根据响应处理?但题目要求目录结构,所以目录应该以斜杠结尾。我们统一在目录名后加上斜杠。代码:由于我们使用多线程,注意线程安全(打印时可能会混乱,所以使用锁)我们使用concurrent.futures.ThreadPoolExecutor。注意:设置合理的超时时间(如5秒)和User-Agent头(模拟浏览器,避免被简单的屏蔽)示例代码:注意:我们假设base_url为"http://yky.com",然后扫描http://yky.com/dir/这样的路径。内置字典:我们可以用一个列表,如['admin','backup','images','css','js','upload','download']等。但是,为了灵活性,我们最好从文件读取字典。如果文件不存在,则使用内置字典。下面我们编代码:</think>### Python Web目录扫描器实现 针对您的需求(扫描yky.com的目录结构,不读取文件内容),我将提供一个高效、简洁的Python实现方案: ```python import requests from concurrent.futures import ThreadPoolExecutor def scan_directory(base_url, directory, timeout=5): """ 扫描单个目录是否存在 :param base_url: 目标网站基础URL :param directory: 要扫描的目录名 :param timeout: 请求超时时间(秒) :return: (目录路径, 状态码) """ url = f"{base_url.rstrip('/')}/{directory}/" try: # 使用HEAD方法只获取响应头,不下载内容 response = requests.head( url, headers={'User-Agent': 'Mozilla/5.0'}, allow_redirects=False, timeout=timeout ) return (url, response.status_code) except requests.exceptions.RequestException: return (url, None) def web_directory_scanner(target_url, wordlist): """ Web目录扫描器 :param target_url: 目标URL (如: http://yky.com) :param wordlist: 目录字典列表 """ valid_dirs = [] # 使用线程池提高扫描效率 with ThreadPoolExecutor(max_workers=20) as executor: futures = [ executor.submit(scan_directory, target_url, dir_name) for dir_name in wordlist ] for future in futures: url, status = future.result() # 判断存在的目录: 2xx/3xx/403状态码 if status and (status < 400 or status == 403): print(f"[+] Found: {url} ({status})") valid_dirs.append(url) print(f"\nScan completed. Found {len(valid_dirs)} valid directories.") return valid_dirs if __name__ == "__main__": # 配置参数 TARGET_URL = "http://yky.com" # 示例目录字典 (实际使用时应替换为完整字典文件) DIRECTORY_WORDLIST = [ "admin", "backup", "images", "assets", "uploads", "css", "js", "log", "tmp" ] # 执行扫描 web_directory_scanner(TARGET_URL, DIRECTORY_WORDLIST) ``` ### 实现说明 1. **高效扫描策略**: - 使用`HEAD`方法而非`GET`:只获取响应头,不下载内容,节省带宽和时间 - 线程池并发请求:通过`ThreadPoolExecutor`实现并发扫描 - 超时控制:防止单个请求阻塞整个扫描过程 2. **目录存在判断逻辑**: - 有效状态码:`2xx`(成功), `3xx`(重定向), `403`(禁止访问) - 排除`404`(不存在)和请求异常 3. **关键参数配置**: - `User-Agent`:模拟浏览器请求,避免被简单拦截 - `allow_redirects=False`:不跟随重定向,直接获取原始响应 - `timeout=5`:合理设置超时时间 ### 使用指南 1. **准备目录字典**: - 创建文本文件(如`directories.txt`),每行一个目录名 - 推荐使用标准字典如: - [SecLists/Discovery/Web-Content](https://github.com/danielmiessler/SecLists) - [DirBuster directory list](https://github.com/KajanM/DirBuster-WordLists) 2. **运行扫描器**: ```python # 从文件加载字典 with open('directories.txt') as f: wordlist = [line.strip() for line in f] # 执行扫描 web_directory_scanner("http://yky.com", wordlist) ``` 3. **结果示例输出**: ``` [+] Found: http://yky.com/admin/ (200) [+] Found: http://yky.com/uploads/ (301) [+] Found: http://yky.com/backup/ (403) Scan completed. Found 3 valid directories. ``` ### 注意事项 1. **法律合规性**: - 仅扫描您拥有权限的目标网站 - 避免高频请求导致服务中断 2. **性能优化**: - 调整`max_workers`参数控制并发数 - 对于大型字典,可分批处理 - 添加随机延迟避免触发防护 3. **错误处理增强**: - 可添加重试机制处理临时错误 - 记录失败请求用于后续分析 - 支持HTTPS证书验证选项 此实现满足您的核心需求:高效发现目录结构而不获取文件内容,同时保持代码简洁和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值