Python 文件操作

文件操作是编程中绕不开的核心技能------无论是读取配置文件、处理日志数据、存储程序运行结果,还是实现数据的持久化,都离不开对文件的操作。Python 凭借简洁的语法和强大的标准库,让文件处理变得高效而优雅。本文将从基础到高级,系统性地讲解 Python 文件操作的所有知识点,并配有丰富的实战案例。

一、文件操作的核心概念

1.1 文件操作的三部曲

在 Python 中,对文件进行操作的经典流程是三步:打开文件 → 读写文件 → 关闭文件 。打开文件是通过内置的 open() 函数来实现的,它返回一个文件对象。

python 复制代码
# 传统三步曲(不推荐)
f = open('demo.txt', 'w', encoding='utf-8')  # 打开文件
f.write('Hello World')                        # 读写文件
f.close()                                     # 关闭文件

1.2 为什么必须关闭文件?

手动关闭文件存在两大风险:

  • 资源泄漏:未关闭的文件描述符会占用系统资源,可能导致程序运行缓慢甚至崩溃。
  • 数据丢失 :写入操作会先进入缓冲区,如果程序异常退出而未调用 close(),缓冲区中的数据可能无法写入磁盘。

推荐使用 with 语句来自动管理文件生命周期。

二、打开文件:open() 函数详解

2.1 基本语法

open() 函数的基本语法如下:

python 复制代码
file_object = open(file_path, mode='r', encoding=None, buffering=-1)
  • file_path :文件路径,支持相对路径(如 data/log.txt)和绝对路径(如 C:/project/data.csv)。
  • mode:打开模式,决定文件的读写权限。
  • encoding :编码格式,处理文本文件时推荐指定为 'utf-8'

2.2 文件模式详解

open() 函数的第二个参数 mode 决定了可以对文件执行哪些操作。常见的模式如下:

模式 名称 行为 适用场景
'r' 只读 文件必须存在,否则报错;指针在开头 读取配置/日志
'w' 覆盖写入 清空原文件,不存在则创建 生成新文件
'a' 追加写入 在文件末尾添加内容,不存在则创建 持续记录日志
'x' 独占创建 如果文件已存在则失败 防止意外覆盖
'r+' 读写 文件必须存在,可读可写 修改文件中间内容
'w+' 读写 文件存在则覆盖,不存在则创建 写入后读取
'a+' 读写 在末尾追加,可读取 追加并读取
'b' 二进制模式 与 r/w/a 组合使用(如 'rb' 处理图片/音频等非文本
't' 文本模式 默认模式 处理文本文件

2.3 常用组合模式示例

python 复制代码
# 以只读模式打开(默认)
with open('config.ini', 'r', encoding='utf-8') as f:
    content = f.read()

# 以写入模式打开(覆盖原内容)
with open('output.txt', 'w', encoding='utf-8') as f:
    f.write('新内容')

# 以追加模式打开(在末尾添加)
with open('app.log', 'a', encoding='utf-8') as f:
    f.write('2026-06-26: 程序启动\n')

# 以二进制模式读取图片
with open('image.jpg', 'rb') as f:
    data = f.read()

# 以读写模式打开(文件必须存在)
with open('data.txt', 'r+', encoding='utf-8') as f:
    content = f.read()
    f.seek(0)          # 回到开头
    f.write('新内容')

三、文件读写操作

3.1 读取文件的四种方法

文件对象提供了多种读取方法:

方法 说明
read(size=-1) 读取整个文件或指定大小的数据
readline() 读取一行
readlines() 读取所有行并返回列表
直接迭代 逐行迭代,内存友好
(1)read() --- 一次性读取全部内容

适合小文件,大文件会导致内存问题。

python 复制代码
with open('config.json', 'r', encoding='utf-8') as f:
    full_content = f.read()
    print(full_content)

# 读取指定字节数
with open('data.txt', 'r', encoding='utf-8') as f:
    first_100 = f.read(100)  # 读取前100个字符
(2)readline() --- 逐行读取
python 复制代码
with open('data.txt', 'r', encoding='utf-8') as f:
    line1 = f.readline()  # 第一行
    line2 = f.readline()  # 第二行
    print(line1, line2)
(3)readlines() --- 读取所有行到列表
python 复制代码
with open('data.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()  # 返回列表,每行作为一个元素
    for line in lines:
        print(line.strip())
(4)直接迭代 --- 最内存友好的方式

适用于大文件,逐行处理,内存占用恒定。

python 复制代码
error_count = 0
with open('server.log', 'r', encoding='utf-8') as f:
    for line in f:  # 逐行读取,内存占用恒定
        if 'ERROR' in line:
            error_count += 1
print(f"发现 {error_count} 个错误")

3.2 写入文件的两种方法

(1)write() --- 写入单行
python 复制代码
with open('output.txt', 'w', encoding='utf-8') as f:
    f.write('第一行内容\n')  # 必须手动添加换行符
    f.write('第二行内容\n')
(2)writelines() --- 写入多行
python 复制代码
lines = ['苹果\n', '香蕉\n', '橙子\n']
with open('fruits.txt', 'w', encoding='utf-8') as f:
    f.writelines(lines)  # 不会自动添加换行符,需要自行处理

# 如果列表中元素没有换行符,可以这样处理
data = ['苹果', '香蕉', '橙子']
clean_data = [f"{item}\n" for item in data]
with open('fruits.txt', 'w', encoding='utf-8') as f:
    f.writelines(clean_data)

四、with 语句与上下文管理器

4.1 为什么使用 with 语句?

传统的 open() + close() 模式存在三大隐患:

  1. 忘记调用 close() 导致资源泄漏
  2. 异常发生时文件无法正常关闭
  3. 代码冗余

with 语句通过上下文管理器自动处理资源释放,即使发生异常也能确保文件关闭。

4.2 基本用法

python 复制代码
# 传统方式(存在风险)
try:
    f = open('data.txt', 'r')
    data = f.read()
finally:
    f.close()  # 必须手动关闭

# with 语句(优雅且安全)
with open('data.txt', 'r', encoding='utf-8') as f:
    data = f.read()
# 离开 with 块后文件自动关闭,无需手动操作

4.3 同时打开多个文件

python 复制代码
# 同时读写两个文件
with open('source.txt', 'r', encoding='utf-8') as src, \
     open('dest.txt', 'w', encoding='utf-8') as dst:
    content = src.read()
    dst.write(content)

五、文件指针控制:seek() 与 tell()

文件指针记录了当前读写位置,通过 seek()tell() 可以实现精确定位控制。

5.1 tell() --- 获取当前位置

python 复制代码
with open('data.txt', 'r', encoding='utf-8') as f:
    print(f.tell())  # 0,指针在开头
    f.read(10)
    print(f.tell())  # 10,已读取10个字节

5.2 seek() --- 移动指针

seek(offset, whence) 的语法:

  • offset:偏移量(字节数)
  • whence :参照位置
    • 0(默认):文件开头
    • 1:当前位置
    • 2:文件末尾
python 复制代码
with open('data.txt', 'rb') as f:
    # 回到文件开头
    f.seek(0)
    
    # 移动到文件末尾前10个字节
    f.seek(-10, 2)
    last_10_bytes = f.read()
    
    # 从当前位置向后移动5个字节
    f.seek(5, 1)

5.3 实战:读取文件首尾

python 复制代码
# 读取文件前10字节和最后10字节
with open('large_file.dat', 'rb') as f:
    first_part = f.read(10)        # 读取前10字节
    f.seek(-10, 2)                 # 移动到末尾前10字节
    last_part = f.read(10)         # 读取最后10字节

六、异常处理

文件操作中可能会遇到各种异常,如文件不存在、权限不足等。使用 try-except 可以优雅地处理这些情况。

6.1 常见异常类型

  • FileNotFoundError:文件不存在
  • PermissionError:权限不足
  • IOError:其他 I/O 错误

6.2 异常处理示例

python 复制代码
try:
    with open('config.txt', 'r', encoding='utf-8') as f:
        content = f.read()
        print(content)
except FileNotFoundError:
    print('错误:文件不存在')
except PermissionError:
    print('错误:没有读取权限')
except IOError as e:
    print(f'错误:无法读取文件 - {e}')

6.3 使用 try-except-finally

python 复制代码
f = None
try:
    f = open('data.txt', 'r', encoding='utf-8')
    content = f.read()
    print(content)
except FileNotFoundError:
    print('文件不存在')
finally:
    if f:
        f.close()  # 确保文件被关闭
    print('操作完成')

七、文件编码处理

7.1 编码的基本概念

Python 3 中,文本文件默认使用 UTF-8 编码。但实际工作中可能会遇到各种编码的文件(如 GBK、GB2312 等),需要正确处理以避免乱码。

7.2 指定编码读写文件

python 复制代码
# 读取 UTF-8 编码的文件
with open('data.txt', 'r', encoding='utf-8') as f:
    content = f.read()

# 读取 GBK 编码的文件
with open('data_gbk.txt', 'r', encoding='gbk') as f:
    content = f.read()

# 写入时指定编码
with open('output.txt', 'w', encoding='utf-8') as f:
    f.write('你好,世界!')

7.3 处理编码错误

python 复制代码
# 忽略无法解码的字符
with open('data.txt', 'r', encoding='utf-8', errors='ignore') as f:
    content = f.read()

# 用替代字符替换无法解码的字符
with open('data.txt', 'r', encoding='utf-8', errors='replace') as f:
    content = f.read()

7.4 自动检测文件编码

可以使用 chardet 库来检测文件编码:

python 复制代码
import chardet

with open('unknown.txt', 'rb') as f:
    raw_data = f.read()
    result = chardet.detect(raw_data)
    encoding = result['encoding']
    print(f'检测到的编码:{encoding}')

with open('unknown.txt', 'r', encoding=encoding) as f:
    content = f.read()

八、二进制文件操作

对于非文本文件(如图片、音频、视频等),需要使用二进制模式。

8.1 读取二进制文件

python 复制代码
# 读取图片文件
with open('image.jpg', 'rb') as f:
    image_data = f.read()
    print(f'文件大小:{len(image_data)} 字节')

8.2 写入二进制文件

python 复制代码
# 复制二进制文件
with open('source.jpg', 'rb') as src:
    data = src.read()
    
with open('copy.jpg', 'wb') as dst:
    dst.write(data)

8.3 大文件分块复制

对于大文件,应该分块读取和写入以避免内存占用过高:

python 复制代码
chunk_size = 4096  # 4KB 块大小
with open('source.mp4', 'rb') as src:
    with open('copy.mp4', 'wb') as dst:
        while True:
            chunk = src.read(chunk_size)
            if not chunk:
                break
            dst.write(chunk)

九、os 模块:文件和目录操作

os 模块提供了与操作系统交互的功能,包括文件和目录操作。

9.1 常用 os 文件操作

python 复制代码
import os

# 获取当前工作目录
current_dir = os.getcwd()
print(f'当前目录:{current_dir}')

# 列出目录下的所有文件和子目录
files = os.listdir('.')
print(f'目录内容:{files}')

# 重命名文件
os.rename('old_name.txt', 'new_name.txt')

# 删除文件
os.remove('unnecessary.txt')

# 检查文件是否存在
if os.path.exists('data.txt'):
    print('文件存在')

# 检查是否为文件
if os.path.isfile('data.txt'):
    print('这是一个文件')

# 检查是否为目录
if os.path.isdir('my_folder'):
    print('这是一个目录')

9.2 目录操作

python 复制代码
import os

# 创建单级目录
os.mkdir('new_folder')

# 创建多级目录
os.makedirs('parent/child/grandchild')

# 删除空目录
os.rmdir('empty_folder')

# 删除目录树(谨慎使用)
import shutil
shutil.rmtree('folder_to_delete')

9.3 路径操作

python 复制代码
import os

# 拼接路径
path = os.path.join('folder', 'subfolder', 'file.txt')
print(path)  # folder/subfolder/file.txt (Windows 下为 folder\subfolder\file.txt)

# 获取文件名
filename = os.path.basename('/path/to/file.txt')  # file.txt

# 获取目录名
dirname = os.path.dirname('/path/to/file.txt')    # /path/to

# 分离文件名和扩展名
name, ext = os.path.splitext('file.txt')          # ('file', '.txt')

十、shutil 模块:高级文件操作

shutil 模块提供了更高级的文件操作功能,如复制、移动、删除目录树等。

10.1 复制文件

python 复制代码
import shutil

# 复制文件(复制内容和权限)
shutil.copy('source.txt', 'destination.txt')

# 复制文件(保留元数据)
shutil.copy2('source.txt', 'destination.txt')

10.2 复制目录

python 复制代码
import shutil

# 递归复制整个目录
shutil.copytree('source_folder', 'destination_folder')

10.3 移动文件/目录

python 复制代码
import shutil

# 移动文件或目录
shutil.move('source.txt', 'new_location/source.txt')

10.4 删除目录树

python 复制代码
import shutil

# 递归删除整个目录(谨慎使用!)
shutil.rmtree('folder_to_delete')

十一、CSV 文件读写

CSV(逗号分隔值)是存储表格数据的常用格式。Python 内置的 csv 模块提供了便捷的读写功能。

11.1 写入 CSV 文件

python 复制代码
import csv

# 写入 CSV(使用 writer)
data = [
    ['姓名', '年龄', '城市'],
    ['张三', 25, '北京'],
    ['李四', 30, '上海'],
    ['王五', 28, '深圳']
]

with open('people.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.writer(f)
    writer.writerows(data)

# 使用 DictWriter 写入字典数据
data_dict = [
    {'name': '张三', 'age': 25, 'city': '北京'},
    {'name': '李四', 'age': 30, 'city': '上海'}
]

with open('people_dict.csv', 'w', newline='', encoding='utf-8') as f:
    fieldnames = ['name', 'age', 'city']
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(data_dict)

11.2 读取 CSV 文件

python 复制代码
import csv

# 读取 CSV(使用 reader)
with open('people.csv', 'r', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)  # row 是一个列表

# 使用 DictReader 读取为字典
with open('people_dict.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row['name'], row['age'], row['city'])

十二、JSON 文件读写

JSON 是轻量级的数据交换格式,与 Python 的字典和列表天然契合。

12.1 写入 JSON 文件

python 复制代码
import json

data = {
    'name': '张三',
    'age': 25,
    'city': '北京',
    'hobbies': ['阅读', '编程', '旅游']
}

with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)  # indent 美化输出

12.2 读取 JSON 文件

python 复制代码
import json

with open('data.json', 'r', encoding='utf-8') as f:
    data = json.load(f)
    print(data['name'])   # 张三
    print(data['hobbies'])  # ['阅读', '编程', '旅游']

12.3 JSON 与字符串互转

python 复制代码
import json

# Python 对象 → JSON 字符串
data = {'name': '张三', 'age': 25}
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)  # {"name": "张三", "age": 25}

# JSON 字符串 → Python 对象
json_str = '{"name": "张三", "age": 25}'
data = json.loads(json_str)
print(data['name'])  # 张三

十三、临时文件与目录

tempfile 模块用于创建临时文件和目录,在程序结束后会自动清理。

13.1 创建临时文件

python 复制代码
import tempfile

# 创建临时文件(匿名,不保留文件名)
with tempfile.TemporaryFile(mode='w+t') as tf:
    tf.write('临时数据')
    tf.seek(0)
    content = tf.read()
    print(content)
# 离开 with 块后文件自动删除

# 创建有名称的临时文件
with tempfile.NamedTemporaryFile(mode='w+t', delete=True) as tf:
    tf.write('临时数据')
    print(f'临时文件路径:{tf.name}')
    tf.seek(0)
    print(tf.read())
# 离开 with 块后文件自动删除

13.2 创建临时目录

python 复制代码
import tempfile
import os

# 创建临时目录
with tempfile.TemporaryDirectory() as tmpdir:
    print(f'临时目录:{tmpdir}')
    # 在临时目录中创建文件
    with open(os.path.join(tmpdir, 'temp.txt'), 'w') as f:
        f.write('临时文件')
# 离开 with 块后目录自动删除

十四、综合实战案例

14.1 案例一:日志分析器

统计日志文件中的错误数量,并将错误行写入单独的文件。

python 复制代码
def analyze_log(log_file, error_output):
    """分析日志文件,提取错误行"""
    error_count = 0
    error_lines = []
    
    try:
        with open(log_file, 'r', encoding='utf-8') as f:
            for line in f:
                if 'ERROR' in line.upper():
                    error_count += 1
                    error_lines.append(line.strip())
        
        # 将错误行写入输出文件
        with open(error_output, 'w', encoding='utf-8') as f:
            f.write(f'共发现 {error_count} 个错误:\n')
            f.write('=' * 50 + '\n')
            f.writelines([line + '\n' for line in error_lines])
        
        print(f'分析完成!共发现 {error_count} 个错误')
        print(f'错误详情已保存到:{error_output}')
        
    except FileNotFoundError:
        print(f'错误:日志文件 {log_file} 不存在')
    except PermissionError:
        print(f'错误:没有权限读取文件 {log_file}')
    except IOError as e:
        print(f'错误:{e}')

# 使用示例
analyze_log('server.log', 'error_report.txt')

14.2 案例二:学生成绩管理系统(数据持久化)

将学生数据保存到 JSON 文件,实现数据的持久化存储。

python 复制代码
import json
import os

class StudentManager:
    def __init__(self, data_file='students.json'):
        self.data_file = data_file
        self.students = []
        self.load_data()
    
    def load_data(self):
        """从文件加载学生数据"""
        if os.path.exists(self.data_file):
            try:
                with open(self.data_file, 'r', encoding='utf-8') as f:
                    self.students = json.load(f)
                print(f'已加载 {len(self.students)} 名学生数据')
            except (json.JSONDecodeError, IOError) as e:
                print(f'加载数据失败:{e}')
                self.students = []
        else:
            print('数据文件不存在,将创建新文件')
    
    def save_data(self):
        """保存学生数据到文件"""
        try:
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(self.students, f, ensure_ascii=False, indent=2)
            print('数据已保存')
        except IOError as e:
            print(f'保存数据失败:{e}')
    
    def add_student(self, name, age, score):
        """添加学生"""
        student = {'name': name, 'age': age, 'score': score}
        self.students.append(student)
        self.save_data()
    
    def list_students(self):
        """列出所有学生"""
        if not self.students:
            print('暂无学生数据')
            return
        print('=' * 40)
        print(f"{'姓名':<10} {'年龄':<6} {'成绩':<6}")
        print('-' * 40)
        for s in self.students:
            print(f"{s['name']:<10} {s['age']:<6} {s['score']:<6}")
        print('=' * 40)
    
    def get_average_score(self):
        """计算平均成绩"""
        if not self.students:
            return 0
        total = sum(s['score'] for s in self.students)
        return total / len(self.students)

# 使用示例
manager = StudentManager('students.json')

# 添加学生
manager.add_student('张三', 18, 92)
manager.add_student('李四', 19, 85)
manager.add_student('王五', 18, 78)

# 列出所有学生
manager.list_students()

# 计算平均成绩
print(f'平均成绩:{manager.get_average_score():.2f}')

14.3 案例三:大文件处理

处理大型日志文件时,使用分块读取和逐行处理来节约内存。

python 复制代码
def process_large_file(file_path, keyword, output_file):
    """
    在大文件中搜索包含关键字的行
    使用逐行读取,内存友好
    """
    found_count = 0
    
    try:
        with open(file_path, 'r', encoding='utf-8') as src:
            with open(output_file, 'w', encoding='utf-8') as dst:
                for line in src:
                    if keyword in line:
                        dst.write(line)
                        found_count += 1
                        
                        # 每处理1000行显示一次进度
                        if found_count % 1000 == 0:
                            print(f'已找到 {found_count} 行')
        
        print(f'处理完成!共找到 {found_count} 行包含 "{keyword}" 的内容')
        print(f'结果已保存到:{output_file}')
        
    except FileNotFoundError:
        print(f'错误:文件 {file_path} 不存在')
    except MemoryError:
        print('错误:内存不足,请尝试使用分块处理')
    except Exception as e:
        print(f'处理过程中发生错误:{e}')

# 使用示例
process_large_file('huge_server.log', 'ERROR', 'errors.txt')

14.4 案例四:文件批量重命名

批量重命名指定目录下的所有文件,添加日期前缀。

python 复制代码
import os
from datetime import datetime

def batch_rename(directory, prefix=None):
    """
    批量重命名目录下的所有文件
    添加日期前缀或自定义前缀
    """
    if not os.path.exists(directory):
        print(f'错误:目录 {directory} 不存在')
        return
    
    if not os.path.isdir(directory):
        print(f'错误:{directory} 不是一个目录')
        return
    
    # 获取所有文件
    files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))]
    
    if not files:
        print('目录中没有文件')
        return
    
    # 生成前缀
    if prefix is None:
        prefix = datetime.now().strftime('%Y%m%d_')
    
    renamed_count = 0
    for filename in files:
        # 跳过已经包含前缀的文件
        if filename.startswith(prefix):
            continue
        
        old_path = os.path.join(directory, filename)
        new_path = os.path.join(directory, prefix + filename)
        
        try:
            os.rename(old_path, new_path)
            renamed_count += 1
            print(f'重命名:{filename} → {prefix + filename}')
        except OSError as e:
            print(f'重命名 {filename} 失败:{e}')
    
    print(f'完成!共重命名了 {renamed_count} 个文件')

# 使用示例
batch_rename('./documents', '20260626_')

十五、最佳实践总结

15.1 核心原则

  1. 始终使用 with 语句管理文件,自动处理资源的打开和关闭。
  2. 始终指定编码 (如 encoding='utf-8'),避免乱码问题。
  3. 处理大文件时使用逐行读取或分块读取,避免内存溢出。
  4. 做好异常处理 ,捕获 FileNotFoundErrorPermissionError 等常见异常。
  5. 处理文件路径时使用 os.path.join(),保证跨平台兼容性。

15.2 常见陷阱与解决方案

陷阱 解决方案
忘记关闭文件导致资源泄漏 使用 with 语句自动管理
写入内容未保存 调用 flush() 或使用 with 语句
中文乱码 读写时明确指定 encoding='utf-8'
大文件一次性读取导致内存爆炸 使用逐行读取或分块读取
文件路径在不同操作系统不兼容 使用 os.path.join() 拼接路径

15.3 速查表

操作 代码
打开文件 with open(path, mode, encoding=enc) as f:
读取全部 content = f.read()
读取一行 line = f.readline()
读取所有行 lines = f.readlines()
逐行迭代 for line in f:
写入字符串 f.write(text)
写入多行 f.writelines(list_of_strings)
获取指针位置 pos = f.tell()
移动指针 f.seek(offset, whence)
复制文件 shutil.copy(src, dst)
移动文件 shutil.move(src, dst)
删除文件 os.remove(path)
检查文件存在 os.path.exists(path)
读取 CSV csv.reader(f)
写入 CSV csv.writer(f)
读取 JSON json.load(f)
写入 JSON json.dump(obj, f)

通过本文的系统学习,你应该已经掌握了 Python 文件操作的所有核心知识点------从基础的打开、读写、关闭,到进阶的指针控制、异常处理、编码管理,再到 os/shutil 模块、CSV/JSON 格式处理,以及大文件处理和临时文件等高级技巧。熟练运用这些技能,你将能够高效地处理各种文件操作场景,写出更加健壮和专业的 Python 程序。

相关推荐
负责的蛋挞2 小时前
异步HttpModule的实现方式
java·服务器·前端
涛声依旧-底层原理研究所2 小时前
Agent 长任务可靠性设计:实现暂停、恢复、续跑与崩溃重启的完整方案
人工智能·python·系统架构
AC赳赳老秦2 小时前
防火墙规则批量配置实战:OpenClaw 自动生成模板、批量下发与合规性校验全解析
java·开发语言·人工智能·python·github·php·openclaw
小小编程路2 小时前
如何优化while循环的性能?
python
Tian_Hang2 小时前
Eclipse Ditto 物模型相关代码
java·运维·服务器·ide·eureka·eclipse
lzqrzpt3 小时前
LED驱动电源选型标准与工程应用技术要点解析
python·单片机·嵌入式硬件·物联网
Maiko Star3 小时前
Python核心语法——函数
开发语言·python
linzᅟᅠ3 小时前
README
人工智能·python
瓶中怪4 小时前
ROS2 机器人软件系统
linux·c++·python·ubuntu·vmware·ros2·机器人软件开发