2017-06-13 53 views
1

我將一個文件轉換爲String。msync的'length`參數不起作用

int fd = open(FILE_PATH, O_RDWR); 
struct stat s; 
int status = fstat(fd, &s); 
char *f = (char*) mmap (0, s.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 

然後我cJSON解析f並做一些修改。

cJSON *root = cJSON_Parse(f); 
//some JSON operation 

完成後,我從cJSON重新生成字符串,並嘗試將其寫回到磁盤。

char* rendered = cJSON_Print(root); 
memcpy(f, rendered, strlen(rendered)); 
msync(f, strlen(renderer), MS_SYNC); 

mmap或msync中沒有錯誤。

我檢查了文件內容,發現它正確地改變了,因爲我使用cJSON庫進行了修改。

但是,該文件沒有完成。更具體地說,它寫回磁盤的大小(我使用Sublime進行檢查)不是我在msync的參數length中輸入的大小, strlen(rendered),但文件的原始大小,即strlen(f)

然後我試圖通過512128硬編碼地分配length或其他,但我發現它們都不起作用。從mmap回寫到文件的大小仍然是mmaped字符的原始大小。

msync手冊中,它說:

對應於存儲區開始於addr和具有長度的長度被更新的文件的一部分。

所以我感到困惑,誰能告訴我如何分配地址的長度我想刷新到磁盤?

+0

'msync'不能更改底層映射的大小。您只有'mmap'原始文件大小,並且不能通過映射的地址更改大小。 – kaylum

+0

對磁盤的讀/寫操作是以塊爲單位執行的,而mmap()是在讀/寫的基礎上構建的。歷史上的塊大小是512字節,今天它通常是4096字節。你不能寫一個分塊。 (您可以截斷文件,在這種情況下,只有最後一個塊的一部分將*可見*) – joop

+0

您引用的msync手冊頁中的「更新」是指「與存儲區域對應的文件部分」並不涉及更新長度。 – kaylum

回答

0

感謝在評論中鼓舞我的人,對不起,我對手冊做了一個糟糕的閱讀。

msync無法擴展您映射的大小,也不能mmap以上的文件大小都不是。

所以這裏的理念是:

  1. 增加文件大小
  2. 取消映射
  3. remmap
  4. 的msync重新映射f控制新的內容

那裏爲我實現了resize_remap功能

result_t file_remap_resize(int* fd, char** f, int new_size){ 
    if(ftruncate(*fd, new_size) == -1){ 
     printf("failed to resize\n"); 
     return ERR_CODE; 
    } 
    if(munmap(*f, sizeof(*f)) == -1){ 
     printf("failed to unmap\n"); 
     return ERR_CODE; 
    } 
    *f = (char*)mmap (0, new_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
    if(!f){ 
     printf("failed to remap\n"); 
     return ERR_CODE; 
    } 
    return SUCCESS 
} 

然後程序是這樣的:

char* rendered = cJSON_Print(root); 
file_remap_resize(&fd, &f, strlen(rendered)); 
memcpy(f, rendered, strlen(rendered)); 
msync(f, strlen(renderer), MS_SYNC); 

和它的作品!

修改過的文件可以刷新到磁盤中!