一、问题描述 
Personal Diary 是一个命令行程序,包含以下四个程序
pdadd pdlist [] pdshow pdremove 
 
1.1 pdadd程序 
向日记文件dairy.txt 中添加一个实体,包含日记的时间、内容
1.2 pdlist程序 
按照日期的顺序,列出diary.txt 中的日记实体
输入:如果通过命令行参数,输入了开始日期和结束日期,则只输出在这两个日期之间的日记 
输出:stdout  
 
1.3 pdshow程序 
按照输入的日期,列出diary.txt 中的对应日记实体的内容
1.4 pdremove程序 
按照输入的日期,删除diary.txt 中的对应日记
输入:stdin  
输出:stdout  
返回值:0 表示删除成功,1 表示删除失败 
 
二、实现思路 
2.1 定义的类 
2.1.1 Date类 
成员变量 
int  year;  int  month; int  day;   
 
成员函数 
bool  input ()  ; bool  input (ifstream& fin)  ; void  output ()  ;void  output (ofstream& fout)  ;
 
重载符号 
以年、月、日为第一、二、三关键字进行比较 
注意,-1/-1/-1 默认为最大值 
 
2.1.2 Diary类 
成员变量 
Date date;				 vector<string>content;   
 
成员函数 
bool  input ()  ; bool  input (ifstream& fin)  ; void  output ()  ;void  output (ofstream& fout)  ;void  outputDate ()  ;Date GetDate ()  ;
 
重载符号 
以date 为唯一关键字进行比较 
 
2.2 存储 
日记文件为./code/diary.txt  
按照日期,升序排列所有日记文件 
以-1/-1/-1 为文件结尾 
 
2.3 pdadd 
用一个vector< Diary
>diary 保存已有的所有日记
首先,从键盘中输入新增日记的信息,放到vector 数组里面,记为diary[0]  
然后,从diary.txt 文件读取所有日记,放到vector 数组里面 
从diary[1] 开始输出存下的所有日记,分为三种情况
diary[i] =
diary[0] :根据题意,舍弃diary[i] ,将diary[0] 输入到文件中 
diary[i] > diary[0] && diary[i] <
diary[0] :由于根据日期升序排列,此时要先输出diary[0] ,后输出diary[i]  
其它情况:直接输出diary[i]  
  
 
2.4 pdlist 
与pdadd 类似,从diary.txt 中读取所有日记,保存到diary 数组中 
从diary[0] 开始输出存下的所有日记,由于只需要表示日记实体,因此我们只输出日记的日期 
至于输出一定范围内的日记,我们只需要在输出的时候,判断一下diary[i] 的日期是否在指定的范围内即可 
当没有日记输出时,会输出提示信息 
 
2.5 pdshow 
与pdlist 类似,从diary.txt 中读取所有日记,保存到diary 数组中 
从diary[0] 开始遍历存下的所有日记,如果日期与输入的相同,则输出当前日记的所有内容 
当没有日记输出时,会输出提示信息 
 
2.6 pdremove 
与pdadd 类似,从diary.txt 中读取所有日记,保存到diary 数组中 
从diary[0] 开始输出存下的所有日记,分为两种情况
diary[i] 的日期与给定的日期相同:跳过该条日记 
否则将diary[i] 输入到文件中 
  
当待删除的日期不存在时,会输出提示信息 
 
三、源码 
3.0 公共类 
3.0.1 Date 
#pragma  once #include  <iostream>  #include  <fstream>  #include  "Utils.h"  class  Date  {public :	Date () : year (0 ), month (0 ), day (0 ) {} 	Date (int  year, int  month, int  day) : year (year), month (month), day (day) {} 	 	bool  input ()  ; 	 	bool  input (std::ifstream& fin)  ; 	 	void  output ()  const  ; 	 	void  output (std::ostream& fout)  const  ; public :	bool  operator ==(const  Date& A) const ; 	bool  operator <(const  Date& A) const ; 	bool  operator >(const  Date& A) const ; private :	int  year, month, day; }; static  const  Date DATE_MAX = Date (9999 , 12 , 31 );static  const  Date DATE_MIN = Date (0 , 1 , 1 );
 
#pragma  warning (disable:4996) #include  "Date.h"  bool  Date::input ()   {	printf ("请输入日记的日期:年 月 日\n" ); 	SetColor (Color::Red); 	std::cin >> year >> month >> day; 	SetColor (Color::Blue); 	if  (year == -1 )return  false ; 	return  true ; } bool  Date::input (std::ifstream& fin)   {	if  (fin.eof ()) return  false ; 	fin >> year >> month >> day; 	if  (year == -1 )return  false ; 	return  true ; } void  Date::output ()  const   {	SetColor (Color::Red); 	printf ("%04d/%02d/%02d\n" , year, month, day); 	SetColor (Color::Blue); } void  Date::output (std::ostream& fout)  const   {	fout << year << " "  << month << " "  << day << std::endl; } bool  Date::operator ==(const  Date& A) const  {	return  year == A.year && month == A.month && day == A.day; } bool  Date::operator <(const  Date& A) const  {	if  (year == -1 )return  false ; 	if  (A.year == -1 )return  true ; 	if  (year != A.year)return  year < A.year; 	if  (month != A.month)return  month < A.month; 	return  day < A.day; } bool  Date::operator >(const  Date& A) const  {	return  !(*this  < A) && !(*this  == A); } 
 
3.0.2 Diary 
#pragma  once #include  <vector>  #include  "Date.h"  class  Diary  {public :	Diary () {} 	Diary (const  Date& date) : date (date) {} 	 	bool  input ()  ; 	 	bool  input (std::ifstream& fin)  ; 	 	void  output ()  const  ; 	 	void  output (std::ostream& fout)  const  ; 	 	void  outputDate ()  const  ; public :	Date GetDate ()  const   { return  date; } public :	bool  operator ==(const  Diary& A) const ; 	bool  operator <(const  Diary& A) const ; 	bool  operator >(const  Diary& A) const ; private :	Date date; 	std::vector<std::string> content; }; 
 
#pragma  warning (disable:4996) #include  "Diary.h"  using  namespace  std;bool  Diary::input ()   {	if  (date.input () == false )return  false ; 	printf ("请逐行输入日记的内容,以.或EOF结束\n" ); 	string s; 	getline (cin, s); 	while  (1 ) { 		SetColor (Color::Yellow); 		printf ("%2d:" , (int )content.size () + 1 ); 		SetColor (Color::Red); 		getline (cin, s); 		if  (s.empty ())break ; 		if  (s[0 ] == '.' )break ; 		content.push_back (s); 	} 	content.push_back (".\n" ); 	SetColor (Color::Yellow); 	printf ("日记输入成功\n" ); 	SetColor (Color::Clear); 	return  true ; } bool  Diary::input (std::ifstream& fin)   {	if  (date.input (fin) == false )return  false ; 	string s; 	getline (fin, s); 	while  (1 ) { 		getline (fin, s); 		if  (s.empty ())break ; 		if  (s[0 ] == '.' )break ; 		content.push_back (s); 	} 	content.push_back ("." ); 	return  true ; } void  Diary::output ()  const   {	date.output (); 	for  (int  i = 0 ; i < content.size () - 1 ; i++) 		cout << content[i] << endl; 	cout << endl; } void  Diary::output (std::ostream& fout)  const   {	date.output (fout); 	for  (int  i = 0 ; i < content.size (); i++) 		fout << content[i] << endl; } void  Diary::outputDate ()  const   {	date.output (); } bool  Diary::operator ==(const  Diary& A) const  {	return  date == A.date; } bool  Diary::operator <(const  Diary& A) const  {	return  date < A.date; } bool  Diary::operator >(const  Diary& A) const  {	return  date > A.date; } 
 
3.0.3 DiaryManager 
#pragma  once #include  "Diary.h"  #include  <set>  class  DiaryManager  {public :	static  DiaryManager& GetInstance ()   { 		static  DiaryManager instance; 		return  instance; 	} public :	void  InputNewDiary ()  ; 	void  OutputAllDiary (Date L = DATE_MIN, Date R = DATE_MAX)  ; 	void  RemoveDiary (Date now)  ; private :	void  InputAllDiary ()  ; 	void  StoreDiary ()  ; private :	DiaryManager (); 	~DiaryManager (); 	std::set<Diary> diary; }; 
 
#include  "DiaryManager.h"  using  namespace  std;void  DiaryManager::InputNewDiary ()   {	Diary tmp; 	tmp.input (); 	diary.insert (tmp); } void  DiaryManager::OutputAllDiary (Date L, Date R)   {	auto  it1 = diary.lower_bound (Diary (L)); 	auto  it2 = diary.upper_bound (Diary (R)); 	SetColor (Color::Yellow); 	if  (it1 == it2) { 		cout << "No diary in this period!\n" ; 	} 	else  { 		cout << "Diary is as following:\n" ; 		for  (auto  it = it1; it != it2; it++) { 			it->output (); 		} 	} 	SetColor (Color::Clear); } void  DiaryManager::RemoveDiary (Date now)   {	SetColor (Color::Yellow); 	if (diary.find (Diary (now)) != diary.end ()) { 		diary.erase (Diary (now)); 		cout << "Remove success"  << endl; 	} 	else  { 		cout << "No diary on this day!"  << endl; 	} 	SetColor (Color::Clear); } void  DiaryManager::InputAllDiary ()   {	ifstream fin ("diary.txt" )  ; 	while  (true ) { 		Diary tmp; 		if  (!tmp.input (fin)) break ; 		diary.insert (tmp); 	} 	fin.close (); } void  DiaryManager::StoreDiary ()   {	ofstream fout ("diary.txt" , ios::out)  ; 	for (auto  it = diary.begin (); it != diary.end (); it++) { 		it->output (fout); 	} 	fout.close (); } DiaryManager::DiaryManager () { 	InputAllDiary (); } DiaryManager::~DiaryManager () { 	StoreDiary (); } 
 
3.0.4 Utils 
#pragma  once #include  <string>  #include  <Windows.h>  enum class  Color  {	Red, 	Blue, 	Green, 	Yellow, 	Clear }; static  void  SetColor (Color color)   {	HANDLE hdl = GetStdHandle (STD_OUTPUT_HANDLE); 	if  (color == Color::Red)SetConsoleTextAttribute (hdl, FOREGROUND_RED | FOREGROUND_INTENSITY); 	else  if  (color == Color::Blue)SetConsoleTextAttribute (hdl, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY); 	else  if  (color == Color::Green)SetConsoleTextAttribute (hdl, FOREGROUND_GREEN | FOREGROUND_INTENSITY); 	else  if  (color == Color::Yellow)SetConsoleTextAttribute (hdl, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY); 	else  if  (color == Color::Clear)SetConsoleTextAttribute (hdl, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY); } 
 
3.1 pdadd 
#pragma  warning (disable:4996) #include  "../Diary/DiaryManager.h"  using  namespace  std;int  main (int  argc, char * argv[])   {	SetColor (Color::Blue); 	if  (argc == 2 ) { 		freopen (argv[1 ], "r" , stdin); 	} 	DiaryManager::GetInstance ().InputNewDiary (); 	return  0 ; } 
 
3.2 pdlist 
#pragma  warning (disable:4996) #include  "../Diary/DiaryManager.h"  using  namespace  std;bool  CheckFormat (int  n, char * s[])   {	if  (n != 3 )return  false ; 	int  len = strlen (s[1 ]); 	int  cnt = 0 ; 	for  (int  i = 0 ; i < len; i++) { 		if  (s[1 ][i] == '/' )cnt++; 		else  if  (s[1 ][i] > '9'  || s[1 ][i] < '0' )return  false ; 	} 	if  (cnt != 2 )return  false ; 	len = strlen (s[2 ]); 	cnt = 0 ; 	for  (int  i = 0 ; i < len; i++) { 		if  (s[2 ][i] == '/' )cnt++; 		else  if  (s[2 ][i] > '9'  || s[2 ][i] < '0' )return  false ; 	} 	if  (cnt != 2 )return  false ; 	return  true ; } int  main (int  argc, char * argv[])   {	SetColor (Color::Blue); 	if  (argc == 1 ) { 		DiaryManager::GetInstance ().OutputAllDiary (); 	} 	else  { 		if  (!CheckFormat (argc, argv)) { 			SetColor (Color::Red); 			printf ("请输入正确的参数格式:xxxx/xx/xx xxxx/xx/xx\n" ); 		} 		else  { 			int  LYear = 0 , LMonth = 0 , LDay = 0 ; 			int  RYear = 0 , RMonth = 0 , RDay = 0 ; 			sscanf (argv[1 ], "%d/%d/%d" , &LYear, &LMonth, &LDay); 			sscanf (argv[2 ], "%d/%d/%d" , &RYear, &RMonth, &RDay); 			DiaryManager::GetInstance ().OutputAllDiary (Date (LYear, LMonth, LDay), Date (RYear, RMonth, RDay)); 		} 	} 	return  0 ; } 
 
3.3 pdremove 
#pragma  warning (disable:4996) #include  "../Diary/DiaryManager.h"  using  namespace  std;int  main (int  argc, char * argv[])   {	SetColor (Color::Blue); 	if  (argc == 2 ) { 		freopen (argv[1 ], "r" , stdin); 	} 	Date now; 	now.input (); 	DiaryManager::GetInstance ().RemoveDiary (now); 	return  0 ; } 
 
3.4 pdshow 
#pragma  warning (disable:4996) #include  "../Diary/DiaryManager.h"  using  namespace  std;int  main (int  argc, char * argv[])   {	SetColor (Color::Blue); 	if  (argc == 2 ) { 		freopen (argv[1 ], "r" , stdin); 	} 	Date now; 	now.input (); 	DiaryManager::GetInstance ().OutputAllDiary (now, now); 	return  0 ; } 
 
3.5 sample.bat 
pdadd sampleAdd.txt pdshow sampleShow.txt pdremove sampleRemove.txt pdlist pdlist 2022/4/10 2022/4/11 pdlist 2025/4/10 2025/4/11 pause 
 
call pdadd.exe < sampleAdd.txt call pdshow.exe < sampleShow.txt call pdremove.exe < sampleRemove.txt pdlist pdlist 2022/4/10 2022/4/11 pdlist 2025/4/10 2025/4/11 pause 
 
3.6 diary.txt 
2022 4 10 asd123www asdqw . 2022 4 11 asd1asdqweyuitbladf . 2022 4 13 asd123www asdqweyuitbladf . 2022 4 14 123456789 00000000 14568+423 . 2022 4 15 123456789 00000000 14568+423 .