C++程序设计课件:第7章 输入输出流_第1页
C++程序设计课件:第7章 输入输出流_第2页
C++程序设计课件:第7章 输入输出流_第3页
C++程序设计课件:第7章 输入输出流_第4页
C++程序设计课件:第7章 输入输出流_第5页
已阅读5页,还剩90页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、输入/输出流层次 终端输入/输出 文件读写,输入/输出流,流 - 数据在程序和设备之间“流动”,流的基本概念,流的基本概念,流 - 可以看作一个无限长的二进制数字序列 通过读写指针进行流的读和写(以字节为单位),将流上的数据读进变量x,将y的值写入流,y,x,输出流 可以看作一端无限,另一端通过写指针不停地向后写入新内容的单向流,,写指针,流的基本概念,输入流 可以看作一端无限,另一端通过读指针不停地从流中读取新内容的单向流,读出的内容从流中删去。,读指针,流的基本概念,有格式读写,以某种数据类型为单位读写 例如:读一个整数,写一个浮点数等; 无格式读写,以字节为单位读写,不区分其中的内容 例

2、如:读20个字节,写50个字节等;,有格式读写和无格式读写字符方式/二进制方式读写,缓冲,引入缓冲的目的是解决CPU的运行速度和外设操作速度 不匹配的矛盾。如输出时先写入缓冲区,再成批输出。 成批写出数据比一个一个写出数据节约时间。,一般地,缓冲区在内存中。,向输出流中写数据时,通常是先向缓冲区中写,当缓冲区写满时,才真正向输出流写;也可以通过函数在程序中主动将缓冲区内容写入输出流。,缓冲区刷新,基本输入输出流类体系,C+预定义了流类,用于完成数据的“流动”(输入输出),流基类,通用输入流基类,通用输出流基类,通用输入输出流类基类,抽象缓冲区基类,在这些已定义的类中, 给出了若干方法(成员函数

3、), 用于控制输入输出。,使用上述流类,必须包含头文件 “ iostream”,用运算符重载实现标准设备的输入输出,观察头文件istream.h :,class istream : virtual public ios public: istream,C+ 对基本的数据类型,均定义了重载运算符 ,将右移位运算符 重载为 提取 运算符, class istream_withassign : public istream ; extern istream cin; ,编译器会将 cinxy; 解释成 (cin.operator(x) .operator(y);,I/O流 C+的输入/输出操作由标准

4、I/O库实现,通常称为I/O流 I/O流是一个利用模板、多继承和虚继承实现的类层次结构,用它可以进行内置数据类型的终端(控制台)、文件和内存输入/输出操作 类的设计者也可以扩展I/O流类层次,来处理自定义类型数据的输入和输出,终端输入输出 终端输入操作由输入流istream提供 终端输出操作由输出流ostream提供 iostream是同时从istream和ostream派生的类,允许双向的输入/输出 为了使用输入/输出操作,需要包含头文件 iostream库预定义了一些标准流对象: cin:istream类对象,代表标准输入,用于从用户终端读入数据 cout:ostream类对象,代表标准输

5、出,用于向用户终端写数据 cerr:ostream类对象,代表标准错误输出,用于输出错误消息 标准流的默认输入/输出设备是控制台(console)终端,同理: C+还定义了三个输出流对象 cout、cerr 和 clog。 这三个对象均是ostream_withassign类的对象, 它们均在头文件ostream.h中被定义,cin 标准输入流(输入设备是键盘) cout 标准输出流(输出设备是显示器) cerr 标准错误输出流,没有缓冲,立刻输出。 clog 输出日志信息,有缓冲,缓冲区满后被输出。,同理在ostream类中重载了 运算符,编译器会将 coutxy; 解释成 (cout.op

6、erator(x) .operator(y);,例 使用cout、cerr和clog #include #include void main( ) double x; coutx; if(x0) cerrx is not a positive number!n; /B return; clogThe root of x is sqrt(x)endl; /C ,在本例中,cout、cerr和clog的作用相同。 而cerr和clog的区别在于,cerr是非缓冲输出, 而clog是缓冲输出。请看例14.3:,缺省的输入输出格式 1缺省的(默认的)输入格式,cin 是缓冲流,当输入一行结束按回车(E

7、nter)时, 操作系统将输入内容放入输入缓冲区, 然后 cin 从输入缓冲区提取数据。,输入数据时,在缺省的情况下,数据之间的分隔符为: 键(空格键)、键(制表键)或键(回车键),这三个键通称为空白字符。,输入数据的类型必须与提取数据的变量类型一致。,如:char c1, c2, c3; cinc1c2c3; 程序运行时, 可输入:abc 也可输入:ab c 或输入:a b c 在上述情况下, 三个变量c1、c2和c3获得值均为 a、b 和 c。 应注意,最后输入的总是回车键。,又如:char s120, s220; cins1s2; 输入abcd 或输入abcd 或输入abcd 结果字符串

8、s1和s2提取的值均分别为ab和cd。,回车 起两个作用: 表示一行结束,可进行提取操作了。 可用它做数据分隔符。,7.4 用成员函数实现输入输出 7.4.1 输出函数 在ostream类中定义了一些公有成员函数,用于输出。,ostream /刷新输出流,例:int i=97; cout.put( char(i) ); char c=*; cout.put( c ); cout.write(abcd, 2);,运行结果: a*ab,表示输出一个字符,表示输出字符串 前 n 个字符,7.4.2 输入函数 在istream类中定义了一些公有成员函数,控制输入。,读取一个字符, 不跳过空白字符,注意

9、 get( ) 和 getline( ) 的区别!,读取一行字符, 不提取n,读取一行字符, 提取n,例: 读取字符和字符串 void main( ) char c1, c2, c3; char str180, str2100; cout输入三个字符:; c1=cin.get( ); cin.get(c2); cin.get(c3); cin.get( ); cout输入第一行字符串:; cin.get(str1,80); cin.get( ); cout输入第二行字符串:; cin.getline(str2,80);,运行: abc computer operator,续: cout.put

10、(c1).put(c2).put(c3).put(n); cout.write(str1, 3); cout.write(str2, strlen(str2); cout.put(n); ,输出结果: abc comoperator,例7.14 输入成员函数的使用 #include #include void main( ) char buf20, max20; int cnum, mc=0; while(cin.getline(buf, 20) / A 提取一行字符,读取并舍弃行尾标志n cnum = cin.gcount( ); / B 获取A行的getline( )实际读取的字符个数 i

11、f(cnummc) mc=cnum; strcpy(max, buf); coutlen=cnum-1,bufendl; / C coutmax len=mc-1,maxendl; / D ,程序的运行状况是: an apple len=8, an apple very good len=9, very good pear? len=5, pear? ok! len=3, ok! Z /输入Ctrl+z,表示输入流结束。 max len=9, very good,程序功能: 输入若干行字符(假定每行少于20个字符),输出每行的字符个数,最后将最长的行及其长度输出。,7.5 重载插入和提取运算符

12、,istream 和 ostream 类对标准数据类型,已定义了 重载运算符: 提取运算符 和 插入运算符 。看头文件 istream.h,对用户新定义的数据类型如“复数”, 能否直接使用 和 进行提取和插入操作呢?,即 如果 Complex c1, c2; 能否 cin c1 ; cout c2;,回答:能! 但必须在定义Complex 类时, 定义重载运算符 和 。,如:int x; cinx; 则自动解释成 cin.operator(x);,前已述,“文件”指:,(1) 磁盘文件 (2) 设备文件(如键盘、显示器、打印机等),这里特别介绍: 磁盘文件,文本文件中存放的是“文本流”- 一串

13、 ASCII 字符,二进制文件中存放的是“二进制流” - 按内存的二进制格式存放(内存映象),在“流”中的数据是以字节为单位的。,文件操作是指对文件中的内容进行读写。,文件流,数值 12345 在 文本流中和二进制流中的形式:,区别:,在“流”中的 数据是以字节 为单位的。,7.6.1 文件流类体系,在流类体系中,包含文件流类体系,完成从文件提取数据,完成向文件插入数据,完成提取插入操作,完成文件缓冲区管理,7.6.2 文件的打开和关闭,文件的使用过程如下: (1) 定义一个文件流对象 (2) 打开文件 (3) 对文件进行读写操作 (4) 关闭文件,1. 定义一个文件流对象 如:ifstrea

14、m infile; /用于与一个输入文件建立联系 ofstream outfile; /用于与一个输出文件建立联系 fstream iofile; /用于与一个输入输出文件建立联系,使用文件流类, 必须包含头文件 “fstream.h”,如:infile.open(“myfile1.txt”); /打开 myfile1.txt 用于读 outfile.open(“myfile2.txt”); /打开 myfile2.txt 用于写 iofile.open(“myfile3.txt”, ios:in| ios:out); /打开 myfile3.txt 用于读写,定义流对象和打开文件可合二为一:

15、,调用成员函数 打开文件。,调用构造函数 打开文件。,2. 打开文件,open( ) 函数格式,打开文件成员函数 格式:,void fstream:open(const char *, int, int=filebuf:openprot); void ifstream:open(const char *, int=ios:in, int=filebuf:openprot); void ofstream:open(const char *, int=ios:out, int=filebuf:openprot);,参数 ios: 意义,在 ios 类中,定义了一个公有的无名枚举成员, 用于定义文件

16、的打开方式。,enum open_mode in=0 x01, /按读方式打开文件 out=0 x02, /按写方式打开文件 ate=0 x04, app=0 x08, /按增补(追加)方式打开文件 trunc=0 x10, nocreate=0 x20, noplace=0 x40, binary=0 x80, /打开二进制文件 ;,引用方式为: ios:in ios:out ios:in|ios:binary ios:out |ios:binary 等等,位运算“|”或,组合条件,与 cin 和 cout 的用法相同 如:infile x; outfile y;,3. 对文件进行读写操作,

17、在对文件进行读写时,我们将文件看成字符流,,随着文件的读写,指针移动。,4. 关闭文件,void ifstream:close( ); void ofstream:close( ); void fstream:close( );,如:infile.close( ); /切断与输入文件 myfile1.txt 的联系 outfile.close( ); /切断与输出文件 myfile2.txt 的联系 iofile.close( ); /切断与输入输出文件 myfile3.txt 的联系,文件读写完毕,必须关闭。,关闭文件成员函数 格式 :,14.6.3 文本文件的读写,例 14.21 将数值1

18、100及其平方根写入文件 sqrttable.txt #include #include #include void main( ) double x; ofstream out; / 定义一个输出流对象 out.open(sqrttable.txt); / 打开文本文件sqrttable.txt for(x=1; x=100; x+) outxtsqrt(x)endl; / 将结果写入文件 out.close( ); / 关闭文件 ,演示并察看结果文件,例 14.22 编写一个程序,用于显示一个文本文件 #include #include #include void main( ) char

19、 filename40, line80; ifstream infile; coutfilename; / A infile.open(filename); / B,if(!infile) coutCan not open file: filenameendl; exit(1); while(infile.getline(line, 80) / 读入一行 coutlineendl; infile.close( ); / 显示一行 ,演示,“!”为重载的运算符,7.6.4 二进制文件的读写,1. 文件的读写操作(成块读写),前三个为读取操作:将第二个参数指定的字节数读入到 以第一个参数为起始地址

20、的内存中。,后三个为写操作:从第一个参数为起始地址的内存开始, 将连续的第二个参数指定字节数的 内容写到文件中。,7.7 文件的随机访问,文件内容,读写数据后自动移动,istream类和ostream类 提供成员函数 , 控制读写位置指针的移动, 实现文件的随机读写。,文件刚打开时:,前三个:适用于输入文件 get 后三个:适用于输出文件 put,其中: 在 ios 类中定义 typedef long streamoff ; /offset typedef long streampos; /position,所以, 本质上, streamoff 和 streampos 就是long 类型,另外

21、,在 ios 类中定义枚举类型: enum seek_dir beg=0, /文件开始处,使用 ios:beg cur=1, /当前位置, 使用 ios:cur end=2 /文件结束处,使用 ios:end ;,用于指定移动文件 指针时的参照点。,同理得出后三个函数的功能!,例 7.29 将Fibonnaci数列的前40项写入二进制文件fib.bin中,然后输出其中的奇数项,每行输出5个数。 #include #include #include #include void main( ) fstream iofile(fib.bin,ios:in|ios:out|ios:binary); i

22、f( !iofile ) coutCan not open file: fib.binendl; exit(1); ,streampos pos = iofile.tellp( ); coutBegin posi=posendl; int f1=1, f2=1; for( int i=0; i20; i+ ) iofile.write(char*),例 7.29 续2 iofile.seekp(0, ios:beg); /将读写位置指针重新定位于文件起始位置 for(i=0; i20; i+) iofile.read(char*) ,二进制文件读写,直接写二进制数据,记事本看未必正确。,/下面

23、的程序从键盘输入几个学生的姓名的成绩,/ 并以二进制 /文件形式存起来 #include #include using namespace std; class CStudent public: char szName20; int nScore; ;,int main() CStudent s; ofstream OutFile( c:tmpstudents.dat, ios:out|ios:binary); while( cin s.szName s.nScore ) if( stricmp(s.szName,“exit”) = 0) /名字为exit则结束 break; OutFile.

24、write(char * ) ,输入: Tom 60 Jack 80 Jane 40 exit 0 则形成的 students.dat 为 72字节,用 记事本打开,呈现: Tom 烫烫烫烫烫烫烫烫 Jack 烫烫烫烫烫烫烫蘌 Jane 烫烫烫烫烫烫烫?,/下面的程序将 students.dat 文件的内容读出并显示 #include #include using namespace std; class CStudent public: char szName20; int nScore; ;,int main() CStudent s; ifstream InFile(“c:tmpstud

25、ents.dat”,ios:in);if(!InFile) cout error endl; return 0; while( InFile.read( (char* ) ,输出: Tom 60 Jack 80 Jane 40,/下面的程序将 students.dat 文件的Jane的名字改成Mike #include #include using namespace std; class CStudent public: char szName20; int nScore; ;,输出: Tom 60 Jack 80 Mike 40,int main() CStudent s; fstream

26、 iofile( c:tmpstudents.dat,ios:in|ios:out); if( !iofile) cout error ; return 0; iofile.seekg( 2 * sizeof(s),ios:beg);/定位写指针到第三个记录 iofile.write(Mike,strlen(Mike)+1); iofile.seekp(0,ios:beg); /定位读指针到开头 while( iofile.read( (char* ) ,7.8 输入输出流的出错处理,ios类中,有一个输入输出出错状态字state, 各状态位由ios类中定义的枚举常量来表示: enum io_

27、state goodbit = 0 x00, / 表示状态正常 eofbit = 0 x01,/ 表示达到了文件结尾 failbit = 0 x02,/ 表示I/O操作失败 badbit = 0 x04 / 表示试图进行非法操作 ;,在使用流进行输入输出操作时,可能会出现一些错误。 如当程序中需要输入整型数时,在输入流中却出现了字符。 C+提供一套类机制,用于检测输入输出流状态,以发现错误并清除错误状态。,ios 类提供了几个内联函数,用于完成查看状态字state中的各个状态位、清除状态字等工作。 各函数的功能是: rdstate( ) 返回当前状态字 operator!( ) ! 运算符重载

28、,与fail( )函数功能相同 bad( ) 如果badbit被置位,返回真,否则返回假 clear(int _i=0) 用参数 _i 置新的状态字 eof( ) 如果eofbit被置位,返回真,否则返回假 fail( ) 如果badbit或failbit被置位,返回真,否则返回假 good( ) 如果无任何错误返回真,否则返回假,例7.31 出错处理函数的使用 #include void main( ) double aver=0, score; char temp80; for(int i=0; iscore; while(cin.rdstate( ) / 若有输入错误 cin.clear

29、( ); / 清除出错状态,但错误输入依然留在输入缓冲区中,cin.getline(temp,80); / 将缓冲区中的错误输入读入到temp,丢弃 coutscore; aver+=score; aver/=10; coutaver=“ averendl; ,程序的一次运行状况可能如下: 10 20 30 a a为非法输入,请重新输入! 40 50 60 70 80 90 100 aver=55,异常处理,程序中的错误及处理 异常机制 多态异常处理,编写健壮、没有Bug的程序是软件开发的首要任务,实际软件开发中,花费最大的是测试、发现和修复Bug。预测和处理错误占据了大多数代码。 发现问题的

30、时间越晚,修复所需付出的代价越高。 尽量避免产生错误; 编译器发现的语法错误; 通过编译的Bug,首次测试被发现; 偶尔出现的Bug(更难被发现修复); 程序的脆弱性(异常输入、内存不足等)。,程序中的各种错误,-59-,不同类型的Bug,Bug:程序员犯错引起的程序功能错误; 逻辑错误:由于程序员对问题以及解决方案的误解所引起的; 异常:由于不常见但可预见的问题(如内存不足或磁盘空间耗尽)引起的。,-60-,处理意外情况,通过设计审核和详尽测试来发现逻辑错误。 我们无法消除异常,只能为各种可能的异常情况提前做好准备(如内存不足、磁盘空间不足)。 出现异常时有以下的处理方式 崩溃 通知用户并妥

31、善退出 通知用户,让用户尝试恢复并继续执行 采取措施,在不影响用户的情况下继续运行,很难做到从所有异常情况下恢复正常,但最起码不能让 程序直接崩溃。,-61-,什么是异常,异常是一段代码遇到异常状态后,通知另一段代码(异常处理代码)并进行处置的机制。 遇到错误的代码抛出(throw)异常 处理异常的代码捕获(catch)异常 异常的处理流程不遵守常规的代码执行流程,代码抛出异常后,立即停止执行,跳转到异常处理处。,异常处理的基本思想,异常处理的实现机制,抛掷异常的程序段 . throw 表达式; .,捕获并处理异常的程序段 try 复合语句 catch(异常类型声明) 复合语句 catch(异

32、常类型声明) 复合语句 ,异常处理的实现机制,若有异常则通过throw操作创建一个异常对象并抛掷。 将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。 如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。 catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。 如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序。,例12-1处理除零异常,#incl

33、ude int Div(int x,int y); void main() try cout5/2=Div(5,2)endl; cout8/0=Div(8,0)endl; cout7/1=Div(7,1)endl; catch(int) coutexcept of deviding zero.n; coutthat is ok.n; int Div(int x,int y) if(y=0) throw y; return x/y; ,程序运行结果如下: 5/2=2 except of deviding zero. that is ok.,异常接口声明,可以在函数的声明中列出这个函数可能抛掷的所

34、有异常类型。 例如:void fun() throw(A,B,C,D); 若无异常接口声明,则此函数可以抛掷任何类型的异常。 不抛掷任何类型异常的函数声明如下: void fun() throw();,异常处理中的构造与析构,找到一个匹配的catch异常处理后: 初始化参数。 将从对应的try块开始到异常被抛掷处之间构造(且尚未析构)的,所有自动对象进行析构。 从最后一个catch处理之后开始恢复执行。,例12-2 异常处理时的析构,#include void MyFunc( void ); class Expt public: Expt(); Expt(); const char *Show

35、Reason() const return Expt类异常。; ;,class Demo public: Demo(); Demo(); ; Demo:Demo() cout构造 Demo.endl; Demo:Demo() cout析构 Demo.endl; ,void MyFunc() Demo D; cout在MyFunc()中抛掷Expt类异常。endl; throw Expt(); int main() cout在main函数中。endl; try cout在try块中,调用MyFunc()。 endl; MyFunc(); ,catch( Expt E ) cout在catch异常

36、处理程序中。endl; cout捕获到Expt类型异常:; coutE.ShowReason()endl; catch( char *str ) cout捕获到其它的异常:strendl; cout回到main函数。从这里恢复执行。 endl; return 0; ,程序运行时输出: 在main函数中。 在try块中,调用MyFunc()。 构造 Demo. 在MyFunc()中抛掷Expt类异常。 析构 Demo. 在catch异常处理程序中。 捕获到Expt类型异常:Expt类异常。 回到main函数。从这里恢复执行。,-73-,处理异常,#include int main() try s

37、td:coutdivide(5,2)std:endl; std:coutdivide(8,0)std:endl; std:coutdivide(7,1)std:endl; catch( double ) std:coutexcept of deviding zero.n; std:coutthat is ok.n; return 0; ,divide函数中抛出double类型异常, 直接跳转到catch处理块。,-74-,定义异常类,class XBoundary public: XBoundary() XBoundary() private: ;,在代码中遇到异常状态时,可以抛出自定义的 异

38、常类对象,通常会在异常类中保存异常信息, 示例中做了简化。,class Array public: Array( int newSize ); Array( int *p, int size ); Array(); Array( const Array,-76-,抛出异常类对象,int ,在代码中遇到异常状态(非法的索引下标), 构造并抛出异常对象(XBoundary对象)。 抛出的异常将匹配到类型为XBoundary的 catch块。,-77-,处理异常,#include int main() Array intArray(20); try for(int i=0; i100; +i) in

39、tArrayi=i; std:cout“OKn”; catch( XBoundary) std:cout“Unable to process your input.n; std:cout“Done.n; return 0; ,下标为20时,超过可访问范围,抛出 XBoundary对象,匹配到catch处理 块,catch块执行完成继续执行后面 的代码。,异常传参及多态处理,抛出的异常可以是类的对象,为了有效处理异常,常见的做法是定义异常类的层次结构。 在catch块中,可以定义异常对象形参,形参匹配并接收所抛出的异常对象(类似函数传参)。通过传递引用,配合定义的异常类体系,可以多态地处理异常。

40、,-78-,-79-,1、识别Array类可能的异常,class Array public: Array(int newSize); Array(int *p,int size); Array(); Array(const Array,数组大小设置太大 数组大小设置太小 数组大小为0 数组大小为负数 索引下标非法 ,-80-,2、定义异常类体系,class XBoundary ; class XSize public: XSize(int newSize):size(newSize) XSize() virtual int getSize() return size; virtual void

41、 printError() std:cout Size error. Received: size n; protected: int size; ;,XBoundary处理下标越界的异常。 XSize是分配数组大小非法异常的基类,定义 getSize和printError虚函数。,-81-,定义异常类体系,class XTooBig : public XSize public: XTooBig(int size) : XSize(size) virtual void printError() std:cout Too big! Received: ; std:cout XSize:size

42、n; ;,XTooBig是XSize的子类,重写了基类的虚函数printError, 以显式不同的错误信息。 XSize:size访问基类的数据成员size。,-82-,定义异常类体系,class XTooSmall : public XSize public: XTooSmall(int size):XSize(size) virtual void printError() std:cout Too small! Received: ; std:cout XSize:size n; ;,XTooSmall是XSize的子类,重写基类的虚函数printError, 以显式不同的错误信息。,-8

43、3-,定义异常类体系,class XZero : public XTooSmall public: XZero(int newSize) : XTooSmall(newSize) virtual void printError() std:cout Zero Received: ; std:cout XSize:size n; ;,XZero是XTooSmall的子类,重写基类的虚函数printError, 以显式不同的错误信息。 构造XZero类对象时,先调用XSize类的构造函数,再调用 XTooSmall构造函数,最后调用XZero的构造函数。,-84-,定义异常类体系,class XNegative : public XSize public: XNegative(int size):XSize(size) virtual void printError() std:cout Negative! Received: ; std:cout XSize:size n; ;,XNegative是XSize的子类,重写基类的虚函数printError, 以显式不同的错误信息。,-85-,3、为数组类抛出异常,void Array:copyData(int *p, int newSize) size = newSize

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论