C++标准模板库编程实战 第九章 流操作

目录

9.1 流迭代器


9.1 流迭代器

9.1.1 输入流迭代器

不能处理二进制流。

istream_iterator生成输入流迭代器:默认构造函数会生成一个代表流结束的对象--当EOF被识别时的那种对象。

std::istream_iterator<string> in {std::cin}; // Reads strings from cin
std::istream_iterator<string> end_in; // End-of-stream iterator

默认情况下这种流被认为包含char类型。也能够定义输入流迭代器来读取包含其他类型字符的流。

std::basic_ifstream<wchar_t> file_in {"no_such_file.txt"}; // File stream of wchar_t
std::istream_iterator<std::wstring, wchar_t> in {file_in}; // Reads strings of wchar_t
std::istream_iterator<std::wstring, wchar_t> end_in; // End-of-stream iterator

第二个语句定义了一个流迭代器,第一个模板参数必须是wstring,流中的字符类型由第二个模板参数指定的,这里是wchar_t。

istream_iterator有以下成员函数:

1.operator*()返回流中当前对象的引用,可以用这个运算符多次重读相同的值。

2.operator->()返回流中当前对象的地址。

3.operator++()从底层流中读取一个值保存到一个迭代器对象中,返回迭代器对象的引用。

4.operator++(int)从底层流中读取一个值保存到一个迭代器对象中,为operator*()和operator->()做准备。

一。迭代器和流迭代器

常规迭代器指向的是数组或容器中的元素,递增一个常规迭代器会改变它所指向的元素,但对指向同一个序列的其他迭代器没有影响。

而如果生成两个指向同一个流的输入流迭代器,当从标准输入流读取时,输入流迭代器不仅会改变它所指向的元素---在引用时得到的结果---也会改变从底层流中下一次读取操作的位置。

这意味着两个输入流迭代器所确定的序列只能由开始迭代器和流的结束迭代器组成。

二。用输入流的成员函数读取数据
std::cout << "Enter one or more words. Enter ! to end:\n";
std::istream_iterator<string> in {std::cin}; // Reads strings from cin
std::vector<string> words;
while(true)
{
 string word = *in;
 if(word == "!") break;
 words.push_back(word);
 ++in;
}
std::cout << "You entered " << words.size() << " words." << std::endl;

读取数值数据(一般不这么用):

 std::cout << "Enter some integers - enter Ctrl+Z to end.\n";
 std::istream_iterator<int> iter {std::cin}; // Create begin input stream iterator...
 std::istream_iterator<int> copy_iter {iter}; // ...and a copy
 std::istream_iterator<int> end_iter; // Create end input stream iterator
 // Read some integers to sum
 int sum {};
 while(iter != end_iter) // Continue until Ctrl+Z read
 {
 sum += *iter++;
 }
 std::cout << "Total is " << sum << std::endl;
 std::cin.clear(); // Clear EOF state
 std::cin.ignore(); // Skip characters
 // Read integers using the copy of the iterator
 std::cout << "Enter some more integers - enter Ctrl+Z to end.\n";
 int product {1};
 while(true)
 {
 if(copy_iter == end_iter) break; // Break if Ctrl+Z was read
 product *= *copy_iter++;
 }
 std::cout << "product is " << product << std::endl;

可以这样计算sum:

std::cout << "Total is " << std::accumulate(iter, end_iter, 0) << std::endl;

向vector中插入数据:

std::vector<double> data;
std::cout << "Enter some numerical values - enter Ctrl+Z to end.\n";
std::copy(std::istream_iterator<double>{std::cin}, std::istream_iterator<double>{},
 std::back_inserter(data));

也可以用流迭代器给vector初始化:

std::cout << "Enter some numerical values - enter Ctrl+Z to end.\n";
std::vector<double> data {std::istream_iterator<double>{std::cin}, 
std::istream_iterator<double>{}};
9.1.2 输出流迭代器:

ostream_iterator类定义了以下成员函数:

构造函数:第一个参数是ostream对象,第二个参数是间隔符,可以忽略第二个参数。

operator=(const T& obj)将obj写到流中,然后写分隔符(如果构造函数指定了的话)。返回一个迭代器的引用。

operator*()operator++()operator++(int)不做任何事,除了返回迭代器对象。为了将迭代器限定为输出迭代器,这个操作必须被定义。

三种方式写到标准输出流中:

std::vector<string> words {"The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog"};
 // Write the words container using conventional iterator notation
 std::ostream_iterator<string> out_iter1 {std::cout}; // Iterator with no delimiter output
 for(const auto& word : words)
 {
 *out_iter1++ = word; // Write a word
 *out_iter1++ = " "; // Write a delimiter
 }
 *out_iter1++ = "\n"; // Write newline
 // Write the words container again using the iterator
 for(const auto& word : words)
 {
 (out_iter1 = word) = " "; // Write the word and delimiter
 }
 out_iter1 = "\n"; // Write newline
 // Write the words container using copy()
 std::ostream_iterator<string> out_iter2 {std::cout, " "};
 std::copy(std::begin(words), std::end(words), out_iter2);
 out_iter2 = "\n";

因为operator*()不做任何事,所以可以去掉。

9.2 重载插入和提取运算符

class Name
{
private:
 std::string first_name{};
 std::string second_name{};
public:
 Name() = default;
 Name(const std::string& first, const std::string& second) : 
 first_name{first}, second_name {second} {}
 friend std::istream& operator>>(std::istream& in, Name& name);
 friend std::ostream& operator<<(std::ostream& out, const Name& name);
};
// Extraction operator for Name objects
inline std::istream& operator>>(std::istream& in, Name& name)
{ return in >> name.first_name >> name.second_name; }
// Insertion operator for Name objects
inline std::ostream& operator<<(std::ostream& out, const Name& name)
{ return out << name.first_name << ' ' << name.second_name; }

9.3 对文件使用流迭代器

流迭代器不知道底层流的特性。可以以文本模式来读写任何类型的流。

9.3.1 文件流

可以以文本模式或二进制模式将数据转移到文件中或从文件中读出来。

文本模式下,至少对于输入来说,数据项必须由一个或多个空格隔开。

二进制模式下,内存和流是以字节的形式传送数据的,不需要转换。但流迭代器只能工作在文本模式下,因此不能用流迭代器读写二进制文件。流缓冲迭代器可以读写二进制文件。

当在小端字节序的系统中读取来自大端字节序的系统中的二进制文件时,需要考虑字节序的差别。

9.3.2 文件流类的模板

ifstream, ofstream, fstream

使用定义在ios_base类中的常量组合指定他们的打开状态:

1.binary:将文件设置为二进制模式。默认模式是文本模式。

2.app: 在每个写操作(append operation)之前会移到文件的末尾。

3.ate:会再打开文件之后(at the end),移到文件的末尾。

4.in: 打开文件来读,对于ifstream,fstream是默认的

5.on:打开文件来写,对于ostream,fstream是默认的

6.trunc:将当前存在的文件长度截断为0;

文本模式的操作会用》和《运算符来读写数据,数值数据被写到流之前会被转换为他们的字符表示。

二进制模式下,没有数据转换;内存中的字节会被直接写到文件中。

当指定一个不存在的文件名称作为ofstream的构造函数参数时,文件会被生成。

9.3.3 用流迭代器进行文件输入

一旦创建用于读取文件的文件流对象,用流迭代器来访问数据和从标准输入流读数据就基本相同。

 // Read words from the file into a set container
 string file_in {"G:/Beginning_STL/dictionary.txt"};
 std::ifstream in {file_in};
 if(!in)
 {
 std::cerr << file_in << " not open." << std::endl;
 exit(1);
 }
 std::set<string> dictionary {std::istream_iterator<string>(in), 
std::istream_iterator<string>()};
 std::cout << dictionary.size() << " words in dictionary." << std::endl;
 std::vector<string> words;
 string word;
 while(true)
 {
 std::cout << "\nEnter a word, or Ctrl+z to end: ";
 if((std::cin >> word).eof()) break;
 string word_copy {word};
 do
{
 if(dictionary.count(word))
 words.push_back(word);
 std::next_permutation(std::begin(word), std::end(word));
 } while(word != word_copy);
 std::copy(std::begin(words), std::end(words), std::ostream_iterator<string>{std::cout, " "});
 std::cout << std::endl;
 words.clear(); // Remove previous permutations
 }
 in.close(); // Close the file
9.3.4 用流迭代器来反复读文件

如果字典文件非常大,不想全部读到内存中,可以用流迭代器来重读文件(此时需要为文件流对象调用clear()来清楚EOF状态):

int main()
{
 string file_in {"G:/Beginning_STL/dictionary.txt"};
 std::ifstream in {file_in};
 if(!in)
 {
 std::cerr << file_in << " not open." << std::endl;
 exit(1);
 }
 auto end_iter = std::istream_iterator<string> {};
 std::vector<string> words;
 string word;
 while(true)
 {
 std::cout << "\nEnter a word, or Ctrl+z to end: ";
 if((std::cin >> word).eof()) break;
 string word_copy {word};
 do
 {
 in.seekg(0); // File position at beginning
 // Use find() algorithm to read the file to check for an anagram
 if(std::find(std::istream_iterator<string>(in), end_iter, word) != end_iter)
 words.push_back(word);
 else
 in.clear(); // Reset EOF
 std::next_permutation(std::begin(word), std::end(word));
 } while(word != word_copy);
 std::copy(std::begin(words), std::end(words), std::ostream_iterator<string>{std::cout, " "});
 std::cout << std::endl;
 words.clear(); // Remove previous permutations
 }
 in.close(); // Close the file
}
9.3.5 用流迭代器输出文件
int main()
{
 string file_in {"G:/Beginning_STL/dictionary.txt"};
 std::ifstream in {file_in};
 if(!in)
 {
 std::cerr << file_in << " not open." << std::endl;
 exit(1);
 }
 string file_out {"G:/Beginning_STL/dictionary_copy.txt"};
 std::ofstream out {file_out, std::ios_base::out | std::ios_base::trunc };
 std::copy(std::istream_iterator<string> {in}, std::istream_iterator<string> {},
 std::ostream_iterator<string> {out, " "});
 in.clear(); // Clear EOF
 std::cout << "Original file length: " << in.tellg() << std::endl;
 std::cout << "File copy length: " << out.tellp() << std::endl;
 in.close();
 out.close();
}

9.4 流迭代器和算法

如果算法需要正向、双向或随即迭代器来定义输入,就不能使用流迭代器。

1.使用count_if()算法确定dictionary.txt中出现和单词中由相同初始字母的频率:

int main()
{
 string file_in {"G:/Beginning_STL/dictionary.txt"};
 std::ifstream in {file_in};
 if(!in)
 {
 std::cerr << file_in << " not open." << std::endl;
 exit(1);
 }
 string letters {"abcdefghijklmnopqrstuvwxyz"};
 const size_t perline {9};
 for(auto ch : letters)
 {
 std::cout << ch << ": "
 << std::setw(5)
 << std::count_if(std::istream_iterator<string>{in}, std::istream_iterator<string>{},
 [&ch](const string& s)
 { return s[0] == ch; })
 << (((ch - 'a' + 1) % perline) ? " " : "\n");
 in.clear(); // Clear EOF...
 in.seekg(0); // ... and back to the beginning
 }
 std::cout << std::endl;
}

2.使用for_each()算法确定dictionary.txt中出现和单词中由相同初始字母的频率:

std::map <char, size_t> word_counts; // Stores word count for each initial letter
size_t perline {9}; // Outputs per line
// Get the words counts for each initial letter
std::for_each(std::istream_iterator<string>{in}, std::istream_iterator<string>{},
 [&word_counts](const string& s) {word_counts[s[0]]++;});
 std::for_each(std::begin(word_counts), std::end(word_counts), // Write out the counts
 [perline](const std::pair<char, size_t>& pr)
 { std::cout << pr.first << ": "
 << std::setw(5) << pr.second
 << (((pr.first - 'a' + 1) % perline) ? " " : "\n");
 });
 std::cout << std::endl;

3.generate_n()生成一些包含Fibonacci数列的文件:

值被写入后,调用seekg()设置文件读指针的位置--将文件设置会开始位置,并且准备读取文件。

int main()
{
 string file_name {"G:/Beginning_STL/fibonacci.txt"};
 std::fstream fibonacci {file_name, std::ios_base::in | std::ios_base::out | 
 std::ios_base::trunc};
 if(!fibonacci)
 {
 std::cerr << file_name << " not open." << std::endl;
 exit(1);
 }
 unsigned long long first {0ULL}, second {1ULL};
 auto iter = std::ostream_iterator<unsigned long long> {fibonacci, " "};
 (iter = first) = second; // Write the first two values
const size_t n {50};
 std::generate_n(iter, n, [&first, &second]
 { auto result = first + second;
 first = second;
 second = result;
 return result; });
 fibonacci.seekg(0); // Back to file beginning
 std::for_each(std::istream_iterator<unsigned long long> {fibonacci},
 std::istream_iterator<unsigned long long> {},
 [](unsigned long long k)
 { const size_t perline {6};
 static size_t count {};
 std::cout << std::setw(12) << k << ((++count % perline) ? " " : "\n");
 });
 std::cout << std::endl;
 fibonacci.close(); // Close the file
}

9.5 流缓冲区迭代器

流迭代器指挥传送字符到流缓冲区或从流缓冲区读出字符。

流缓冲区迭代器可以直接访问流的缓冲区,因此不包含插入和提取运算符。也没有数据的转换,数据之间也不需要分隔符,即使有分隔符,也可以自己处理他们。

istreambuf_iterator,ostreambuf_iterator.可以构造读写任意char\wchar_t\char16_t\char32类型的字符的流缓冲区迭代器。

9.5.1 输入流缓冲区迭代器

由以下成员函数:

1.operator*()返回流中当前字符的副本。流的位置不会被提前,因此可以反复地读取当前字符。

2.operator->()访问当前字符的成员---如果由成员的话

3.operator++() 在移动位置后才返回流迭代器,operator++(int)在被移动位置之前返回流迭代器的一个代理。前缀++运算符很少使用。

4.equal()当前迭代器和参数都不是流结束迭代器或者都是流结束迭代器。返回true。

可以依靠流的结束来终止输入,或者找到特定字符:

std::istreambuf_iterator<char> in {std::cin};
std::istreambuf_iterator<char> end_in;
char end_ch {'*'};
string rubbish;
while(in != end_in && *in != end_ch) rubbish += *in++;
std::cout << rubbish << std::endl; // Whatever you entered up to '*' or EOF
9.5.2 输出流缓冲区迭代器
string file_name {"G:/Beginning_STL/junk.txt"};
std::ofstream junk_out {file_name};
std::ostreambuf_iterator<char> out {junk_out};
std::ostreambuf_iterator<char> out {junk_out.rdbuf()};

可以通过一个流缓冲区的地址传给构造函数来生成输出流缓冲区对象。ofstream对象的成员函数rdbuf()会返回流内部的缓冲区地址,成员函数rdbuf()继承自ios_base,它是所有流对象的基类。

ostreambuf_iterator对象有以下成员函数:

1.operator=()将参数字符写道流缓冲区中。如果失败到EOF,就说明流缓冲区是满的,这个写操作失败。

2.当上一次写缓冲区失败时,failed()返回true。当识别到EOF时,会发生这种情况,因为输出流缓冲区是满的。

3.operator*()不做任何事

4.operator++() operator++(int)

9.5.3 对文件流使用输出流缓冲区迭代器
string file_name {"G:/Beginning_STL/dictionary.txt"};
 std::ifstream file_in {file_name};
 if(!file_in)
 {
 std::cerr << file_name << " not open." << std::endl;
 exit(1);
 }
 string file_copy {"G:/Beginning_STL/dictionary_copy.txt"};
 std::ofstream file_out {file_copy, std::ios_base::out | std::ios_base::trunc};
 std::istreambuf_iterator<char> in {file_in}; // Input stream buffer iterator
 std::istreambuf_iterator<char> end_in; // End of stream buffer iterator
 std::ostreambuf_iterator<char> out {file_out}; // Output stream buffer iterator
 while(in != end_in)
 out = *in++; // Copy character from in to out
 std::cout << "File copy completed." << std::endl;
 file_in.close(); // Close the file
 file_out.close(); // Close the file
}

可以使用copy算法简化代码:

std::copy(std::istreambuf_iterator<char> {file_in}, std::istreambuf_iterator<char> {},
 std::ostreambuf_iterator<char>{file_out});

9.6 string流、流、以及流缓冲区迭代器

string流是标识内存中字符缓冲区中的I/O对象,是定义在sstream头文件中三个模板中的一个实例:

1.basic_istringstream支持从内存中的字符缓冲区读取数据

2.basic_ostringstream支持写数据到内存中的字符缓冲区

3.basic_stringstream支持字符缓冲区上的输入和输出操作

对文件流做的几乎任何事同样也可以对string流做。可以用插入和提取运算符来格式化string流的I/O;这意味着可以用流迭代器来读写。流缓冲区迭代器也行。

当需要多次读取来确定数据是什么的时候,可以利用string流和string流迭代器提高效率:

int main()
{
 string file_in {"G:/Beginning_STL/dictionary.txt"};
 std::ifstream in {file_in};
 if(!in)
 {
 std::cerr << file_in << " not open." << std::endl;
 exit(1);
 }
 std::stringstream instr; // String stream for file contents
 std::copy(std::istreambuf_iterator<char>{in}, std::istreambuf_iterator<char>(),
 std::ostreambuf_iterator<char>{instr});
 in.close(); // Close the file
 std::vector<string> words;
 string word;
 auto end_iter = std::istream_iterator<string> {}; // End-of-stream iterator
 while(true)
 {
 std::cout << "\nEnter a word, or Ctrl+z to end: ";
 if((std::cin >> word).eof()) break;
 string word_copy {word};
 do
 {
 instr.clear(); // Reset string stream EOF
 instr.seekg(0); // String stream position at beginning
 // Use find() to search instr for word

if(std::find(std::istream_iterator<string>(instr), end_iter, word) != end_iter)
 words.push_back(word); // Store the word found
 std::next_permutation(std::begin(word), std::end(word));
 } while(word != word_copy);
 std::copy(std::begin(words), std::end(words), std::ostream_iterator<string>{std::cout, " "});
 std::cout << std::endl;
 words.clear(); // Remove previous anagrams
 }
}

对于std::copy(std::istream_iterator{in}, std::istream_iterator(), std::ostream_iterator{instr, " "});

复制操作使用instr << in.rdbuf();更快。因为没有保函格式化或数据转换。

类似的再度到instr中数据的末尾是会设置EOF,必须调用成员函数clear()来重置这个标志:

课后练习

pe9_1:第一版:

#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<fstream>
#include<algorithm>
using namespace std;
int main() {
	string file = "pe9_1.txt";
	string name;
	size_t age;
	
	ofstream file_out{ file };
	
	if (!file_out) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}
	cout << "Enter name and age(Ctrl+Z to end): " << endl;
	while (true)
	{
		if ((cin >> name >> age).eof()) {
			cin.clear();
			break;
		}
		file_out << name <<" " << age<<" ";
	}
	file_out.close();
	cout << "写入文件中……"<<endl;
	cout << "文件读出中……"<<endl;;
	ifstream file_in{ file };
	if (!file_in) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}
	//auto iter = istream_iterator<string>(file_in);
	//copy(file_in)
	vector<pair<string, size_t>> ppp;
	while (file_in>>name>>age)
	{
		ppp.emplace_back(name, age);
	}
	file_in.clear();
	file_in.close();
	for_each(begin(ppp), end(ppp), [](pair<string, size_t> p) {cout << p.first << " " << p.second << endl; });
	return 0;
}

pe9_1:第二版使用二进制模式:

#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<fstream>
#include<algorithm>
using namespace std;
int main() {
	string file = "pe9_1_第二版.txt";
	string name;
	size_t age;
	pair<string, size_t> na;
	ofstream file_out{ file,ios::out|ios::binary };

	if (!file_out) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}
	cout << "Enter name and age(Ctrl+Z to end): " << endl;
	while (true)
	{
		if ((cin >> na.first >> na.second).eof()) {
			cin.clear();
			break;
		}
		//file_out << name << " " << age << " ";
		file_out.write((char*)&na, sizeof(na));
	}
	file_out.close();
	cout << "写入文件中……"<<endl;
	cout << "文件读出中……"<<endl;
	ifstream file_in{ file,ios::in|ios::binary };
	if (!file_in) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}
	
	while (file_in.read((char*)&na,sizeof(na)))
	{
		cout << na.first << " " << na.second << endl;
	}
	file_in.clear();
	file_in.close();
	
	return 0;
}

 pe9_1:第三版使用copy(begin(ppp), end(ppp), ostream_iterator<pair_adaptor>(cout, " "));

利用ostream_iterator输出自定义类型:

#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<fstream>
#include<algorithm>
using namespace std;
class pair_adaptor {
	
public:
	pair<string, size_t> p;
	pair_adaptor(pair<string, size_t> pp) :p(pp) {};
	
	ostream& operator<<(ostream& os) {
		os << p.first << " " << p.second << endl;
		return os;
	}
};
ostream& operator<<(ostream& os, const pair_adaptor& pp) {
	os << pp.p.first << " " << pp.p.second << endl;
	return os;
}
int main() {
	string file = "pe9_1_第三版.txt";
	string name;
	size_t age;

	ofstream file_out{ file };

	if (!file_out) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}
	cout << "Enter name and age(Ctrl+Z to end): " << endl;
	while (true)
	{
		if ((cin >> name >> age).eof()) {
			cin.clear();
			break;
		}
		file_out << name << " " << age << " ";
	}
	file_out.close();
	cout << "写入文件中……" << endl;
	cout << "文件读出中……" << endl;
	ifstream file_in{ file };
	if (!file_in) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}
	//auto iter = istream_iterator<string>(file_in);
	//copy(file_in)
	vector<pair_adaptor> ppp;
	while (file_in >> name >> age)
	{
		
		ppp.emplace_back(make_pair(name, age));//ppp.emplace_back(name, age)报错没有接受两个参数的重载函数。

	}
	file_in.clear();
	file_in.close();
	copy(begin(ppp), end(ppp), ostream_iterator<pair_adaptor>(cout, " "));
	//for_each(begin(ppp), end(ppp), [](pair<string, size_t> p) {cout << p.first << " " << p.second << endl; });
	return 0;
}

pe9_3:

#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<fstream>
#include<sstream>
#include<algorithm>
using namespace std;
class pair_adaptor {
	
public:
	pair<string, size_t> p;
	pair_adaptor(pair<string, size_t> pp) :p(pp) {};
	
	ostream& operator<<(ostream& os) {
		os << p.first << " " << p.second << endl;
		return os;
	}
};
ostream& operator<<(ostream& os, const pair_adaptor& pp) {
	os << pp.p.first << " " << pp.p.second << endl;
	return os;
}
int main() {
	string file = "pe9_1.txt";
	string name;
	size_t age;

	cout << "文件读出中……" << endl;
	ifstream file_in{ file };
	
	if (!file_in) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}

	stringstream instr;
	//copy(istreambuf_iterator<char>(file_in), istreambuf_iterator<char>(), ostreambuf_iterator{ instr });
	instr << file_in.rdbuf();

	cout << "strResult is: " << instr.str() << endl;
	map<string, size_t> mm;
	while (instr)
	{
		instr >> name >> age;
		mm.emplace(name, age);
	}
	for (auto value : mm) {
		cout << value.first << " " << value.second << endl;
	}
	
	/*std::ostream_iterator<std::pair<const std::string, size_t>> out_iter(std::cout, "\n");
	std::copy(mm.begin(), mm.end(), out_iter);*///不好使
	
	return 0;
}

pe9_4:

#include<iostream>
#include<random>
#include<fstream>
#include<algorithm>
#include<numeric>
using namespace std;
long  generate_rand(const int& min, const int& max);
int main() {
	string file  { "pe9_4.txt" };
	ofstream file_out{ file };
	if (!file_out) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}
	for (int i = 0; i < 100; i++) {
		long number = generate_rand(0, 1000000000);
		file_out << number<<" ";
	}

	file_out.close();

	ifstream file_in{ file };
	if (!file_in) {
		std::cerr << file << " not open." << endl;
		exit(1);
	}
	auto iter = istream_iterator<long>(file_in);
	long  min, max;
	
	min = *min_element(iter, istream_iterator<long>());
	max = *max_element(iter, istream_iterator<long>());
	auto mean = accumulate(iter, istream_iterator<long>(), 0) / 100;
	/*cout << "........." << endl;
	copy(iter, istream_iterator<long>(), ostream_iterator<long>(cout, " "));
	cout << "........." << endl;*/
	file_in.close();
	//必须重新获取迭代器,不然只有一个输出。
	ifstream file_in2{ file };
	auto iter2 = istream_iterator<long>(file_in2);
	cout << "max: " << max << " min: " << min << " mean: " << mean << endl;
	for (int i = 0; i < 13; i++) {
		if (i == 12) {
			copy_n(iter2, 4, ostream_iterator<long>(cout, " "));
			cout << endl;
		}
		else {
			copy_n(iter2, 8, ostream_iterator<long>(cout, " "));
			cout << endl;
		}
	}
	
	file_in2.close();
	return 0;
}
long generate_rand(const int& min, const int& max) {
	random_device rd;
	std::mt19937 gen(rd());

	std::uniform_int_distribution dis(min, max);

	return dis(gen);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值