feof กับ ferror function ที่ใช้อ่าน file ใน standard library ของภาษา C มีอยู่ด้วยกันหลาย function แต่ function เหล่านี้จะไม่สามารถแยกความแตกต่างระหว่าง end-of-file กับการเกิด error ได้ ตัวอย่างของ function เหล่านี้คือ int fgetc (FILE *stream); int getc (FILE *stream); int getchar (void); จะ return EOF เมื่อเจอ end-of-file หรือเมื่อเกิด error char *fgets (char *s, int n, FILE *stream); char *gets (char *s); จะ return NULL เมื่อเจอ end-of-file หรือเมื่อเกิด error int fscanf (FILE *stream, char *format, ... ); int scanf (char *format, ... ); จะ return EOF เมื่อเจอ end-of-file หรือเมื่อเกิด error size_t fread (void *ptr, size_t size, size_t nitems, FILE *stream); จะ return ค่าไม่เท่ากับ nitems เมื่อเจอ end-of-file หรือเมื่อเกิด error การที่จะแยกให้ได้ว่าเกิด end-of-file หรือเกิด error ต้องใช้ feof กับ ferror ครับ int feof (FILE *stream); int ferror (FILE *stream); เมื่อเกิด error ในการอ่าน FILE *stream การเรียกใช้ ferror (stream) จะ return ค่าเป็น non-zero ทำนองเดียวกัน เมื่ออ่าน FILE *stream จนเจอ end-of-file การเรียกใช้ feof (FILE *stream) จะ return ค่าเป็น non-zero function ทั้งสองจะมีลักษณะเหมือนกันคือ ต้องเกิด เหตุ ขึ้นเสียก่อน แล้วถึงจะทดสอบเจอ หาก เหตุไม่เกิด ก็ทดสอบไม่เจอ สำหรับ ferror คงไม่ค่อยมีปัญหา (อาจเป็นเพราะไม่ค่อยเห็นใช้กัน) แต่ feof นี่ผมเห็นใช้ผิดกันบ่อยๆ เพราะว่ามันต้องอ่านจนเจอ end-of-file ถึงจะใช้ feof ทดสอบได้ แต่ที่เห็นใช้กันผิด คือไปทดสอบ feof ก่อน แล้วค่อยไปอ่าน stream เช่น while (!feof(fp)) { c = getc(fp); putchar(c); } เพราะว่าถึงอ่าน byte สุดท้ายของ file ไปแล้ว คืออยู่ที่ท้าย file ไม่มีข้อมูลแล้ว แต่ว่าตัว library function มันยังไม่รู้นะครับว่าไม่มีข้อมูลแล้ว เราต้องสั่งให้อ่านต่อไป มันถึงจะรู้ว่าไม่มีข้อมูลแล้ว เจอ end-of-file แล้ว feof ถึงจะทดสอบเจอ มาทดสอบกันโดยสร้าง file ที่มีหนึ่งตัวอักษร แล้วลองอ่าน file โดยใช้โปรแกรมที่ผิดแบบข้างบน เปรียบเทียบกับโปรแกรมที่เขียนถูก #include <stdio.h> #define TEST_FILE "test.dat" int main () { int c; FILE *fp; puts("Create file contains one character"); fp = fopen(TEST_FILE, "w"); if (fp == NULL) { perror("fopen w"); return -1; } putc('A',fp); fclose(fp); puts("Bad feof program"); fp = fopen(TEST_FILE, "r"); if (fp == NULL) { perror("fopen r"); return -1; } while (!feof(fp)) { c = getc(fp); printf("%c(%d)\n", c, c); } fclose(fp); puts("Good program"); fp = fopen(TEST_FILE, "r"); if (fp == NULL) { perror("fopen r"); return -1; } while ((c = getc(fp)) != EOF) printf("%c(%d)\n", c, c); fclose(fp); puts("End"); getchar(); return 0; } ผลลัพธ์ที่ได้คือ Create file contains one character Bad feof program A(65) (-1) Good program A(65) End จะเห็นว่า feof จะทดสอบไม่เจอ end-of-file มันเลยอ่านเกินไปตัวนึง แล้วควรใช้งาน feof ยังไง คำตอบคือ ให้ใช้เท่าที่จำเป็น จะเห็นว่าในโปรแกรมทดสอบอันที่ถูกของผม ไม่ใช้ feof ด้วยซ้ำ เพราะมันไม่จำเป็นต้องใช้ ที่ผิดกันบ่อยคือใช้ feof เป็น loop condition ทั้งที่จริงๆเราก็ loop อ่านจนมันอ่านไม่ได้แหละครับ ไม่ว่าจะอ่านไม่ได้เพราะ end-of-file หรือ error ไม่เห็นต้องใช้ feof เลย หลังออกจาก loop แล้วถ้าอยากรู้ว่า error หรือเปล่าค่อยไปใช้ ferror เช่น while ((c = getc(fp)) != EOF) printf("%c(%d)\n", c, c); if (ferror(fp)) perror("getc"); สรุปว่าใช้แบบพอเพียงครับ สวัสดีครับ ขอบคุณสำหรับความรู้ดี ๆ ครับ ช่วงนี้ไม่ค่อยได้ใช้ภาษาซี ใช้แต่ Java เป็นหลัก ได้เข้ามาอ่านก็ดหมือนได้ทบทวนภาษาซีไปในตัว
โดย: motokop วันที่: 10 ตุลาคม 2552 เวลา:22:38:44 น.
สวัสดีครับ มาทักทายกันวันศุกร์ แต่ต่อไปสงสัยจะได้ทักทายกันทาง twitter อีกทางหนึ่งด้วย
โดย: motokop วันที่: 16 ตุลาคม 2552 เวลา:20:30:29 น.
โดย: motokop วันที่: 31 ธันวาคม 2552 เวลา:14:37:12 น.
ถ้าต้องใช้ feof จริงๆ
ต้องใช้ยังไงดีครับ โดย: prikthai IP: 202.12.74.1 วันที่: 14 มกราคม 2554 เวลา:18:19:14 น.
|