C++(STL)实现的修改游戏存档文件的2个相关类

 //本类可自动检查游戏存档中的数值

//属于模板类

//T代表要寻找数据的类型//如金钱,生命等属于整型
//但不排除以后要查找其他类型的数据。为了可扩充性,使用了模板。


template <typename T>
class CheckBinaryFile{
    
    public:
        typedef fstream::off_type AddressType;//要找的数据在文件中的地址类型
        CheckBinaryFile();//构造函数
        void Run();
    private:
        static const int MaxByte=sizeof(T);//要查找的数据的类型所占的字节数
        const int CharSize;
        EInputStream CIN;//一个加强输入流(第三方类)
        string FileName;//文件名称
        T OldData;//输入的要查找的数据
        int ByteNumber;//要查找的数据所占的字节数


        //mutable关键字是const的反义作用,容易变动的变量经常使用它

        mutable bool InputIsOk;
        //用于读的文件对象
        mutable ifstream BinaryFile;

        mutable list<AddressType> AddressList;
        
        //操作方法
        void Input();
        int Check() const;


        void SaveAddressToFile(ostream&) const;//最后的"const"作用是防止修改本类对象的状态,即除mutable关键字标识的变量外其他都不可在此函数内做修改
        void AutoModifySave(const T&) const;//在函数内防止修改T类型的参数
};
template <typename T>
//如果是static声明的静态变量在类体内做了声明,则在类外必须再做定义,而且只能被声明一次
const int CheckBinaryFile<T>::MaxByte;



//源文件


//构造函数
template <typename T>
CheckBinaryFile<T>::CheckBinaryFile():CharSize(char),CIN(cin){
    InputIsOk=true;
    Input();
    //CharSize 为sizeof(char),把cin 绑定到CIN。由于CharSize是常量,必须在构造函数的初始化列表中设定。
}


//私有函数:输入成员函数

template <typename T>
void CheckBinaryFile<T>::Input()
{
    //打开指定的输入文件名的二进制文件
    cout<<"Binary Filename:/t";
    cin>>FileName;
    BinaryFile.open(FileName.c_str(),ios::in|ios::binary);
    if(!BinaryFile)
    {
        InputIsOk=false;
        cerr<<"open file failed!/n";
        return;
    }

    //输入要查找的数据
    cout<<"the Integer you want to search:/t";
    CIN>>OldData;
    
    //要找的数据的所占的数据位(字节数)
    cout<<"byte number:(1--"<<CheckBinaryFile<T>::MaxByte<<"):/t";
    CIN>>ByteNumber;
    
    //字节数是否溢出的检查

    if(ByteNumber<1||ByteNumber>CheckBinaryFile<T>::MaxByte)
    {
        ByteNumber=CheckBinaryFile<T>::MaxByte;
    //    cout<<"Byte number was amended to "<<ByteNumber<<endl;
        cout<<"Byte number was amended to "<<CheckBinaryFile<T>::ByteNumber<<endl;//???????????????
    
    }
    
}


//私有函数:检查输入的二进制文件中有多少个OldData,并保存地址到list链表对象中
//memory.h
template <typename T>
int CheckBinaryFile<T>::Check() const{

    //将数据地址转换为字符串地址    
    const char* p=reinterpret_cast<const char*>(&OldData);
    char Range[CheckBinaryFile<T>::MaxByte];
    int Occurs=0;
    AddressType Addr=0;
    //填充0
    memset(Range,0,CheckBinaryFile<T>::MaxByte*CharSize);
    BinaryFile.read(Range,CharSize*ByteNumber);//填满Range
    //如果读文件成功
    while(BinaryFile)
    {
        if(memcmp(p,Range,CharSize*ByteNumber)==0)
        {
            AddressList.push_back(Addr);
            ++Occurs;
        }

    //删除一个最旧的
      memcpy(Range,&Range[1],CharSize*(ByteNumber-1));
    //读最新
    BinaryFile.read(&Range[ByteNumber-1],CharSize);
    ++Addr;
    }
    //返回匹配数量
    return Occurs;
}


//私有函数:保存找到的地址到文件

template <typename T>
void CheckBinaryFile<T>::SaveAddressToFile(ostream& os) const
{
    copy(AddressList.begin(),AddressList.end(),ostream_iterator<T>(os,"/t"));
}


//私有函数:保存修改结果分别为一个文件

template <typename T>
void CheckBinaryFile<T>::AutoModifySave(const T& NewValue) const
{
    list<AddressType>::const_iterator Beg=AddressList.begin(),End=AddressList.end();
    const char *p=reinterpret_cast<const char*>(&NewValue);
    for(;Beg!=End;++Beg){
        //每个地址都要重新开头读
        BinaryFile.clear();//清除错误状态
        BinaryFile.seekg(0,ios::beg);//指向文件开头,准备读取
        AddressType Addr=0;
        char ch;
        stringstream NewFile;
        NewFile<<"@"<<*Beg;
        string NewFileName(NewFile.str());

        ofstream Write(NewFileName.c_str(),IOS::out|IOS::binary);

        //文件对象错误
        if(!Write)
        {
            cerr<<"NewFileName"<<" Failed!/n";
            continue;
        }

        while(Addr<*Beg&&BinaryFile)
        {
            //小于地址内容
            BinaryFile.read(&ch,CharSize);
            Write.write(&ch,CharSize);
            ++Addr;
        }
        
        for(int k=0;k<ByteNumber;++k)
        {
            BinaryFile.read(&ch,CharSize);    
        }
    Write.write(p,CharSize*ByteNumber);
    while(BinaryFile)
    {
        BinaryFile.read(&ch,CharSize);
        Write.write(&ch,CharSize);
    }
    Write.close();
    cout<<NewFileName<<"...successfully./n";
        //下次循环的时候文件已经成为bad状态,要清除这个状态

    }//for

    
}




//公有函数:void Run();
template <typename T>
void CheckBinaryFile<T>::Run()
{
    if(InputIsOk==false)
        return;
    //查找到的地址数量
    const int Occurs=Check();
    cout<<Occurs<<" different address were found!/n";
    //没有找到内存地址,返回
    if(Occurs==0) return;

    //提示保存cout<<"Save address info to files(y/n)?/t";

    cout<<"Save address info into files?(y/n)?/t";

    char YN;
    CIN>>YN;
    if(YN=='Y'||YN=='y'){
        cout<<"Address file name:/t";//提示输入保存的地址文件的名字
        string AddressFileName;
        CIN>>AddressFileName;
        ofstream Save(AddressFileName.c_str(),ios::out);
        if(!Save)
        {
            cerr<<"Create log file:"<<AddressFileName<<" error!/n";
        }else{
            SaveAddressToFile(Save);
            }
        Save.close();
    }

    cout<<"Modify binary file automatically(y/n)?/t";
    CIN>>YN;
    if(YN=='Y'||YN=='y')
    {
        cout<<"New value:/t";
        T NewValue;
        CIN>>NewValue;
        system("dir>@tmp");//下句删除文件在不存在@开头的文件的时候错误,故首先建立一个名为@temp的文件
        system("del @*/q");//执行DOS命令删除所有以@开头的文件
        //将修改的文件分别保存一个单独的文件
        AutoModifySave(NewValue);
    }
    

}



//扩展1.取得2个地址文件的交集

//核心方法:set_intersection函数

template <typename T>

void GetInersection()
{
    EInputStream CIN(cin);
    //提示输入几个交叉的文件名,使用不存在的集合文件来结束输入
    cout<<"Input some text filenames for reading,end with a nonexistent one:/n";

    
    string fn;
    CIN>>fn;
    ifstream Read(fn.c_str());
    if(!Read)
    {
        cerr<<"Open "<<fn<<" failed!/n";
        return;
    }

    vector<T> V1;
    //copy(istream_iterator<T>(Read),istream_iterator<T> (),back_inserter(V1));//保存file1的内容到V1

    //保存file1的内容到V1中
    copy(istream_iterator<T>(Read),istream_iterator<T>(),back_inserter(V1));
    CIN<<fn;
    Read.clear();
    Read.close();
    Read.open(fn.c_str());
    if(!Read)
    {
        cerr<<"Open the file failed!/n";
        return;
    }

    vector<T> V2,V3;
    copy(istream_iterator<T>(Read),istream_iterator<T>(),back_inserter(V2));//保存file2的内容到向量V2中
    sort(V1.begin(),V1.end());//对V1排序
    
    V1.erase(unique(V1.begin(),V2.end()),V1.end());///???????删除重复数据
    
    sort(V2.begin(),V2.end());//对V1排序
    
    V2.erase(unique(V2.begin(),V2.end()),V2.end());

    set_intersection(V1.begin(),V1.end(),V2.begin(),V2.end(),back_inserter(V3));

    while(V3.empty()==false)
    {
        //如果是空集就退出
        CIN<<fn;
        Read.clear();
        Read.close();
        Read.open(fn.c_str());
        if(!Read)
            break;
        
        //建立空容器和V1交换以清除V1
        vector<T>().swap(V1);
        
        copy(istream_iterator<T>(Read),istream_iterator<T>(),back_inserter(V1));
        sort(V1.begin(),V1.end());
        V1.erase(unique(V1.begin(),V1.end()),V1.end());
        V2.swap(V3);
        vector<T>().swap(V3);
        set_intersection(V1.begin(),V1.end(),V2.begin(),V2.end(),back_inserter(V3));
    }

    if(V3.empty())
    {
        cout<<"An empty aggregate was found after reading"<<fn<<"./n";
        return;
    }

    cout<<V2.size()<<"value were enumerated./n";

    cout<<"Input save filename:/t";
    CIN>>fn;
    ofstream Dest(fn.c_str());

    if(!Dest)
    {
        cerr<<"Create file failed!/n";
        return;

    }else
    {
        copy(V3.begin(),V3.end(),ostream_iterator<T>(Dest,"/t"));
        Dest.close();
    }

}


//查找相对值函数

template<class T>
void RelativeValue()
{
   typedef fstream::off_type AddressType;
   EInputStream CIN(cin);
   string FN;
   cout<<"First binary file name:/t";
   CIN>>FN;
   ifstream Read1(FN.c_str(),ios::in ios::binary);
   //读+二进制模式
   if(!Read1)
   {
      cerr<<"Open "<<FN<<" failed./n";
      return;
   }
   cout<<"Second binary file name:/t";
   CIN>>FN;
   ifstream Read2(FN.c_str(),ios::in ios::binary);
   if(!Read2)
   {
      cerr<<"Open "<<FN<<" failed./n";
      return;
   }
   int ByteNumber;
   cout<<"Byte number:/t";
   CIN>>ByteNumber;//字节数
   int RV;//指定的相对值
   cout<<"Relative value(value1-value2):/t";
   cin>>RV;
   const int MaxByte=sizeof(T);
   const int CharSize=sizeof(char);
   if(ByteNumber<1ByteNumber>MaxByte)
      ByteNumber=MaxByte;
      T Value1,Value2;//两个文件中的数值
      char* P1=reinterpret_cast<char*>(&Value1);
      char* P2=reinterpret_cast<char*>(&Value2);
      //先全部清0
      memset(P1,0,MaxByte*CharSize);
      memset(P2,0,MaxByte*CharSize);
      AddressType Address=0;
      //填充满P1
      Read1.read(P1,CharSize*ByteNumber);
      //填充满P2
      Read2.read(P2,CharSize*ByteNumber);
      //保存信息的链表
      typedef list<pair<AddressType,pair<T,T> > > InfoList;
      InfoList IL;
      int Occurs=0;
      //当两个文件都还没有读完
      while(Read1 && Read2)
      {
         if(Value1-Value2==RV)//符合条件了
         {
            //保存信息
            IL.push_back(make_pair(Address,make_pair(Value1, Value2)));
            ++Occurs;
         }
         //除旧
         memcpy(P1,&P1[1],CharSize*(ByteNumber-1));
         memcpy(P2,&P2[1],CharSize*(ByteNumber-1));
         //迎新
         Read1.read(&P1[ByteNumber-1],CharSize);
         Read2.read(&P2[ByteNumber-1],CharSize);
         ++Address;
      }//while(Read1 && Read2)
      cout<<Occurs<<" different addresses were found./n";
      if(Occurs==0) return;
      cout<<"Input save filename:/t";
      CIN>>FN;
      //保存至文件
      ofstream SaveFile(FN.c_str());
      if(!SaveFile)
      {
         cerr<<"Create "<<FN<<" failed./n";
         return;
      }
      SaveFile<<"Relative value is " <<RV<<"/nAddress/tValue1/tValue2/n";
      for(InfoList::const_iterator Beg=IL.begin(), End=IL.end();Beg!=End;++Beg)
      {
         SaveFile<<(*Beg).first<<'/t' <<(*Beg).second.first <<'/t'<<(*Beg).second.second <<'/n';
      }
   }






///修改多个地址值的类/
template<class T>
class Modify
{
   public:
      typedef fstream::off_type AddressType;
      static const int MaxByte=sizeof(T);
      Modify();
      void Run() const;
   private:
      strUCt ModifyInfoUnit
      {
         //修改要素——地址
         AddressType Address;
         //修改要素——新的数值
         T NewValue;
         //修改要素——新数值的字节数
         int ByteNumber;
         //排序原则
         bool operator<(const Modify<T>::ModifyInfoUnit& rhs) const;
         //从输入流读取一个单元
         void ReadFrom(istream&);
      };
      const int CharSize;
      EInputStream CIN;
      void Input();
      bool InputIsOk;
      mutable ifstream SourceFile;
      mutable ofstream DestFile;
      set<ModifyInfoUnit> ModifyInfoSet;//集合
};
template<class T>
const int Modify<T>::MaxByte;


template<class T>
Modify<T>::Modify():CharSize(sizeof(char)),CIN(cin)
{
   InputIsOk=true;
   Input();
}
//构造函数,设置输入状态。

template<class T>
void Modify<T>::Input()
{
   string fn;
   cout<<"Source binary file name:/t";
   CIN>>fn;
   SourceFile.open(fn.c_str(),ios::in ios::binary);
   if(!SourceFile)
   {
      cerr<<"Open "<<fn<<" failed./n";
      InputIsOk=false;
      return;
   }
   cout<<"Save file name:/t";
   CIN>>fn;
   DestFile.open(fn.c_str(),ios::out ios::binary);
   if(!DestFile)
   {
      cerr<<"Create "<<fn<<" failed./n";
      InputIsOk=false;
      return;
   }
   cout<<"Any character which makes format error will end the input progress.(etc a)/n";
   cout<<"Address(Dec)/tNewValue/tByteNumber(1--" <<Modify<T>::MaxByte<<")/n";
   while(true)
   {
      ModifyInfoUnit MIU;
      //从真实的输入流中读取一个ModifyInfoUnit
      MIU.ReadFrom(CIN.Actual());
      //输入失败就退出循环
      if(!CIN.Actual()) break;
      //把输入成功的单元存入集合,自动排序
      ModifyInfoSet.insert(MIU);
   }
   CIN.ClearAndIgnore();//清除流的失败状态
}


template<class T>
void Modify<T>::Run() const
{
   if(InputIsOk==false) return;
   set<ModifyInfoUnit>::const_iterator Beg=
   ModifyInfoSet.begin(),End=ModifyInfoSet.end();
   AddressType Address=0;
   char ch;
   while(SourceFile && Beg!=End)
   {
      //SourceFile没有读完并且集合也没有遍历结束
      if(Address==Beg->Address)
      {
         //到了指定的地址了
         const char*P=reinterpret_cast<const char*>(&(Beg->NewValue));
         for(int k=0;k<Beg->ByteNumber;++k)
         {
            //忽略源文件
            SourceFile.read(&ch,CharSize);
         }
         //写新值
         DestFile.write(P,CharSize*Beg->ByteNumber);
         Address+=Beg->ByteNumber;
         ++Beg;
      }
      else
      {
         SourceFile.read(&ch,CharSize);
         DestFile.write(&ch,CharSize);
         ++Address;
      }
   }
   //源文件中可能还有剩余的内容
   while(SourceFile.read(&ch,CharSize))DestFile.write(&ch,CharSize);
}


template<class T>
bool Modify<T>::ModifyInfoUnit::operator<(const Modify<T>::
ModifyInfoUnit& rhs) const
{
   return Address<rhs.Address;
}
//定义排序原则,应该是一个const成员函数。

template<class T>
void Modify<T>::ModifyInfoUnit::ReadFrom(istream& IS)
{
   IS>>Address>>NewValue>>ByteNumber;
   if(ByteNumber<1ByteNumber>Modify<T>::MaxByte)
      ByteNumber=Modify<T>::MaxByte;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值