2014-10-01 93 views
0

我目前正試圖實現一個功能,刪除已保存在二進制文件中的特定結構。我對如何去做有點困惑。我有一個解決方案,但不會特別優雅:我可以將結構的整個文件讀取到一個結構向量中,刪除舊文件,刪除要從該向量中移除的結構,然後保存結構向量作爲文件再次。我非常有信心,這將工作,但如果文件很大,這似乎是一個漫長的,也許是不必要的解決方案。我知道如何找到我想要刪除的結構,並且我知道如何更改其中的值(通過覆蓋它),但我怎樣才能刪除它?從C++中的二進制文件中刪除結構

這是我救我的結構:

std::fstream binary_file(fileLocation.c_str(), std::ios::out | std::ios::binary | std::ios::app); 
binary_file.write(reinterpret_cast<char *>(&myStruct), sizeof(myStruct)); 
binary_file.close(); 

每個結構都有其獨特的ID整數,我用它來尋找合適的結構,像這樣:

myStream.open(fileLocation.c_str(), std::ios::in | std::ios::out | std::ios::binary); 
    while (!myStream.eof()) 
    { 
     myStream.read(reinterpret_cast<char*>(&myStruct), sizeof(myStruct)); 
     if (myStruct.ID == given_ID) 
     { 
      temp_fstream.seekg(-(sizeof(myStruct), std::ios::cur); 
      //delete struct 
      return; 
     } 
    } 

我不知道該怎麼辦,這甚至有可能嗎?我玩弄了將結構標記爲無效的想法,所以即使我的程序會讀取它,它也不會將它用於任何事情,但再次,似乎是一個可憐的主意。

有什麼建議嗎?

+0

通常的解決方案是複製,跳過你不想複製的內容。但是你的閱讀循環被破壞了;在使用結果之前,您不會驗證您的讀取是否成功。 (當然,如果你用這種方式寫這個文件,幾乎可以保證將來有一段時間,你將無法閱讀它。) – 2014-10-01 17:20:28

回答

2

您可以在沒有刪除項目的情況下重新創建文件,但是這樣效率非常低。

這裏需要的是一些更多的參與。例如,你可以想出一個的系統標記一個結構爲刪除。您的代碼需要在該位置寫入一些特殊值,以便知道它已被刪除,然後在保存另一個結構時重新使用該位置。

這會增加代碼的複雜性。您將無法簡單地在單個語句中讀取和寫入一組結構。

這種方法有許多變化。確切的代碼需要一種取決於你的應用程序。

+0

我想我會用這個解決方案從衆多的這裏的答案,只是因爲我認爲它適合我的需要最好的。我會不斷刪除元素並將新的元素寫入文件,這是一種恥辱,我不再能夠在編寫新元素時追加,但希望它能運行 – user3932479 2014-10-01 18:12:45

+0

如果正確實施,這條路線應該會給你最棒的表演。 – 2014-10-01 18:15:48

+0

@ user3932479如果你的結構體的大小都是固定的,順序無關緊要,那麼可以很容易地重新填充未使用的空間。 FWIW,mmap也同樣適用於這種情況,根據我的經驗,stdio或stream的性能改進是驚人的。 – Alnitak 2014-10-01 18:22:07

2

一個潛在的非常快速的方法,如果該文件不超過可用RAM較大的是使用mmap

  1. mmap文件
  2. 發現問題
  3. memmove一切結構的存儲位置在該位置上方向下按結構尺寸
  4. munmap該文件。
  5. ftruncate文件到新的長度
0

我不知道如果我理解正確的話......不過,你可以得到該結構(找到它的二進制文件),複製所有字節,直到該位置,跳過下一個sizeof(該結構)字節,並將其餘的二進制文件複製到該新文件?

0

假設所有struct s文件中是相同的尺寸和類型,順序並不重要,這裏的算法是什麼樣子:

  1. 找到struct被刪除,請記住它的位置
  2. 查找文件
  3. 複製最後一個struct最後struct的內容到由一個佔用的空間將被刪除
  4. 無論是墊文件或者我們結束E專用操作系統的功能(truncate()在Unix上,SetEndOfFile()在Windows上)

AFAIK有縮小文件的大小,所以你必須使用特定於平臺的東西,對於部分沒有與平臺無關的方式。