2011-06-02 111 views
0

我對二進制文件有一個相當困難的問題。我被要求製作一個將信息存儲在文件中的程序,但是在Sequential模式下。由於我不允許直接在順序模式下修改內容,因此我創建了一個函數,它首先讀取文件,直到找到正確的註冊表爲止,同時將其他註冊表複製到輔助文件中。當我完成我需要的修改後,我將它複製到輔助文件並恢復複製。完成後,我將所有內容從輔助文件複製到原始文件。我做了以下各種二進制文件的例子,但我的程序做了一些奇怪的事情。它開始吃掉我寫的所有信息,只留下最後一項(類似無限截斷),甚至更糟糕的是,有一部分(標記爲「討厭的部分」)開始無意義的循環(它是無意義的就好像這個文件有無限大小一樣),我已經像上千次那樣追查邏輯了,我似乎沒有發現任何錯誤,我不知道你是否能夠幫助我,如果我錯過了一些重要的東西。C++,順序模式下的二進制文件問題

下面是我使用

class Cliente{ 
public: 
    int numCuenta; 
    char dni[10]; 
    char nombre[40]; 
}; 

class Cuenta{ 
private:   
    int numCuenta; 
    double monto; 
    int numDuenhos; 

public: 
    const static double MONTO_MIN = 100.0; 
    Cuenta(){ 
     numCuenta = 0; 
     monto = 0; 
     numDuenhos = 0; 
    } 
    int getnumCuenta(){ 
     return numCuenta; 
    } 
    void setnumCuenta(int numCuenta){ 
     this->numCuenta= numCuenta; 
    } 
    int getnumDuenhos(){ 
     return numDuenhos; 
    } 
    void setnumDuenhos(int numDuenhos){ 
     this->numDuenhos= numDuenhos; 
    } 
    double getMonto(){ 
     return monto; 
    } 
    void setMonto(double monto){ 
     this->monto = monto; 
    } 
}; 

類和有問題的功能

void modificarCuenta() { 
    Cuenta aux; 
    Cliente c; 
    ifstream rep_cuentas("cuentas.bin"); 
    ofstream buf_cuentas("cuentas_rep.bin",ios::out | ios::trunc | ios::binary); 
    if(!rep_cuentas) { 
     cout <<endl << "Error al leer fila principal"; 
    } 
    else if(!buf_cuentas) { 
     cout << endl << "Error al abrir el archivo buffer"; 
    } 
    else { 
     cout <<endl << "Ingrese el numero de cuenta a modificar: "; //id of entry 
     int num_cuenta; 
     cin >> num_cuenta; 
     ifstream rep_clientes("clientes.bin"); 
     ofstream buf_clientes("cilentes_rep.bin",ios::out | ios::trunc | ios::binary); 
     //este archivo es necesario, por eso termina si no lo lee 
     if (!rep_clientes) { 
      cerr << "Error al Abrir el Archivo de Clientes" << endl; 
      return; 
     } 
     rep_cuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta)); 
     while(!rep_cuentas.eof()){ 
      if(aux.getnumCuenta() == num_cuenta){ 
       rep_clientes.read(reinterpret_cast<char *>(&c),sizeof(Cliente)); 
       while(!rep_clientes.eof()){ 
        if(c.numCuenta == num_cuenta){ 
         cout << "DNI del Cliente: " << c.dni << endl; //old dni 
         cout << "Nombre del Cliente: " << c.nombre << endl; // old name 
         cout << "Modificar estos datos? (1 para confirmar): "; 
         int opc; 
         cin >> opc; 
         if (opc == 1){ 
          c.numCuenta = aux.getnumCuenta(); 
          cout << endl << "Ingrese nuevo DNI: "; //new dni 
          cin >> c.dni; 
          cout << endl << "Ingrese nuevo Nombre: "; //new name 
          cin >> c.nombre; 
         } 
        } 
        buf_clientes.write(reinterpret_cast<char *>(&c),sizeof(Cliente)); 
        rep_clientes.read(reinterpret_cast<char *>(&c),sizeof(Cliente)); 
       } 
       int num = aux.getnumDuenhos(); 
       while(true){ 
        cout << endl << "Desea ingresar mas duenhos? (1 para confirmar): "; //appending new user? 
        int op; 
        cin >> op; 
        if (op == 1){ 
         c.numCuenta = aux.getnumCuenta(); 
         cout << endl << "Ingrese nuevo DNI: "; //new dni 
         cin >> c.dni; 
         cout << endl << "Ingrese nuevo Nombre: "; //new name 
         cin >> c.nombre; 
         num++; 
         buf_clientes.write(reinterpret_cast<char *>(&c),sizeof(Cliente));            
        } 
        else{ 
         aux.setnumDuenhos(num); 
         break; 
        } 
       } 
      } 
      buf_cuentas.write(reinterpret_cast<char *>(&aux),sizeof(Cuenta)); 
      rep_cuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta)); 
     } 
     rep_clientes.close(); 
     buf_clientes.close(); 
    } 

    rep_cuentas.close(); 
    buf_cuentas.close(); 
    ofstream rcuentas("cuentas.bin",ios::out | ios::trunc| ios::binary); 
    ifstream bcuentas("cuentas_rep.bin"); 
    if(!rcuentas) { 
     cout << endl << "Error al abrir la fila principal"; 
    } 
    else if(!bcuentas) { 
     cout << endl << "Error al abrir el archivo buffer"; 
    } 
    else{ 
     bcuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta)); 
     while(!bcuentas.eof()){ 
      rcuentas.write(reinterpret_cast<char *>(&aux),sizeof(Cuenta)); 
      bcuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta)); 
     } 
     rcuentas.close(); 
     bcuentas.close(); 
     ofstream rclientes("clientes.bin",ios::out | ios::trunc | ios::binary); 
     ifstream bclientes("clientes_rep.bin"); 
     bclientes.read(reinterpret_cast<char *>(&c),sizeof(Cliente)); 
     //pesky part 
     while(!bclientes.eof()){ 
      rclientes.write(reinterpret_cast<char *>(&c),sizeof(Cliente)); 
      bclientes.read(reinterpret_cast<char *>(&c),sizeof(Cliente));         
     }        
     //end of pesky part 
     bclientes.close(); 
     rclientes.close(); 
     cout << endl << "Modificacion Realizada con Exito" << endl; //confirmation text 
    } 
} 

在你需要它的情況下,這是寫一個新條目的功能,它完美罰款:

void crearCuenta(){ 
    Cuenta aux; 
    aux.setnumCuenta(0); 
    ifstream rcuentas("cuentas.bin"); 
    if(!rcuentas){ 
     cout<< endl <<"Primer uso del Sistema detectado, generando numero de cuenta inicial" <<endl; 
    } 
    else { 
     rcuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta)); 
     while(!rcuentas.eof()){ 
      rcuentas.read(reinterpret_cast<char *>(&aux),sizeof(Cuenta)); 
     } 
     rcuentas.close(); 
    } 
    Cuenta cu;   
    cu.setnumCuenta(aux.getnumCuenta() + 1); 
    int num_duenhos = 0; 
    ofstream a_clientes("clientes.bin",ios::app |ios::binary); 
    while(true){ 
     char dni[10]; 
     cout << "Ingrese el DNI del Duenho: "; //new dni 
     Cliente c; 
     cin >> c.dni; 
     cout << "Ingrese el Nombre del Duenho: "; //new name 
     cin >> c.nombre; 
     c.numCuenta = cu.getnumCuenta(); 
     num_duenhos++; 
     a_clientes.write(reinterpret_cast<char *>(&c),sizeof(Cliente)); 
     cout << "Desea ingresar otro duenho? (escriba 1 para confirmar): "; //another entry? 
     int val; 
     cin >> val; 
     if (val != 1) 
      break; 
    } 
    cu.setnumDuenhos(num_duenhos); 
    while(true){ 
     double monto; 
     cout << endl; 
     cout << "Ingrese el monto con el cual iniciara la cuenta:"; //numerical value (greater than 100) 
     cin >> monto; 
     if (monto < Cuenta:: MONTO_MIN){ 
      cout << "Debe ingresar un valor mayor a " << Cuenta::MONTO_MIN << endl; 
     } 
     else{ 
      cu.setMonto(monto - monto * 0.005); 
      break; 
     } 
    } 
    ofstream acuentas("cuentas.bin",ios::app| ios::binary); 
    if(!acuentas){ 
     cout<< endl <<"ERROR en la fila secuencial" <<endl; 
    } 
    else{ 
     acuentas.write(reinterpret_cast<char *>(&cu),sizeof(Cuenta)); 
     acuentas.close(); 
    } 
    cout << "Cuenta Guardada Satisfactoriamente con número: " << cu.getnumCuenta() << endl; //confirmation text 
} 

不介意西班牙文本,它只是用於用戶通信。任何幫助將不勝感激

+3

您需要本地化問題,或至少嘗試。對於一個SO問題,IMO太長了。 – 2011-06-02 16:23:14

+0

您應該從一個無需修改即可讀寫的程序開始。第一個錯誤是在這個函數中。只有當這部分工作完美時,你應該添加代碼來修改數據。 – Beta 2011-06-02 16:28:48

+0

此外,不是將輔助文件中的數據複製到原始文件,而是刪除原始文件並重命名輔助文件。其實,保持原來的和輔助的,直到輔助是正確的。 – MRAB 2011-06-02 16:50:52

回答

2

對於初學者,你不打開輸入二進制模式,所以除非你在Unix下 ,你不會看到磁盤上的文件的字節圖像。 如果我理解正確,那麼您希望閱讀使用相同程序編寫的文件 ;如果是這樣,在不同的 模式下閱讀和寫作將無法正常工作。

其次,你讀,寫複雜的數據結構(CuentaCliente)使用istream::readostream::write。這不是 工作,除少數情況下。無論是二進制還是文本,所有文件 都有一種格式,並且此格式必須在代碼中得到遵守。您的 課程要麼是POD,要麼接近一個,您可能不會 看到問題,直到您在開發 環境中進行了一些更改,但仍然存在。 (事實上​​,你需要一個 reinterpret_cast這樣做應該是一個紅色的標誌在這裏)。它肯定不會工作 (Unix下除外),如果你在文本模式下讀或寫。在文本模式下讀取以這種方式寫入的文件 將返回其他字符,或在Windows下在文件結尾之前停止 。

另外,while (file.eof())而不是正確的方法來讀取文件。直到輸入 失敗後,file.eof()的 結果纔可靠。對於文本文件,你通常會使用:

while (file >> something) ... 

while (std::getline(file, line)) ... 

閱讀爲你做什麼,

while (rep_clentes.read(...)) ... 

應該工作,只要你解決問題的其餘部分。 這可能是你無限循環的原因; istream在 出於某種原因而不是文件結尾的錯誤狀態,所以eof()將 永遠不會成爲真。

+0

好吧,這種使用reinterpret_cast的形式和寫作和閱讀的形式是從課程老師給出的一些示例文件中獲得的;但這些例子更簡單。經過調整,你建議該計劃仍然無法正常工作。我只是通過限制請求發送相應的投訴來調用該程序是不可能的。感謝您的支持 – 2011-06-02 18:50:57