【C++修炼之路】string 概述

👑作者主页:@安 度 因
🏠学习社区:StackFrame
📖专栏链接:C++修炼之路

文章目录

  • 一、string 为何使用模板
  • 二、string 类认识
    • 1、构造/析构/赋值运算符重载
    • 2、容量操作
    • 3、增删查改
    • 4、遍历
    • 5、迭代器
    • 6、非成员函数
    • 7、库函数※
  • 三、测试扩容
  • 四、写时拷贝
  • 五、win 下 string 的内存分布

如果无聊的话,就来逛逛 我的博客栈 吧! 🌹

一、string 为何使用模板

image-20230208161508298

string 是 typedef 后的模板,也就相当于是这样:

template<class T>

class basic_string
{
private:
	T* _str;
	// ... 
};

// typedef basic_string<char> string;

int main()
{
	string s("hello");

	return 0;
}

那 string 不就是字符串,管理字符不就是 char ,为什么使用模板?因为编码问题。

计算机是 usa 发明的,一开始对于计算机只需要显示英文就可以,编码简单,因为表示简单;通过计算机编码,将数据翻译为二进制序列,将其组合,一个字节表示一个 char ,将英文和符号进行一个映射,通过建立映射关系(编码表)完成编码。例如 ascii编码表 – 表示英文。

字符根据 ascii 码表中的 ascii 值,以二进制存储在计算机内的就是对应的数值,根据这些,就可以表示出英文。

例如 “helllo” 存储在内存中就是每个字符的 ascii 表对应的数组:

image-20230208162415414

早期计算机只有欧美在用,只有英文的编码方式,但是后来对于世界别国也需要用了,需要让电脑编码能适用于全球,所以后来就诞生了: u n i c o d e unicode unicode ,为了表示全世界文字的编码表(unicode 包含 ascii),它支持各种问题的编码,比如 unicode 就兼容 utf-8, utf-16, utf-32 .

所有的编码通过值与符号建立映射关系,对与英文比较简单,但是对于类似于中文的编码就比较困难。原先一字节存储一个英文字符,但是对于中文可能存不下;所以对于中文字符,可以存储为 2 个字节,这样子 256 * 256 就可以表示 65536 个汉字。但是如果想要扩展更多的话,对于空间的消耗就大了,所以 uft-8 就把常见的汉字用两个字节编,生僻的用若干个字节进行编(Linux 下默认编码就是 uft-8)。

比如:

image-20230208163147012

两个字节存储一个中文字符,根据编码表查阅字符。

编译器中也可以更改编码方式:

image-20230208164232145

如果编码对应不上就是所谓的乱码。

中文自己量身定做的编码表 gbk ,windows 下默认 gbk ,linux 下 utf-8,例如 GB2312 就是 gbk .

根据这种方式,也可以让一些不良用语,根据词库,隐藏为 **** .但是仍然可以使用同音字,比如如下现象:

image-20230208165325701

有时候,这种也可以吟唱国粹。由于这些同音字都是挨着的,所以也可以选中国粹中重音的字根据范围屏蔽。

多种编码:

image-20230208170858515

有些字符串会用两个字符表示一个值,例如 wchar_t 宽字节:

image-20230208170551006

就是 wstring . 另外两个也都是为了更好的表示编码。

而 string 就是 basic_string 的一个实例,用来存储 char 字符,我们日常使用 string 即可,特殊情况要灵活使用。

二、string 类认识

认识:

  1. 字符串是表示字符序列的类

  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。

  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。

  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。

  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

总结:

  1. string是表示字符串的字符串类

  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator>string;

  4. 不能操作多字节或者变长字符的序列。

在使用string类时,必须包含 #include 头文件以及 using namespace std; ,string 在 std 命名空间。

1、构造/析构/赋值运算符重载

七个构造函数:

image-20230208171409660

1(s1),2(s2),4(s3)常用

image-20230208172159305

由于 string 重载了 >> 与 << 所以可以直接进行输入输出。

(3):从 pos 位置开始,截取 len 长度,初始化 string ,len 有缺省值 nops 为 -1 ,为静态成员变量。len 类型为 size_t ,转换为一个很大的数字,即截取整个字符串。同理,当 len 长度超过 string 本身长度时,都会截取从 pos 位置开始的整个字符串。

image-20230208172910423

(5):取字符串的前 n 个字符初始化

image-20230208173412755

(6):用 c 来填充 n 个字符

image-20230208173510428

析构函数

不用管,自动释放:

image-20230208173649362

赋值运算符重载

image-20230208173729547

2、容量操作

image-20230208181008877

1)size/length :计算 string 长度

length 先出现,后来出现的 size ,因为 size 比较适用,因为 length 不符合其他 ds 的大小说明,推荐使用 size .

int main()
{
	string s1;
	cin >> s1;

	cout << s1.size() << endl;
	cout << s1.length() << endl;

	return 0;
}

2)max_size:string 的最大长度,没有被界定,根据多种情况衡量

cout << s.max_size() << endl; // 2147483647

我的电脑是这么多。

3)capacity:算此刻容量

int main()
{
	string s1;
	cout << s1.capacity() << endl; // 15

	return 0;
}

实际上是 16 ,但是有一个给了 ‘\0’ ,为实际能存储的字符个数。

4)clear:清理数据,不清理空间;清理数据后,可以用 capacity ,检查空间是否被清理

image-20230209085842892

5)empty:判断是否为空,空返回1,非空返回0

关于容量的增长

除第一次二倍增长,其他均约呈 1.5 倍正常:

image-20230209104308835

起始空间是放到一个对象的数组(16大小,包含 \0 ,15是有效字符)中,数组满了,对象中就不存在这个数组,在堆上开了一个32容量的空间,之后呈 1,5 倍增长(PJ版本);而 linux 上的是呈二倍增长的(SGI版本)。

image-20230209105406535

一句话,版本不同,时代更新。虽然功能一样,但是每个版本的底层可能都不一样,因为不同版本的源码都在更新。

6)reserve :不是 reverse 逆置。reserve 是请求容量的改变,传递参数,来改变容量

频繁扩容有消耗,所以一次性把空间开大,就可以减少增容时的消耗:

image-20230209110658974

但是申请的元素会根据上面说的对齐方式,比如这边申请 1000 个,他会申请1008个,一个给 \0 ,可用 1007 个。

7)reszie:开辟空间并改变数据个数。可以给值对空间进行初始化,不给默认为 \0

image-20230209111348988

image-20230209111449611

reserve/resize 不会对已有的数据进行修改,是扩容/扩容+初始化,不是覆盖:

image-20230209112820055

如果 resize 给的空间比初始容量小,则会保留初始数据,后面的被删除:

image-20230209113156599

对于 reserve 给的大小比已有容量小时,则不会改变容量大小

image-20230209113848362

但是如果空间中的数据被清空,则可以减容,由此可见不可约束力:

杭哥说是:数据没有清空,所以仍然可能增容减容,所以并不会缩减容量,但是数据清空就没问题了,就认为不需要空间,就可以减容:

image-20230702121244975

image-20230702121858057

6、7总结:

  • reserve :开空间,影响容量
  • resize:开空间,改变数据个数 size ,对这些空间给一个初始值并初始化,不给值默认给 \0

3、增删查改

image-20230208181025567

改:

operator[] :可以像数组一样访问

image-20230208181455211

s1[i] <==> s1.operator[](i)

可以 s1[i] 修改 string 的内容,operator[] 类似:

char& operator[] (size_t pos)
{
    return _str[pos];
}

这里的引用返回不是为了减少拷贝(char 空间小),而是为了支持修改返回对象。

image-20230209093008481

at 和 operator[] 一样,以函数形式使用:

s1.at(i) -= 1; // 例如

它们检查越界的方式不一样,operator[] :使用断言;at:抛异常:

operator[] :s1[100]

image-20230208182941095

at:s1.at(100)

image-20230208183015208

增:

image-20230208183247171

push_back:尾插一个字符;append:尾插一个字符串

image-20230208183453764

operator+= 也可以起到插入的效果,字符和字符串都可以,推荐使用:

image-20230208183540993

insert:插入 string ,可以再任意位置插入,但是效率不高,一般是 O ( N ) O(N) O(N)

image-20230209214225464

(5):

image-20230209214548708

查:

c_str:c_str 返回的是 string 的首元素地址

image-20230209114646043

image-20230209114831766

与 c 库中函数或文件操作时配合使用 c_str

int main()
{
    string file("test.txt");
    FILE* out = fopen(file.c_str(), "w"); // 第一个参数为 char* 
}

find:在 string 中查找内容(看文档)

image-20230209115306867

image-20230209204506633

(2):找c字符串,返回第一个找到的位置下标;找不到返回 npos ,是无符号的 -1 ,是一个极大的值;当数字很大时,就认定这个位置不存在,因为 stirng 过大,也不实际了

substr:从 pos 位置开始,取 len 个字符,len 缺省值为 npos ,如果不给 len ,默认截取从 pos 位置开始的所有字符串

image-20230209204529731

find 和 substr 组合使用:

image-20230209205950965

pos 找到 . 开始的位置,从 . 位置开始截取后面的所有元素。pos 返回的是下标,总长 - 下标 = . 之后的长度;;如果想要直接截到结尾,可以 substr(pos) 一步到位。

如果连续后缀,要取最后一个?可以使用 rfind ,反向取:

image-20230209210757600

第三个 find 使用

image-20230209213934533

erase,三种重载:

image-20230209214707363

第一个比较常用:从 pos 位置开始删除 len 个字符,如果不给 len ,则默认从该位置删完

image-20230209215039641

pop_back 是尾删,就不演示了,很简单。

4、遍历

三种遍历和修改的方法:

1)operator[]

void test_str1()
{
	string s1("hello");
	for (size_t i = 0; i < s1.size(); i++)
	{
		s1[i] += 1;
	}

	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i] << ' ';
	}
}

2)迭代器

void test_str1()
{
	string s1("hello");
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
        *it += 1; // 修改
		cout << *it << ' ';
        ++it;
	}
	cout << endl;
}

image-20230209093505724

当前理解为 it 就是 h 位置的指针,s1.begin() 返回第一个位置 h 的地址;s1.end() 返回最后一个位置下一个位置的地址 \0 . 迭代器是内嵌类型,是在 类中定义的,类型名称就是 iterator ,全局没有这个迭代器,所以要指定类域。

对于 string 来说,while(it < s1.end()) 也可以进行遍历,因为 string 是连续的;但是推荐用 != ,因为其他容器的迭代器可能不支持。

这里我们先用,把迭代器想象成:像指针一样的类型 ,之后模拟实现时,慢慢理解清楚。

3)范围 for(C++11)

void test_str1()
{
	string s1("hello");
	for (auto& e : s1) // 加引用修改
	{
		e += 1;
		cout << e << ' ';
	}
}

自动取出元素,作为别名,往后迭代,自动判断结束。(底层类似被替换为迭代器遍历)

5、迭代器

image-20230209095850447

正向迭代器 begin 和 end 我们已经说过使用方式,下面讲解别的。

rbegin/rend 是反向迭代器

void test_str2()
{
	string s1("hello world");
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		*rit += 1;
		cout << *rit << ' ';
		++rit;
	}
}

image-20230209100131570

类似于:

image-20230209100303563

++rit 是往左边走的,与正向迭代器相反。

const 的正向迭代器

image-20230209102342866

给 const 对象用的,const 对象调用 const 的迭代器,可读但不可写

image-20230209102804855

对于普通的 string 对象,也可以使用 const 迭代器,权限缩小是可以的:

image-20230209102910279

同理,对于 const 的反向迭代器也是一样的。

C++11 中有 cbegin,cend等专门区分 const 的迭代器:

因为当用 auto 进行类型推导时,比如这样:

void foo(const string& s)
{
    auto it = s.begin();
}

这里 it 是 auto 推导的,是不是 const 迭代器需要根据参数才能看出,所以后来规定 const 迭代器可以使用 cbegin 等,但是一般不常用。

迭代器遍历的意义是什么?对于 string ,无论是正着遍历还是倒着遍历,下标 + [] 都足够好用,为什么还要迭代器?

迭代器是适用于所有容器的,都可以通过迭代器访问。

对于 string ,下标和 [] 就足够好用,确实可以不用迭代器,但是如果是其他容器(数据结构),其他容器就不支持,比如 list ,map 等,它们都是不支持下标遍历的。

迭代器是用统一的方式支持遍历的。

结论:对于 string ,得会用迭代器,一般用下标。

6、非成员函数

image-20230209215230075

getline :

cin 在遇到空白字符时,会停止读取,其他数据留在缓冲器;getline 可以读取带空格的一行 string :

image-20230210101858079

第一个参数是 istream ,即 cin .

原理类似于:

int main()
{
	string s1;
	char ch = cin.get();
	while (ch != '\n')
	{
		s1 += ch;
		ch = cin.get(); // cin 的成员函数,一个字符一个字符拿
	}
	cout << s1 << endl;

	return 0;
}

一个字符一个字符读取。

image-20230210102106641

image-20230211092903484

string 的比较;可以支持 string 和 string ,string 和 char,因为重载了:

image-20230211093215427

根据 ascii 码值比较,大的则大一旦比较时不相等,直接返回结果;类似于 strcmp

7、库函数※

image-20230211093750072

一些库函数,比如 atoi 和 itoa ,在 C++ 中并不好用;并且它们并不是标准库下的函数,可能换个 ide 就不好用了。这时这些库函数就发挥了作用。

stoi :string 转 int(默认十进制),平时我们一般用整形,所以其他的可以先不用管。

image-20230211094612908

image-20230211094419767

同理,剩下几个函数,是对不同类型数据的转换。

image-20230211094906123

将数据转换为字符串(C++11):

image-20230211094931829

image-20230211095145766

(double 默认转六位)

三、测试扩容

void TestPushBackReserve()
{
	string s;
	s.reserve(100);
	size_t sz = s.capacity();
	cout << "capacity changed: " << sz << '\n';


	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('c');
		if (sz != s.capacity())
		{
			sz = s.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

vs:大约 1.5 倍

初始容量为 15,其实有 16 个,一个是 \0

image-20230709082227345

linux :2 倍

image-20230709082605785

四、写时拷贝

image-20230709082707299

写时拷贝就是一种拖延症,是在浅拷贝的基础之上增加了引用计数的方式来实现的。

引用计数:用来记录资源使用者的个数。在构造时,将资源的计数给成1,每增加一个对象使用该资源,就给计数增加1,当某个对象被销毁时,先给该计数减1,然后再检查是否需要释放资源,如果计数为1,说明该对象时资源的最后一个使用者,将该资源释放;否则就不能释放,因为还有其他对象在使用该资源。

当修改对象时,发现引用计数不为 1,则对对象进行深拷贝,并将两个引用计数都置为 1 。

Linux 下为写时拷贝:

image-20230709083313100

image-20230709083338939

一开始为浅拷贝,修改对象时,进行深拷贝。

五、win 下 string 的内存分布

win 下当 string 中有效字符 <= 15 时,sizeof(str) 大小为 28

image-20230709084858341

image-20230709085009154

win 财大气粗,在初识状态有一个 16 字节的 _Buf(能存 15 个,有一个给 \0) ,根据对齐,大小为 15 + 1 + 4 + 4 + 4 ,为 28

当 size < 16 时,字符存在 _buf 数组中;size >= 16 存在 _Ptr 指向的堆空间中:

image-20230709085303604

优点:string 小时,效率高

缺点:string 大时,存在空间浪费

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

P1 第一章 电路模型与电路定律

1、什么是电路模型&#xff1f; 实际电路与电路模型间的关系&#xff1f;建立在相同的电路理论基础之上。 实际电路定义&#xff1a;由电工设备和电气器件&#xff0c;按照预期目的连接构成的&#xff0c;电流的通路。 实际电路的功能&#xff1a;能量方面&#xff0c;可以传输…

Vivado 下 呼吸灯实验

目录 Vivado 下 呼吸灯实验 1、实验简介 2、实验环境 3、实验任务 4、硬件设计 5、程序设计 5.1、呼吸灯代码如下&#xff1a; 5.2、添加约束文件 .xdc 5.3、下载验证 Vivado 下 呼吸灯实验 呼吸灯最早由苹果公司发明并应用于笔记本睡眠提示上&#xff0c;其一经展出&…

MySQl数据库第五课 --------在SQl的简单命令--------学习学习

作者前言 欢迎小可爱们前来借鉴我的gtiee秦老大大 (qin-laoda) - Gitee.com ———————————————————————————— 目录 数据库的简单介绍 1.数据储存 2.数据库类型 &#xff08;1&#xff09;.关系型数据库 &#xff08;2&#xff09;.非关系型数据库…

第四章 网络层【计算机网络】

第四章 网络层【计算机网络】 前言推荐第四章 网络层4.1 网络层的几个重要概念4.1.1 网络层提供的两种服务4.1.2 网络层的两个层面例-路由表的建立 4.2网际协议IP4.2.1 虚拟互连网络4.2.2 IP地址例-分类地址练习例-子网划分例-聚合超网4.2.3IP地址与MAC地址4.2.4地址解析协议AR…

elk高并发架构

1.前言 普通的elk架构只适合数据量小的情景&#xff0c;而且也不安全&#xff0c;在瞬时数据量大的情况下可能会导致logstash崩溃&#xff0c;从而导致数据的丢失&#xff0c;对于数据安全有较高要求&#xff0c;可以在架构中加入消息队列&#xff0c;既可以防止瞬时的大流量并…

软件UI工程师的职责模板

软件UI工程师的职责模板1 职责&#xff1a; 1.负责产品的UI视觉设计(手机软件界面 网站界面 图标设计产品广告及 企业文化的创意设计等); 2.负责公司各种客户端软件客户端的UI界面及相关图标制作; 3.设定产品界面的整体视觉风格; 4.为开发工程师创建详细的界面说明文档&…

TiDB(6):数据迁移-TiDB Lightning

1 TiDB Lightning介绍 TiDB Lightning 是一个将全量数据高速导入到 TiDB 集群的工具&#xff0c;目前支持 Mydumper 或 CSV 输出格式的数据源。你可以在以下两种场景下使用 Lightning&#xff1a; 迅速导入大量新数据。 备份恢复所有数据。 TiDB Lightning 主要包含两个部分…

路由的介绍

目录 路由器的转发原理&#xff1a;路由表 路由——指示路由器去往未知网段的方法 路由器的转发原理&#xff1a;路由表 当一个数据包来到路由器&#xff0c;路由器将基于数据包中的目标IP地址查询自身的路由表&#xff0c;如果路由表中有相应的记录&#xff0c;则无条件根据…

VMware16.0安装教程和创建

许可证&#xff1a; ZF3R0-FHED2-M80TY-8QYGC-NPKYFYF390-0HF8P-M81RQ-2DXQE-M2UT6ZF71R-DMX85-08DQY-8YMNC-PPHV8设置网络 添加镜像 下载centos7镜像网址https://mirrors.aliyun.com/centos/7/isos/x86_64/?spma2c6h.25603864.0.0.d7724511YPrZpg win10镜像地址https://ww…

【Spring boot+VUE2+Android 7.1】智慧校园源码

一、智慧校园实现了智慧校园基础数据的统一管理&#xff0c;通过此平台提供教师基础信息管理、学生基础信息管理、用户认证管理、权限管理、资源管理、应用管理、第三方应用接入等基础功能与服务。 二、源码包含&#xff1a;电子班牌管理系统、成绩管理系统、考勤人脸刷卡管理系…

总结STM32嵌入式面试知识点

一、STM32F1和F4的区别&#xff1f; 内核不同&#xff1a;F1是Cortex-M3内核&#xff0c;F4是Cortex-M4内核&#xff1b;主频不同&#xff1a;F1主频72MHz&#xff0c;F4主频168MHz&#xff1b;浮点运算&#xff1a;F1无浮点运算单位&#xff0c;F4有&#xff1b;功能性能&…

MySQL之数据库引擎详解(内附面试题:InnoDB和MyISAM的联系与区别)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于MySQL数据库引擎的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一. 数据库引擎是什么&#xff…

LinuxCP插件virtio与内核vhost

以下为LCP创建的接口对&#xff0c;VPP侧为物理接口port7&#xff0c;映射到Linux侧的为虚拟接口hostap1&#xff0c;接口hostap1作为vhost的后端存在。VPP侧接口tap1为前端的virtio接口。 vpp# show lcp itf-pair: [0] port7 tap1 hostap1 24 type tap vdp# vdp# show interf…

【计算机视觉 | 图像分割】arxiv 计算机视觉关于图像分割的学术速递(7 月 3 日论文合集)

文章目录 一、分割|语义相关(4篇)1.1 SPAE: Semantic Pyramid AutoEncoder for Multimodal Generation with Frozen LLMs1.2 Achieving RGB-D level Segmentation Performance from a Single ToF Camera1.3 Topological Data Analysis Guided Segment Anything Model Prompt Op…

双非本大二上岸大厂——念念不忘,必有回响

⭐️前言⭐️ 博主就读于一所普通的学校&#xff08;双非本&#xff09;&#xff0c;在大二下学期3月份开始网上投递简历&#xff0c;历时近百余天&#xff0c;投递简历500&#xff0c;面试近40余场&#xff0c;最终在6月份学期末&#xff0c;斩获了两个大厂offer&#xff08;北…

开发框架前后端分离的好处是什么

关于将前端和后端保持在一起或分开&#xff0c;存在广泛的意见分歧。唯一重要的是&#xff0c;这两个组件对于开发成熟的应用程序都是必需的。 考虑&#xff1a;紧密耦合的前端和后端 许多人认为后端和前端的分离是一个坏主意&#xff0c;这两个角色之间没有太大区别。 以下…

MySQL-SQL存储过程/触发器详解(下)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

计算机体系结构基础知识介绍之缓存性能的十大进阶优化之编译器优化和硬件预取(六)

优化七&#xff1a;编译器优化&#xff0c;降低miss率 处理器和主内存之间不断扩大的性能差距促使编译器编写者仔细检查内存层次结构&#xff0c;看看编译时优化是否可以提高性能。再次&#xff0c;研究分为指令缺失的改进和数据缺失的改进。接下来介绍的优化可以在许多现代编…

【图像识别】openCV基础知识

图像处理基础 一、使用OpenCV前要准备的工作1.先导入需要用到的库2.自定义&#xff0c;图片展示函数 二、开始学习常用函数1.生成随机整数①. 函数说明②.代码a. 二维灰度图b. 三维彩色图 ③.代码现象a. 二维灰度图b. 三维彩色图 2.通道的分离与合并①先导入一张图片② 将其RGB…

Python获取指定路径下所有文件的绝对路径

import osdef get_file_path_by_name(file_dir, format.JPG):获取指定路径下所有文件的绝对路径:param file_dir::return:L []for root, dirs, files in os.walk(file_dir): # 获取所有文件for file in files: # 遍历所有文件名if os.path.splitext(file)[1] format: L.ap…