如何將乙個10G的檔案逆序寫入乙個新的檔案

2021-09-24 07:16:54 字數 3488 閱讀 2926

最近的同事的組內分享的內容就是標題的內容,這是一道大資料處理的演算法的經典面試題,以前也經常碰到,用到的是mmap的知識,了解過,但是沒有自己實際去寫過。趁這個機會,就再一次回顧下,用swift來實現一把。

特權級, 使用者態,核心態,使用者空間,核心空間,執行緒上下文,中斷上下文, mmu等概念請參考下文

linux一些概念

mmap分析

由於指定資料的內容比較大,所以我們不能直接通過read,write的方式將大檔案直接讀入內容,因為這樣記憶體會不夠用,所以我們需要借助linux中的mmap的知識,進行記憶體對映。

mmap的工作原理,當你發起這個呼叫的時候,它只是在你的虛擬空間中分配了一段空間,連真實的實體地址都不會分配的,當你訪問這段空間,cpu陷入os核心執行異常處理,然後異常處理會在這個時間分配物理記憶體,並用檔案的內容填充這片記憶體,然後才返回你程序的上下文,這時你的程式才會感知到這片記憶體裡有資料

void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);

具體引數含義

length: 代表將檔案中多大的部分對映到記憶體。

prot : 對映區域的保護方式。可以為以下幾種方式的組合:

prot_exec 對映區域可被執行

prot_read 對映區域可被讀取

prot_write 對映區域可被寫入

prot_none 對映區域不能訪問

flags : 影響對映區域的各種特性。在呼叫mmap()時必須要指定

map_shared 或map_private。

map_fixed 如果引數start所指的位址無法成功建立對映時,則放棄對映,不對位址做修正。通常不鼓勵用此旗標。

map_shared 對對映區域的寫入資料會複製回檔案內,而且允許其他對映該檔案的程序共享。

map_private 對對映區域的寫入操作會產生乙個對映檔案的複製,即私人的「寫入時複製」(copy on write)對此區域作的任何修改都不會寫回原來的檔案內容。

map_anonymous建立匿名對映。此時會忽略引數fd,不涉及檔案,而且對映區域無法和其他程序共享。

map_denywrite只允許對對映區域的寫入操作,其他對檔案直接寫入的操作將會被拒絕。

map_locked 將對映區域鎖定住,這表示該區域不會被置換(swap)。

fd : 要對映到記憶體中的檔案描述符。如果使用匿名記憶體對映時,即flags中設定了map_anonymous,fd設為-1。有些系統不支援匿名記憶體對映,則可以使用fopen開啟/dev/zero檔案,

然後對該檔案進行對映,可以同樣達到匿名記憶體對映的效果。

offset:檔案對映的偏移量,通常設定為0,代表從檔案最前方開始對應,offset必須是page_size的整數倍。

複製**

錯誤**: ebadf 引數fd 不是有效的檔案描述詞 eacces 訪問許可權有誤。如果是map_private 情況下檔案必須可讀,使用map_shared則要有prot_write以及該檔案要能寫入。 einval 引數start、length 或offset有乙個不合法。 eagain 檔案被鎖住,或是有太多記憶體被鎖住。 enomem 記憶體不足。

使用者層的呼叫很簡單,其具體功能就是直接將物理記憶體直接對映到使用者虛擬記憶體,使使用者空間可以直接對物理空間操作。但是對於核心層而言,其具體實現比較複雜。

通過mmap對映出來的記憶體,通過munmap來解除對映關係

int munmap( void * addr, size_t len )

在程序位址空間中解除乙個對映關係,當對映關係解除後,對原來對映位址的訪問將導致段錯誤發生。

size_t len :對映區的大小

複製**

int msync ( void * addr , size_t len, int flags)

一般說來,程序在對映空間的對共享內容的改變並不直接寫回到磁碟檔案中,往往在呼叫munmap()後才執行該操作。可以呼叫msync()實現磁碟上檔案與共享記憶體區的內容一致。

size_t len :對映區的大小

int flags :ms_asyn: 非同步寫,ms_syn : 同步寫,ms_invalidat : 無效的cache 資料。

複製**

具體**如下

func

handlefile()

let leftbuf = malloc(int(leftsize))

memcpy(leftbuf, leftpart, int(leftsize))

var data = data.init(bytes: leftbuf!, count: int(leftsize))

data.reverse()

fhout?.write(data)

fhout?.synchronizefile()

munmap(leftpart, int(leftsize))

free(leftbuf)

print("剩餘部分寫入成功")

// 多執行緒處理大小的記憶體,加快處理速度

let queue = operationqueue.init()

queue.maxconcurrentoperationcount = 5

// 設定最大併發數,執行緒太多,因為執行緒切換,速度反而也降低

// 使用訊號量,防止資源寫入的時候,多執行緒seek檔案的問題

let semaphore = dispatchsemaphore.init(value: 1)

// 從第0到count段資料,分別寫入檔案的相應位置

for i in

0..let buf = malloc(int(mem_size))

memcpy(buf, part, int(mem_size))

var data = data.init(bytes: buf!, count: int(mem_size))

data.reverse()

free(buf)

semaphore.wait() // 搶占訊號資源

fhout?.seek(tofileoffset: leftsize + mem_size * (count - i - 1))

fhout?.write(data)

fhout?.synchronizefile()

semaphore.signal() // 釋放訊號資源

munmap(part, int(mem_size))

print("操作成功 i= \(i)")}}

//等佇列中所有操作結束,才能執行後面的close控制代碼的操作

queue.waituntilalloperationsarefinished()

fhin?.closefile()

fhout?.closefile()

}複製**

如何將乙個PHP陣列有格式的寫入檔案中

如何將 array k1 v1,k2 v2 這個陣列寫入乙個檔案,檔案裡面的內容和下面這種格式基本一致 array k1 v1,k2 v2 不要和我說一行行寫,有沒有快捷一點的方法?鏈結cuimingda 22 2012年11月18日提問 得票數時間先後 0贊踩採納 file put content...

python 如何將字典值寫入乙個文字檔案?

我有乙個字典,我打算把它寫入乙個檔案。exdict with open file.txt r as file file write exdict 我遇到了這樣的錯誤 file write exdict typeerror must be str not dict我修復了剛才的錯誤 exdict wi...

如何將多個excel檔案合成乙個檔案

1.需要把多個excel表都放在同乙個資料夾裡面,並在這個資料夾裡面新建乙個excel。2.用microsoft excel開啟新建的excel表,並右鍵單擊sheet1,找到 檢視 單擊進去。進去之後就看到了巨集計算介面。3.然後把下面這些巨集計算的 複製進去,然後找到 工具欄上面的 執行 下的 ...