C_and_CPP 板


LINE

原文在這 #1DyUBD7Q (C_and_CPP) http://webptt.com/m.aspx?n=bbs/C_and_CPP/M.1307697869.A.1DA.html 都翻起舊文了,給個機會,澄清一下。 我先自首件事,這篇文當初我只有小提 fread + strchr 可以達成 較穩定的需求,會這麼說是有個專案 BUF_SIZE 設 32767 , 結果 fgets 檔案有一行真的 overflow。 我必須強調,當初講的 fgets / fread + strchr / fgetc 等方式, 其實都沒考慮到檔案編碼、多國語系問題,然後 fread + strchr 只 是小提一下,當時實作上是順手寫的,這次將它完善。 ※ 引述《gary8520 (元丁)》之銘言: : 小弟學C不久,非資工人, : 正在寫一個小程式需要讀數十行,每行字元十個左右的資料。 : 想瞭解BUF_size大約要怎麼取, : 小小測試了一下, : 我使用動態記憶體配製決定BUF_SIZE的大小(用for迴圈跑), : 並算出line_cut。 : ※ 引述《tropical72 (藍影)》之銘言: <............恕刪............> : : ---------- : : step 4: 用 fread 進行 : 計算結果輸出為line_cnt4 : 這似乎就要看BUF_SIZE的大小… <............恕刪............> : 只要bufsize一改,這個方法算出來的結果就會不同? : 說實在話我不知道為什麼,也想不出來為什麼"Orz : 所以,若要像我讀小筆資料,step3的方法似乎是比較適當的。 ^^^^^^^^^^^^ 就是 fgets 一般而言,不論檔案大小,大多做法都是用 fgets 去做,因很少有機會會遇到 存文字檔,一行很長的(正確的說,很少情況會遇到純文字檔會寫很大的,寫大 的話到後來都是用 binary mode 寫入),所以 buf_size 設大一點就沒事了, 一般我是直接給 BUFSIZ * 4 ,我手邊 compiler BUFSIZ 是給 512 。 --------------------- 原 source code 有問題的 重點如下 while(BUF_SIZE==fread(buf, 1, BUF_SIZE, fp)){ ptr = (char*)strchr(buf, '\n'); /* 這裡還有個 issue 要修正 */ while(ptr!=NULL){ ++line_cnt; ptr = (char*)strchr(ptr+1, '\n'); } } 關鍵其實在於 fread 傳回值 ,代表成功從檔案讀取了幾個 bytes , 原本是只考慮成功讀取了 BUF_SIZE bytes 時才繼續往下做 , 想一下 如果檔案有 351 bytes, 每次讀 100 bytes , 最後會有 51 bytes 會 被丟掉,所以判斷式不該那麼下 [Lemma],要簡單的話是只要 fread 傳回值是非 0 就直接往下做。 然後考慮一下最後一次 fread 的情況,假設 BUF_SIZE = 100 , 但只讀 了 51 bytes , 這時候 buf 後面的 49 bytes 都不會被清 0 , 意思是說 如果 buf 後 49 bytes 裡面有 '\n' 的話就會被重覆計算, 所以在做 string search 之前要再塞個結束字元。 整個可以 run 的 code 如下。 #include <stdio.h> #include <stdlib.h> #include <string.h> enum {LINE_CNT = 150, BUF_SIZE = 20}; const char * FILENAME = "tst.txt"; int main() { FILE * fp ; char * ptr; char buf[BUF_SIZE+1] ; // +1 : 加上結束字元 size_t read_bytes , line_cnt = 0; fp = fopen(FILENAME, "rb"); // no error defect while(read_bytes = fread(buf, 1, BUF_SIZE, fp)) { // read_bytes==0 時結束 buf[read_bytes] = '\0'; ptr = (char*)strchr(buf, '\n'); while(ptr!=NULL) { ++line_cnt; ptr = (char*)strchr(ptr+1, '\n'); } } fclose(fp); printf("line_cnt = %d\n", line_cnt); return 0; } 然後整個 fread + strchr , 其實可用 fread + memchr 做 , memchr 速度應會比 strchr 還快一點點 , 這裡就不再示範。 [Lemma] 當初之所以會用 while(BUF_SIZE==fread(buf, 1, BUF_SIZE, fp)) , 是因為不想在 while loop 裡面做很多事,想單純化,最後沒讀滿 BUF_SIZE 的是跳出 loop 之後再獨立做,速度估會較快。 -- ~ 這輩子與神手無緣 我只好當神獸了 ~ 卡卡獸 --



※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.74.188
1F:→ Feis:個人認為可以的話應該還是不要用 fgets 02/02 20:20
2F:→ Feis:此外 gary8520 的 code 應該跟原本的 code 也不同~ 02/02 20:23
3F:→ EdisonX:個人認為 fgets 是在 c-style 開發下的捷徑,要正確的話當 02/02 20:48
4F:→ EdisonX:然它不會是首選,ifstream 比它正確,但相對的速度慢,不好用 02/02 20:49
5F:→ Feis:喔. 沒有. 是我剛想錯了 :P 02/02 20:57
6F:→ Feis:我想表達的是如果有極小的機率造成錯誤就別用 02/02 20:59
7F:→ Feis:不是 fgets 本身的問題. 而是原文的用法 02/02 21:01
8F:→ EdisonX:了解, 謝謝 :D 02/02 21:01
9F:推 gary8520:其實我那個code基本上是複製t大的,只是加了一些宣告之類 02/02 21:12
10F:→ gary8520:忘了謝謝E大大 02/02 21:14
11F:→ EdisonX:嗯,所以可能你沒了解 bufsize 的含意吧,導致 fgets 有問題 02/02 21:14
12F:推 gary8520:我自認為我應該知道fgets那個方法,只要bufsize夠大,能 02/02 21:18
13F:→ gary8520:讀完一整行,其實fgets應該就可以跑出正確的結果。 02/02 21:18
14F:→ EdisonX:嗯,那是我誤會你了. 附一提, edisonx==tropical72 . 02/02 21:21
15F:→ Feis:@gary8520: 你的 code 我覺得一定有什麼神祕力量. 建議貼一下 02/02 21:25
16F:→ purincess:t大魂魄不散 (? 02/02 22:14
17F:→ EdisonX:嗯... 還剩一口氣 Orz 02/02 22:18
18F:→ freaky:如果只給Windows用,CreateFile/ReadFile是你的好朋友。 02/02 22:43
19F:→ freaky:先GetFileSizeEx()再看你要怎麼分段或一次讀完都可以。 02/02 22:45
20F:→ freaky:可以從32Kb buffer大小開始測讀取速度。 02/02 22:51
21F:→ freaky:讀大檔案memory-mapped file更快。 02/02 22:52







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:BabyMother站內搜尋

TOP