C++面向对象程序设计 - 文件操作与文件流

        在实际应用中,常以磁盘文件作为对象,即能从磁盘文件读取数据,也能将数据输出到磁盘文件,磁盘是计算机的外部存储器,能够长期保留信息,能读能写,可以刷新重写等等。

        在C++中,文件操作通常通过文件流(file streams)来完成,这是<fstream>库提供的功能。fstream库中的三个主要类用于文件操作:ifstream(用于输入文件),ofstream(用于输出文件)和fstream(用于双向文件操作)。

一、文件的概念

        常用的文件有两大类:一类是程序文件(program file),如C++的源程序文件(.cpp)、目标文件(.obj)、可执行文件(.exe)等。一类是数据文件(data fle)在程序运行时,常常需要将一些数据输出到磁盘上存放起来,后期需要时再从磁盘中输入到计算内存,这种磁盘文件就是数据文件。

        文件数据的组织形式,可分为ASCII文件和二进制文件。ASCII文件又称文本(text)文件或字符文件,它的每一个字节放一个ASCII码,代表一个字符。二进制文件又称为内部格式文件或字节文件,是把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放。

        C++提供了低的I/O功能和高级I/O功能。高级的I/O功能是把若干个字节组合为一个有意义的单位(如整数、单精度数、双精度数、字符串或用户自定义的类型的数据),然后以ASCII码字符形式输入和输出(但在传输大容量的文件时由于数据格式转换,速度较慢,效率不高)。低级的I/O功能是以字节为单位输入和输出的,在输入和输出时不进行数据格式的转换,以二进制形式进行的(这种输入输出速度快、效率高、但会感到不方便)。

二、文件流类与文件流对象

        文件流是以外存文件为输入输出对象的数据流,输出文件流是从内存流向外存文件的数据,输入文件是从外存文件流向内存的数据,每一个文件流都有一个内存缓冲区与之对应。

        标准输入输出流istream、ostream和iostream类外,还有3个用于文件操作的文件类:

  1. ifstream类,它是从istream类派生的,用来支持从磁盘文件的输入。
  2. ofstream类,它是从ostream类派生的,用来支持从磁盘文件的输出。
  3. fstream类,它是从iostream类派生的,用来支持从磁盘文件的输入输出。

三、文件的打开与关闭

        对磁盘文件的操作是通过文件流对象(面不是cin和cout)实现的,文件流对象是用文件流类定义的,而不是用istream和ostream类来定义。例如建立一个输出文件流对象:

ofstream outfile;

3.1 打开磁盘

        所谓打开文件是一种形象的说法,打开文件是指在文件读写之前做的必须准备,如:

  1. 为文件流对象和指定的磁盘文件建立关联,以便使文件流流向指定的磁盘文件。
  2. 指定文件的工作方式,如该文件是作为输入文件还是输出文件,是ASCiI文件还是二进制文件等。

        打开文件可以两种形式,具体如下:

1)调用成员函数open形式

文件流对象.open(磁盘文件名, 输入输出方式);

        示例如下:

ofstream outfile;
outfile.open("file.txt", ios::out);

        磁盘文件名可以包括路径,如“c:\new\file.txt”,如缺省路径,则默认为当前目录下的文件。

2)在定义文件流对象时指定参数

        在声明文件流类时定义了带参数的构造函数,其中包括了打开磁盘文件的功能。示例如下:

ofstream outfile("file.txt", out;:out);

        输入输出方式是在ios类中定义的,它们是枚举常量,有多种选择,具体如下表:

方式作用
ios::in以输入方式打开文件
ios::out以输出方式打开文件(这是默认方式),如果已有此名字的文件,则将其原有内容全部清除
ios::app以输出方式打开文件,写入的数据添加在文件末尾
ios::ate打开一个已有的文件,文件指针指向文件末尾
ios::trunc打开一个文件,如果文件已存在,则删除其中全部数据,如文件不存在,则建立新文件。如已指定了ios::out方式,而末指定ios::app、ios::ate、ios::in,则同样默认此方式。
ios::binary以二进制方式打开一个文件,如不指定此方式则默认为ASCII方式
ios::nocreate打开一个已有的文件,如文件不存在,则打开失败。nocreate的意思是不建立新文件
ios::noreplace如文件不存在则建立新文件,如果文件已存在则操作失败,noreplace的意思是不更新原有文件
ios::int|ios::out以输入和输出方式打开文件,文件可读可写
ios::out|ios::binary以二进制方式打开一个输出文件
ios::in|ios::binary以二进制方式打开一个输入文件

        注意:

  1. 新版本 C++系统I/O类库中不提供ios::nocreate和ios::noreplace。
  2. 每一个打开的文件都有一个文件指针,该指针的初始位置由I/O方式指定,每次读写都从文件指针的当前位置开始。每读入一个字节,指针就后移一个字节。当文件指针移到最后,就会遇到文件结束EOF(文件结束符也占一个字节,其值为-1)此时流对像的成员函数eof的值为非0值(一般设为1),表示文件结束。
  3. 要以用“位或”运算符“|”对输入输出方式进行组合。

        示例:

#include <iostream>
#include <fstream>
using namespace std;
int main(){ofstream outfile;outfile.open("file.txt", ios::app);if(!outfile.is_open()){clog <<"Open Error" <<endl;}return 0;
}

        运行如上代码,如file.txt文件不存在,则会输出"Open Error"错误信息,并创建file.txt文件。

3.2 关闭磁盘文件

        在对打开的磁盘文件的读写操作完成后,应关闭该文件。将3.1中代码修改后如下:

#include <iostream>
#include <fstream>
using namespace std;
int main(){ofstream outfile;outfile.open("file.txt", ios::app);if(!outfile.is_open()){clog <<"Open Error" <<endl;}outfile.close();		//关闭流return 0;
}

        所谓的关闭,实际上是解除磁盘文件与文件流的关联,原来设置的工作方式也失效,就不能再通过文件流对该文件进行输入或输出。

四、对ASCII文件的操作

        文件的每一个字节中均以ASCII代码形式存放数据,即一个字节存放一个字符,这个文件就是ASCII文件(或称字符文件)。

        对于ASCII文件的读写操作有以下两种方式:

  1. 用流插入运算符"<<"和流提取运算符">>"输入输出标准类型的数据。
  2. 用文件流put, get, getline等成员函数进行字符的输入输出。

4.1 打开文件并输出数据

        下面将一个整形数组,含10个元素,从键盘输入10个整数给数组,将此数组存放到磁盘文件file2.txt中。代码如下:

#include <iostream>
#include <fstream>
using namespace std;
int main(){int a[10];ofstream outfile("file2.txt", ios::out);			//定义文件流对象,打开磁盘文件"file2.txt"if(!outfile){cerr <<"open errror!" <<endl;exit(1);}cout <<"enter 10 integer numbers:" <<endl;for(int i = 0; i < 10; i++){cin >>a[i];outfile <<a[i] <<" ";		// 向磁盘文件 file2.txt 输出数据}outfile.close();				//关闭磁盘文件"file2.txt"return 0;
}

        运行结果如下图:

        说明:

  1. 程序中ofstream类定义文件流对象outfile,调用结构函数打开磁盘文件,并向文件中写入数据。另外参数ios::out可以省略,因为输出默认为ios::out。
  2. 如果打开成功,则文件流对象outfile的返回值为非0值,如果打开失败,则返回 值为0(假),加上"!“号非则为真。所以”!outfile“为真,则显示信息并执行exit退出。

4.2 打开文件并输入数据

        下在通过示例,从文件file3.txt文件中读取事前存储好的10个整数,通过输入流读取内容,并计算出其中最大值以及其对应数组索引址。

        file3.txt文件中下图:

        示例代码:

#include <iostream>
#include <fstream>
using namespace std;
int main(){int number[10];int max, index, temp;// 定义输入文件流对象ifstream infile("file3.txt", ios::in);// 如果输入失败,显示错误信息if(!infile){cerr <<"open eror~" <<endl;exit(1);}// 循环输入整数for(int i = 0; i < 10; i++){infile >>number[i];				//将读取整数按顺序存放在number数组中cout <<number[i] <<" ";			// 在控制台输出结果}cout <<endl <<endl;// 默认数组中第一个数组最大index = 0;// 默认先设置最大值为数组第一位元素max = number[index];// 循环判断最大值for(int i = 0; i < 10; i++){// 如果最大值小于当前元素值,则将其赋值给maxif(max < number[i]){index = i;max = number[i];}}// cout <<"max value:" <<max <<endl <<",index value:" <<index <<endl;// 关闭输入流infile.close();return 0;
}

        运行后结果如下图:

4.3 复制文件

        输出和输出数据前面已了解了,现在可以用已了解的知识,写一个复制文件功能。

        复制文件message.txt文本如下:

Desktop version: Privacy online features carefully protect you. Firefox automatically blocks more than 2,000 trackers from collecting records of your online behavior.
Mobile: No matter where you are, your privacy doesn't have to be compromised - your passwords, search history, open tabs, and other data are safe to take with you.
Enterprise Edition: Tailor product support cycles to your business needs for unparalleled data protection.

        示例代码如下:

#include <iostream>
#include <fstream>
using namespace std;
int main(){ifstream infile("message.txt");ofstream outfile("messageCopy.txt");// 判断是否打开成功if(!infile){cerr <<"Open message.txt Error";exit(1);}if(!outfile){cerr <<"Open messageCopy.txt Error";exit(1);}// 定义变量接收字符char ch;// 循环读取文件中字符while(infile.get(ch)){outfile.put(ch);cout <<ch;}cout <<endl;// 关闭流文件infile.close();outfile.close();return 0;
}

        运行后,本来只有message.txt文件的目录,则会多出一个messageCopy.txt文件,并且将message.txt文件中内容全部复制到messageCopy.txt新创建文件中。(注意:ofstream流对象在默认ios::out情况下,则也默认ios:trunc,当文件不存时创建它。这个在本章节”2)在定义文件流对象时指定参数“中,文件输入输出方式设置值表中有说明)。

4.4 复制内容转换为大写

        在4.3的按钮中,复制内容都是英文内容,而且txt文件中存为字符ASCII码。英文字母a~z小写字符对应范围是97~122,大写字母范围则是65~90,所以a与A之间相关为32。

        在了解此规律后,再把上述示例修改一下,将所有复制内容转换为大写后,再复制到新文件中。示例代码如下:

#include <iostream>
#include <fstream>
using namespace std;
int main(){ifstream infile("message.txt");ofstream outfile("messageUpper.txt");// 判断是否打开成功if(!infile){cerr <<"Open message.txt Error";exit(1);}if(!outfile){cerr <<"Open messageCopy.txt Error";exit(1);}// 定义变量接收字符char ch;// 循环读取文件中字符while(infile.get(ch)){// 如果发现字母ASCII码值在97~122,则为小写字母,减32将其转换为大写if(ch >= 97 && ch <= 122) ch -= 32;outfile.put(ch);cout <<ch;}cout <<endl;// 关闭流文件infile.close();outfile.close();return 0;
}

        运行后结果如下:

        此时目录中也会多出messateUpper.txt文件,其中内容已全部转换为大写。

五、对二进制文件的操作

        二进制文件不是以ASCII码存放数据的它将内存中的数据存储形式不加转换地传送到磁盘文件,因此它又称作为内存数据的映像文件。因为文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为字节文件。

5.1 用成员函数read和write读写二进制文件

        对二进制文件的读写主要用istream类的成员函数read和write来实现。这两个函数的原型为:

istream& read(char *buffer, int len);

ostream& write(const char *buffer, int len);

5.1.1 通过二进制形式存储数据

        在程序中定义一个Student类对象,再定义数组存储三个Student对象数据,然后使用流对象将数组信息通过二进制形式存储起来。示例代码如下:

#include <iostream>
#include <fstream>
using namespace std;// 定义学生类
class Student{private:string name;int num;int age;public:Student(const char* nameStr = "None", int num = 0, int age = 0): num(num), age(age){// 使用strncpy来避免缓冲区溢出(注意这里要确保不会超过30个字符)  // 如果nameStr可能超过29个字符(需要留一个位置给'\0'),则需要额外的长度检查  strncpy(name, nameStr, sizeof(name) - 1); // 复制nameStr到name,并确保最后一个字符是'\0'  name[sizeof(name) - 1] = '\0'; // 确保字符串是null终止的}
};int main(){//定义学生类对象并初始化数据Student list[] = {Student("Tom", 1, 18),Student("Lily", 2, 19),Student("John", 3, 20)};// 创建输入流ofstream outfile("student.data", ios::binary);if(!outfile){cerr <<"Open file Error" <<endl;exit(1);}// 循环输出学生数据for(int i = 0; i < 3; i++){outfile.write((char*)&list[i], sizeof(list[i]));}// 关闭流对象outfile.close();return 0;
}

        运行后,目录中则会出现student.data文件,使用文本打开发现内容是一堆乱码,这侧是通过二进制保存的数据。如下图:

        上述代码中,&list[i]是结构体数组的一个元素首地址,但这个指向结构体的指针,与形参类型不匹配,因此要用(char *)把它强制转换为字符指针。第二个sizeof(list[i])的值是结构体数组的一个元素的字节数据,sizeof也在之前章节中应用过,并通过它获取过数组的长度,想必大家也并不陌生。

5.1.2 通过二进制读取数据

        能通过二进制存储数据,也可以通过二制制将数据读取回来。现在就将5.1.1中生成的student.data数据读取到内存中,示例代码如下:

#include <iostream>
#include <fstream>
using namespace std;// 定义学生类
class Student{private:char name[30];int num;int age;public:Student(const char* nameStr = "None", int num = 0, int age = 0): num(num), age(age){// 使用strncpy来避免缓冲区溢出(注意这里要确保不会超过30个字符)  // 如果nameStr可能超过29个字符(需要留一个位置给'\0'),则需要额外的长度检查  strncpy(name, nameStr, sizeof(name) - 1); // 复制nameStr到name,并确保最后一个字符是'\0'  name[sizeof(name) - 1] = '\0'; // 确保字符串是null终止的}string getName(){return name;}int getNum(){return num;}int getAge(){return age;}
};int main(){Student list[3];// 定义流对象,读取文件ifstream infile("student.data", ios::binary);// 判断是否打开成功if(!infile){cerr <<"Open file error" <<endl;}for(int i = 0; i < 3; i++){infile.read((char *)&list[i], sizeof(list[i]));}// 关闭流文件infile.close();// 输出数据for(int m = 0; m < 3; m++){cout <<"name:" <<list[m].getName() <<endl;cout <<"num:" <<list[m].getNum() <<endl;cout <<"age:" <<list[m].getAge() <<endl <<endl;}return 0;
}

        运行后结果如下图:

5.2 与文件指针有关的流成员函数

        在磁盘文件中有一个文件指针,用来指明当前应进行读写的位置。在输入时每读入一个字节,指针就向后移动一个字节。在输出时每向文件输出一个字节,指针就向后移动一个字节,随着输出文件中字节不断增加,指针不断后移。对于二进制文件,允许对指针进行控制,使它按用户的效果图移动到所需的位置,以便在该位置上进行读写。

        文件流提供了一些有关文件指针的成员函数,具体如下表:

成员函数作用
gcount()返回最后一次输入所读入的字节数
tellg()返回输入文件指针的当前位置
seekg(文件中的位置)将输入文件中指针移到指定的位置
seekg(位移量, 参照位置)以参照位置为基础移动若干字节(“参照位置”的用法见说明)
tellp()返回输出文件指针当前的位置
seekp(文件中的位置)将输出文件中指针移到指定的位置
seekp(位移量, 参照位置)以参照位置为基础移动若干字节

        注意:上述函数名中带的"g"或"p",其实g是get的首字母,p是put的首字母。所以带有get的则是用于输入文件,带有put则是用于输出文件。

        参照位置如下表:

名称描述
ios::beg文件开头(beg是begin的缩写),这是默认值
ios::cur指针当前的位置(cur是current的缩写)
ios::end文件末尾

        它们是在ios类中定义的枚举常量。它们使用方法,如下示例:

infile.seekg(100);                //输入文件中的指针向前移到100字节位置
infile.seegg(-50, ios::cur);      //输入文件中的指针从当前位置后移50字节
outfile.seekp(-75, ios::end);     //输出文件中的指针从文件尾后移50字节

5.3 随机访问二进制数据文件

        一般情况下读写是顺序进行的,即逐个字节进行读写。但是对于二进制数据文件来说,可以利用上的成员函数移动指针,随机地访问文件中任一位置上的数据,还可以修改文件中的内容。

5.3.1 reinterpret_cast

        语法形式:

reinterpret_cast<type-id> (expression)

        type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。

        该运算符的用法比较多。操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。例如:

int *n= new int ;
double *d=reinterpret_cast<double*> (n);

        在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析。

5.3.2 static_cast

        static_cast是一个c++运算符,功能是把一个表达式转换为某种类型,但没有运行时类型检查来保证转换的安全性。

        语法形式:

static_cast <type-id>( expression )

        static_cast和reinterpret_cast的区别主要在于多重继承,例如:

#include <cstdio>
class A {public:int m_a;
};class B {public:int m_b;
};
class C : public A, public B {};
//那么对于以下代码:
int main(){C c;printf("%p,\n%p, \n%p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));return 0;
}

        运行结果如下图:

        前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。

        编译器隐式执行任何类型转换都可由static_cast显示完成;reinterpret_cast通常为操作数的位模式提供较低层的重新解释。

5.3.3 示例

        将5.1.1和5.1.2中示例代码稍作修改,将数据添加至5条,修改第三条数据的内容,再将其保存到文件中。代码如下:

#include <iostream>  
#include <fstream>  
#include <cstring>  using namespace std;  class Student {  
private:  char name[50];  int id;  int age;  public:  Student(){}// 构造函数,假设name不会超过49个字符(需要为'\0'留出空间)  Student(const char* nameStr, int id, int age) {  strncpy(name, nameStr, sizeof(name) - 1);  name[sizeof(name) - 1] = '\0';  this->id = id;  this->age = age;  }  void setId(int id){this->id = id;}void setAge(int age){this->age = age;}// 打印函数  void print() const {  cout << "Name: " << name << ", ID: " << id << ", Age: " << age << endl;  }   
};  int main() {  // 定义学生数组并初始化数据  Student students[5] = {  Student("Tom", 1, 18),  Student("Lily", 2, 19),  Student("John", 3, 20),  Student("LiuLei", 4, 18),  Student("LiMei", 5, 17)  };  string filename = "stu.data";// 写入文件  fstream file(filename, ios::out | ios::binary | ios::trunc);  if (!file) {  cerr << "Open file error for writing." << endl;  return 1; // 退出程序  }  for (const auto& student : students) {  file.write(reinterpret_cast<const char*>(&student), sizeof(student));  }  file.close();  // 读取文件并打印学生信息  file.open(filename, ios::in | ios::binary);  if (!file) {  cerr << "Open file error for reading." << endl;  return 1; // 退出程序  }  Student tempStudent; for (int i = 0; i < 5; i++) {  file.read(reinterpret_cast<char*>(&tempStudent), sizeof(tempStudent));  tempStudent.print();  }  file.close();  // 修改第三个学生的信息  students[2].setId(303);  students[2].setAge(21);  // 重新打开文件以进行写入  file.open(filename, ios::in | ios::out | ios::binary);  if (!file) {  cerr << "Open file error for updating." << endl;  return 1; // 退出程序  }  // 定位到第三个学生的开始位置  file.seekg(2 * sizeof(students[2]), ios::beg); // 跳过前两个学生信息  if (file) {  // 写入第三个学生的新信息  file.write(reinterpret_cast<const char*>(&students[2]), sizeof(students[2]));  } else {  cerr << "Seek error." << endl;  }  file.close();  cout << "Student information has been updated and saved to the file." << endl;  // 再次读取文件并显示所有学生的信息  file.open(filename, ios::in | ios::binary);  if (!file) {  cerr << "Open file error for reading again." << endl;  return 1; // 退出程序  }  cout << "Updated student information:" << endl;  for (int i = 0; i < 5; i++) {  Student tempStudent;  file.read(reinterpret_cast<char*>(&tempStudent), sizeof(tempStudent));  tempStudent.print();  }  file.close(); return 0;  
}

        运行后结果如下图:

      

注意几点:

  1. 我们使用了fstream而不是分别使用ofstream和ifstream,因为我们要在同一个文件中进行读写操作。
  2. 使用seekg来定位到文件中第三个Student对象的开始位置。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

106.网络游戏逆向分析与漏洞攻防-装备系统数据分析-在UI中显示装备与技能信息

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

新媒体暴力起号必备因素!沈阳新媒体运营培训学校

1周涨粉10w&#xff1f;这对普通人来说可以说是天文数字&#xff0c;但只要掌握方式方法&#xff0c;普通人也能做到&#xff01; 面试经验丰富的人都深知&#xff0c;给面试官留下的第一印象相当重要&#xff0c;几乎决定了80%的面试机会。标题也是如此&#xff0c;在完成一篇…

[经验] 蝉联一词的含义是什么 #知识分享#职场发展

蝉联一词的含义是什么 蝉联这个词起源于古代中国&#xff0c;最初是指天子连续两年以上的年号相同。后来&#xff0c;这个词被用于形容某个人或某个团体连续多次获得某种荣誉或奖项的情况。在现代生活中&#xff0c;我们常常听到某个体育运动员蝉联冠军、某个企业蝉联业绩排行榜…

基于拓扑漏洞分析的网络安全态势感知模型

漏洞态势分析是指通过获取网络系统中的漏洞信息、拓扑信息、攻击信息等&#xff0c;分析网络资产可能遭受的安全威胁以及预测攻击者利用漏洞可能发动的攻击&#xff0c;构建拓扑漏洞图&#xff0c;展示网络中可能存在的薄弱环节&#xff0c;以此来评估网络安全状态。 在网络安…

科普|大数据风险检测对申贷人有哪些好处?

大数据风险检测可以极大地提高金融机构在用户肖像、反欺诈和信用评级等方面的效率和风险控制能力&#xff0c;这是金融企业发展过程中必须结合的一种科技技术。大数据风险检测覆盖信贷领域的所有流程&#xff0c;从客户获取到身份验证&#xff0c;再到信贷中和信贷后。因此&…

电赛报告书写

一、总体要求 &#xff08;1&#xff09;摘要&#xff1a;一页&#xff0c;小于300字 &#xff08;2&#xff09;正文&#xff1a;不超过8页 &#xff08;3&#xff09;附录&#xff1a;可以没有&#xff0c;但是不能超过2页 二、摘要书写 摘要要小于等于300字&#xff0c…

实现飞书机器人推送消息到指定群组或者用户

实现飞书机器人推送消息到指定群组或者用户 1 简介2 创建飞书应用2.1 注册登录2.2 创建应用2.3 添加应用能力2.4 权限管理3 发布应用4 代码示例4.1 获取应用ID与token4.2 使用Python SDK4.3 简单示例4.4 获取用户或机器人所在的群列表4.5 通过手机号或邮箱获取用户 ID4.6 给群组…

生活使用英语口语柯桥外语学校成人英语学习

● “自来水”英语怎么说&#xff1f; ● “自来水”的英语表达是&#xff1a;Running water或者Tap water. 例句&#xff1a; There are hot and cold running water in all the bedrooms. 所有的卧室里都有冷热自来水。 ● “热水”英文怎么水&#xff1f; ● 我们不管…

C++设计模式——Adapter适配器模式

一&#xff0c;适配器模式简介 适配器模式是一种结构型设计模式&#xff0c;用于将已有接口转换为调用者所期望的另一种接口。 适配器模式让特定的API接口可以适配多种场景。例如&#xff0c;现有一个名为"Reader()"的API接口只能解析txt格式的文件&#xff0c;给这…

【css3】png图片实现动态动画

.border_style {width: 400px;height: 400px;background-color: black;margin: auto;}keyframes sprite-animation {0% {background-position: 0 0;}100% {background-position: 0 -2064px;/* 假设每个图像的宽度为100px */}}.wrj_box {width: 86px;height: 86px;background-im…

STL中stack和queue模拟实现+容器适配器

目录 容器适配器 STL标准库中stack和queue的底层结构 deque的简单介绍 deque的缺陷 为什么选择deque作为stack和queue的底层默认容器 stack的模拟实现 queue的模拟实现 容器适配器 适配器是一种设计模式&#xff08;设计模式是一套被反复使用的&#xff0c;多数人知晓…

OpenAI模型规范概览

这是OpenAI对外分享的模型规范文档&#xff08;Model Spec&#xff09;&#xff0c;它定义了OpenAI希望在API接口和ChatGPT&#xff08;含GPT系列产品&#xff09;中模型的行为方式&#xff0c;这也是OpenAI超级对齐团队奉行的行为准则&#xff0c;希望能对国内做RLHF的同学有帮…

阿里云对象存储OSS简单使用

文章目录 概念基本概念Bucket 准备工作控制台操作对象存储OSSJava客户端操作对象存储OSS参考来源 概念 基本概念 阿里云对象存储 OSS是一款海量、安全、低成本、高可靠的云存储服务&#xff0c;提供最高可达 99.995 % 的服务可用性。而且提供了多种存储类型&#xff0c;降低我…

SemiDrive X9H 平台 QT 静态编译

一、 前言 芯驰 X9H 芯片&#xff0c;搭载多个操作系统协同运行&#xff0c;系统实现了仪表、空调、中控、副驾多媒体的四屏驱动控制&#xff0c;在人车智能交互上可以通过显示屏、屏幕触摸控制、语音控制、物理按键控制、车身协议的完美融合&#xff0c;使汽车更智能。让车主…

算法:94. 二叉树的中序遍历

给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root [1] 输出&am…

静态IP代理服务对比:哪些提供商值得信赖?静态ip代理哪家好用?

当涉及选择静态IP代理时&#xff0c;许多人可能会感到困惑&#xff0c;因为市场上存在着各种各样的选项。本文旨在为您提供一些关键指导&#xff0c;帮助您确定哪种静态IP代理是最适合您需求的。在这个过程中&#xff0c;我们将介绍一个备受推崇的解决方案——太阳HTTP。 1.高速…

拥抱生态农业,享受绿色生活

随着人们对健康生活的追求日益增强&#xff0c;生态农业逐渐成为人们关注的焦点。我们深知生态农业对于保护生态环境、提高农产品品质的重要性&#xff0c;因此&#xff0c;我们积极推广生态农业理念&#xff0c;让更多的人了解并参与到生态农业的实践中来。 生态农业的蓝总说&…

ADASIS V2 协议-1

ADAS V2协议-1 1 简介2 版本控制3 ADASIS v23.1 ADASIS v2 Horizon &#xff08;地平线&#xff09;3.2 ADASIS v2的构建3.3 ADASIS v2 Horizon Provider &#xff08;ADAS V2地平线提供者&#xff09;3.4 paths and offsets &#xff08;路径和偏移量&#xff09;3.5 Path Pro…

YOLOv8---seg实例分割(制作数据集,训练模型,预测结果)

YOLOv8----seg实例分割&#xff08;制作数据集&#xff0c;训练模型&#xff0c;预测结果&#xff09; 内容如下&#xff1a;【需要软件及工具&#xff1a;pycharm、labelme、anaconda、云主机&#xff08;跑训练&#xff09;】 1.制作自己的数据集 2.在yolo的预训练模型的基础…

Prompt 提示词强大方法论和框架2

自从ChatGPT Chat Generative Pre-trained Transformer于2022年11月30日发布以来&#xff0c;一个新兴的行业突然兴起&#xff0c; 那就是提示工程Prompt engineering&#xff0c;可谓如日冲天。 从简单的文章扩写到RAG&#xff0c;ChatGPT展现了前所未有的惊人能力。 在上一…