You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python下载文件写入报错:如何仅在文件末尾追加指定字符串

问题说明

使用Python实现文件下载+末尾追加指定行功能时,首次运行抛出如下类型错误:

f.write(data + """<auth-user-pass>
TypeError: can't concat str to bytes

将字符串修改为b"""<auth-user-pass>"""格式后类型错误消失,但出现新问题:自定义字符串被重复追加到文件每一段内容后,而非仅出现在整个文件尾部。尝试f.write(str(data) + "<auth-user-pass>")写法仍未达到预期效果。

原实现代码如下:

import requests
from multiprocessing.pool import ThreadPool


def download_url(url):
    print("downloading: ", url)
    # 逻辑说明:取url中最后一个/后的片段作为文件名
    # 例如url为abc/xyz/file.txt时,文件名为file.txt
    file_name_start_pos = url.rfind("/") + 1
    file_name = url[file_name_start_pos:]

    save_path = 'ovpns/'

    complete_path = os.path.join(save_path, file_name)
    print(complete_path)
    r = requests.get(url, stream=True)
    if r.status_code == requests.codes.ok:
        with open(complete_path, 'wb') as f:
            for data in r:
                f.write(data + """<auth-user-pass>
username
password
</auth-user-pass>""")

    return url

servers = [
    "us-ca72.nordvpn.com",
    "us-ca73.nordvpn.com"
]

urls = []
for server in servers:
    urls.append("https://downloads.nordcdn.com/configs/files/ovpn_legacy/servers/" + server + ".udp1194.ovpn")

# 开启5个线程并发执行任务,每次从urls列表取一个元素传入下载函数
results = ThreadPool(5).imap_unordered(download_url, urls)
for r in results:
    print(r)
错误原因
  • 类型错误:requests流式下载返回的data是二进制(bytes)类型,无法直接和字符串(str)类型拼接
  • 内容重复追加:追加自定义内容的逻辑写在了响应内容遍历循环内部,每读取一块下载数据就会拼接一次自定义内容写入,导致内容重复出现在文件中
  • 原代码缺失os模块导入,运行时会触发名称错误,且没有提前创建存储目录,目录不存在时会抛出文件写入异常
修复后代码
import os
import requests
from multiprocessing.pool import ThreadPool


def download_url(url):
    print("downloading: ", url)
    file_name_start_pos = url.rfind("/") + 1
    file_name = url[file_name_start_pos:]

    save_path = 'ovpns/'
    # 自动创建存储目录,已存在时不报错
    os.makedirs(save_path, exist_ok=True)
    complete_path = os.path.join(save_path, file_name)
    print(complete_path)
    
    # 待追加内容提前转为bytes类型
    append_content = b"""<auth-user-pass>
username
password
</auth-user-pass>"""

    r = requests.get(url, stream=True)
    if r.status_code == requests.codes.ok:
        # 先完整写入下载的原文件内容
        with open(complete_path, 'wb') as f:
            for data in r:
                f.write(data)
        # 原文件写入完成后,以二进制追加模式在末尾写入自定义内容
        with open(complete_path, 'ab') as f:
            f.write(append_content)

    return url

servers = [
    "us-ca72.nordvpn.com",
    "us-ca73.nordvpn.com"
]

urls = []
for server in servers:
    urls.append("https://downloads.nordcdn.com/configs/files/ovpn_legacy/servers/" + server + ".udp1194.ovpn")

results = ThreadPool(5).imap_unordered(download_url, urls)
for r in results:
    print(r)
关键调整点
  • 补全os模块导入,新增目录自动创建逻辑,避免路径不存在导致的写入失败
  • 全程使用二进制模式读写文件,不需要做bytes和str的类型转换,避免编码问题
  • 将追加内容的逻辑移出下载循环,等原文件全部写入完成后再执行追加操作,保证自定义内容仅在文件末尾出现一次

内容的提问来源于stack exchange,提问作者Ppap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 09:06:52