2015-04-07 11 views
2

我創建了一個空文件,我正在嘗試調整它。除了開放模式外,我的調整大小和創建代碼非常相似。初始創建按預期工作。調整大小的代碼執行得很好,但文件調整大小沒有反映出來。文件大小不反映使用std :: filebuf

這裏是我的代碼:

void resize() 
{ 
    std::filebuf fileBuffer; 
    fileBuffer.open(filePath, ios::out | ios::binary | ios::app); 
    if (fileBuffer.is_open()) 
    { 
     fileBuffer.pubseekoff((2 * fileSize) - 1, ios::beg); 
     auto x = fileBuffer.sputc(0); 
     fileBuffer.close(); 
    } 
} 

int main() 
{ 
    std::filebuf fileBuffer; 
    fileBuffer.open(filePath, ios::out | ios::trunc | ios::binary); 
    if (fileBuffer.is_open()) 
    { 
     fileBuffer.pubseekoff(fileSize - 1, ios::beg); 
     fileBuffer.sputc(0); 
     fileBuffer.close(); 
    } 
    resize(); // Doesn't work 

    resizeWithData(); // Works 
} 

當我嘗試調整推實際數據成其爲下圖所示的文件,它的工作原理:

void resizeWithData() 
{ 
    ofstream fstr(filePath, ios::out | ios::binary | ios::app); 
    if (fstr.is_open()) 
    { 
     const auto emptySec = make_unique<char[]>(fileSize); 
     memset(emptySec.get(), 0, fileSize); 
     fstr.write(emptySec.get(), fileSize); 
     fstr.close(); 
    } 
} 

爲什麼這種差異?我的實際情況涉及創建和調整真正的大文件(1 GB或更多),所以我希望我可以避免爲空數據分配內存,如上面的代碼所示(因爲它真的很慢)如果可能的話

PS:我正在使用VS2013更新4上的windows 7 7

+0

但是,如果是這樣的話,爲什麼獨創的文件,而無需實際把這些有多少位工作? – Arun

+0

爲什麼你使用'std :: file_buf'而不是'std :: fstream'? cppreference說mehtod的基本版本沒有效果。請參閱http://en.cppreference。COM/W/CPP/IO/basic_streambuf/pubseekoff。 – Lingxi

+1

@靈溪不,'std :: basic_streambuf :: pubseekoff'沒有效果;但是他調用了'std :: basic_filebuf :: pubseekoff',但是這個被覆蓋。 – edmz

回答

1

原因resize()失敗是因爲您已在app模式下打開文件。每次寫入此流時,實現都會將寫入位置重新同步到文件末尾。撥打pubseekoff本身的電話seekoff(根據fseek定義)不會寫任何內容,它只是重新定位文件位置指示符。

正如你在main打開的文件中可以看出,沒有app標誌sputc會立即寫入到當前位置,雖然這可能不是嚴格的保證。

大多數basic_filebuf操作都是根據C文件函數定義的,這些函數似乎沒有提到當文件位置指示符超出文件末尾時調用fputc時會發生什麼情況。然而,POSIX清楚地表明,這將寫入零位,並且您可能會發現大多數實現將支持此定義。

+0

我在一分鐘之內看到我們得到了相同的結論,但是我找不到任何可能的狀態,將會寫入空字符。只有從已創建的間隙中讀取才會返回「零」。你能否提供說明它被寫入的源代碼?我發現很奇怪的是'append'和'truncate'的行爲有所不同。 – luk32

+0

@ luk32空字符的值保證爲0,所以它是一樣的,雖然POSIX標準確實提到了0我想。 – user657267

+0

@ luk32另外我不認爲這是'trunc'和'app'之間的區別問題,如果你認爲'app'將總是強制寫入位置與實際文件的末尾同步, 。 – user657267

1

區別在於,在第一個示例中截斷了該文件。如果在resize中將ios::app更改爲ios::trunc,則文件將具有所需的大小(至少在我的系統上)。有趣的是,在標準中,我無法找到它應該如何表現的聲明,只是一些聲明,它在C風格的API中表現爲等同的調用。而對於C風格的API,我只在cpp reference上發現以下注意事項:

POSIX允許在現有文件結尾之外尋找。如果在此查找後執行輸出,則從間隙讀取的數據將返回零字節。在文件系統支持的地方,這將創建一個稀疏文件。

IMO,最後你的fileBuffer.pubseekoff(fileSize - 1, ios::beg);調用也可能失敗。

但是,分配1GB的零來轉儲它們到文件中是浪費。我會用反覆寫入調用的緩衝區:

#include <fstream> 
#include <iostream> 
#include <array> 

using std::ios; 

std::string filePath("test.file"); 
size_t fileSize = 1024*1024; 

void resize(const std::string& path, std::size_t newSize){ 
    const std::size_t buffSize = 1024*1024; 
    std::array<char, buffSize> buff{}; 
    std::filebuf fileBuffer; 

    fileBuffer.open(path, ios::out | ios::binary | ios::app); 

    auto reminder = newSize - fileBuffer.pubseekoff(0, ios::cur); 
    while(reminder > buffSize){ 
    fileBuffer.sputn(buff.data(), buffSize); 
    reminder -= buffSize; 
    } 
    fileBuffer.sputn(buff.data(), reminder); 

    fileBuffer.close(); 
} 

int main() 
{ 
    std::filebuf fileBuffer; 
    fileBuffer.open(filePath, ios::out | ios::binary | ios::trunc); 
    if (fileBuffer.is_open()) 
    { 
    fileBuffer.pubseekoff(fileSize - 1, ios::beg); 
    fileBuffer.sputc(0); 
    fileBuffer.close(); 
    } 
    resize(filePath, 3500000); 
} 
相關問題