標籤:des style blog http 使用 os strong 檔案
轉載請註明出處:http://blog.csdn.net/suool/article/details/38129201
問題引入
檔案的種類
根據資料存放區的方式不同,可以將檔案分為文字檔和二進位檔案.具體的區別和關係如下:
文字檔與二進位檔案在電腦檔案系統中的實體儲存體都是二進位的,也就是在實體儲存體方面沒有區別都是01碼,這個沒有異議,他們的區別主要在邏輯儲存上,也就是編碼上。
文字檔格式儲存時是將值作為字元然後存入其字元編碼的二進位,文字檔用‘字元’作為單位來表示和儲存資料,比如對於1這個值,文字檔會將其看做字元‘1’然後儲存其ASCII編碼值(這裡假定是ASCII編碼),這樣在物理上就是0x31這個二進位值,而若是二進位儲存1,則直接儲存其二進位值,比如如果程式中是處理1為整數則儲存的二進位值就是 0x00000001 (4位元組)。
當然如果程式本來就是按字元儲存的 也就是 char ch =‘1‘ ;則二進位儲存後值就是其ASCII碼,因為該變數的二進位本來就是其ASCII碼。可以總結出二進位檔案就是值本身的編碼,那麼就是不定長的編碼了,因為值本身就是不等位元組的,如整數4個位元組那麼儲存在二進位檔案就是這四個位元組的原生二進位值。
綜上,可以知道文字檔與二進位檔案就是編碼方式不一樣而已,而這個是使用者行為,把一個資料以什麼樣的編碼(字元還是值本身)存入檔案是由使用者主動選擇的,也就是寫入的介面選擇,如果以二進位介面方式寫入檔案那麼就是一個二進位檔案,如果以字元方式寫入檔案就是一個文字檔了。既然有寫入時候的編碼也就會有讀出的編碼,只有兩個編碼對應才能讀出正確的結果,如用記事本開啟一個二進位檔案會呈現亂碼的,這裡稍微提一下尾碼名,尾碼名並不能確定其是否就是文字檔,二進位檔案也可以是txt尾碼名,尾碼名只是用來關聯開啟程式,給使用者做備忘用的,與檔案的具體編碼沒有關係。
可以使用字元介面讀寫二進位檔案,只需要做些處理即可,所以所謂的二進位檔案,文字檔主要體現在讀寫方式這裡。此外windows有一個明顯的區別是對待文字檔讀寫的時候,會將換行 \n自動替換成 \r\n。
最後文字檔和二進位檔案主要是windows下的概念,UNIX/Linux並沒有區分這兩種檔案,他們對所有檔案一視同仁,將所有檔案都看成二進位檔案。
檔案操作方式
根據應用程式對檔案的訪問方式不同,可以分為帶緩衝區的檔案操作和非緩衝檔案操作,具體區別簡單介紹如下:
緩衝檔案操作:進階檔案操作,將在使用者空間中自動為正在使用的檔案開闢記憶體緩衝區,遵循ANSI C標準的I/O函數就是緩衝檔案操作
非緩衝檔案操作:低級檔案操作,如果需要,只能由使用者自己在程式中為每個檔案設定緩衝區,遵循POSIX標準的系統調用I/O函數就是這種類型.
具體的區別見:http://www.360doc.com/content/11/0521/11/5455634_118306098.shtml
ANSI C庫函數為了實現他的特性,採用了流的概念,在流的實現中,緩衝區是最重要的單元,根據需要可以分為全緩衝,行緩衝,無緩衝.
下面就具體講一下關於ANSI C的流和檔案I/O相關的方法和函數.
問題解析關於流及其功能
在linux系統中,系統預設為每個進程開啟了三個檔案,即是每個進程可以預設操作三個流:標準輸入資料流,輸出資料流,錯誤流.
在系統源檔案中的宏定義如下:
檔案流的主要功能是:
1‘格式化內容:實現不同輸入輸出格式轉換.
2‘緩衝功能:將資料讀寫集中,從而減少系統調用次數
檔案流指標
在應用編程層面上,程式對流的操作主要是體現在檔案流指標FILE上,操作一個檔案之前,需要使用fopen開啟檔案,之後返回該檔案的檔案流指標與該檔案關聯,所有針對該檔案的讀寫操作都是通過檔案指標完成.下面是在應用程式層能夠訪問的FILE的結構體,因此結構體成員可以在使用者空間訪問:
struct _IO_FILE { int _flags; /* High-order word is _IO_MAGIC; rest is flags. */#define _IO_file_flags _flags /* The following pointers correspond to the C++ streambuf protocol. */ /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */ char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */.............. int _fileno; / 檔案描述符#if 0}
上面那個結構體中包含了I/O庫為管理該流所需要的所有資訊.
下面是列印了一個開啟的檔案流指標指標成員資訊的樣本程式,在此程式中,使用標準的C庫函數實現了檔案的複製操作,在複製過程中,即時列印當前的讀寫位置和緩衝區資訊.
代碼如下:
#include <stdlib.h>#include <stdio.h>#include <string.h>#define prt(CONTENT,MSG) printf(CONTENT":\t%p\n",MSG)int main(int argc, char *argv[]){ FILE *fp_src,*fp_des; // 檔案讀寫指標 char buffer[10],buffer1[128]; // 檔案讀寫緩衝區 int i; if((fp_src=fopen(argv[1],"r+"))== NULL) // 從第一個命令列檔案參數,讀檔案 { perror("open1"); exit(EXIT_FAILURE); } if((fp_des=fopen(argv[2],"w+"))== NULL) // 從第二個命令列檔案參數,寫檔案 { perror("open2"); exit(EXIT_FAILURE); } setvbuf(fp_src,buffer1,_IOLBF,128); // 顯式設定緩衝區的位置和類型 do { /* * 以下的prt內容均是屬於提示性內容,是讀取應用程式層所能訪問的FILE結構體得到的. */ prt("src_IO_read_ptr",fp_src->_IO_read_ptr); // 源檔案讀位置,source prt("_IO_read_end",fp_src->_IO_read_end); prt("_IO_read_base",fp_src->_IO_read_base); prt("src_IO_write_ptr",fp_src->_IO_write_ptr); prt("_IO_write_base",fp_src->_IO_write_base); prt("_IO_write_end",fp_src->_IO_write_end); prt("_IO_buf_base",fp_src->_IO_buf_base); // 源檔案緩衝區位置 prt("_IO_buf_end",fp_src->_IO_buf_end); memset(buffer,'\0',10); i = fread(buffer,1,10,fp_src); // 讀 fwrite(buffer,1,i,fp_des); // 寫 prt("des_IO_read_ptr",fp_des->_IO_read_ptr); prt("des_IO_write_ptr",fp_des->_IO_write_ptr); // 目標檔案寫位置 }while(i==10); fclose(fp_src); fclose(fp_des); // 關閉檔案讀寫}
運行結果如下:
最終成功複製.
緩衝區類型
剛剛說了三種緩衝區類型,他們依然在系統原始碼檔案有所定義.
對於標準流ANSI C有如下的要求:
1.標準輸入輸出:若且唯若不涉及互動作用裝置時,他們才是全緩衝的
2.標準錯誤:絕不會是全緩衝的
下面是用於測試緩衝區類型的樣本程式.
代碼:
#include <stdio.h>void pr_stdio(const char *, FILE *);int main(void){ FILE *fp; fputs("enter any character\n", stdout); if(getchar()==EOF) printf("getchar error"); fputs("one line to standard error\n", stderr); pr_stdio("stdin", stdin); // test for standard input stream pr_stdio("stdout", stdout); // test for standard output stream pr_stdio("stderr", stderr); // test for standard error stream if ( (fp = fopen("/etc/motd", "r")) == NULL) // 普通檔案 printf("fopen error"); if (fgetc(fp) == EOF) printf("getc error"); pr_stdio("/etc/motd", fp); return(0);}void pr_stdio(const char *name, FILE *fp){ printf("stream = %s, ", name); if (fp->_flags & _IO_UNBUFFERED) // 無緩衝 printf("unbuffered"); else if (fp->_flags & _IO_LINE_BUF) // 行緩衝 printf("line buffered"); else printf("fully buffered"); // 全緩衝 printf(", buffer size = %ld\n", fp->_IO_buf_end-fp->_IO_buf_base);}
結果如下:
指定緩衝區類型,通過sretbuf函數.其中三種緩衝的定義如下:
一個範例程式碼如下:
/* Example show usage of setbuf() &setvbuf() */#include<stdio.h>#include<error.h>#include<string.h>int main( int argc , char ** argv ){ int i; FILE * fp; char msg1[]="hello,wolrd\n"; char msg2[] = "hello\nworld"; char buf[128]; //open a file and set nobuf(used setbuf).and write string to it,check it before close of flush the stream if(( fp = fopen("no_buf1.txt","w")) == NULL) { perror("file open failure!"); return(-1); } setbuf(fp,NULL); // set the buff NULL memset(buf,'\0',128); fwrite( msg1 , 7 , 1 , fp ); // write message to file printf("test setbuf(no buf)!check no_buf1.txt\n"); printf("now buf data is :buf=%s\n",buf); // test buff printf("press enter to continue!\n"); getchar(); fclose(fp); //open a file and set nobuf(used setvbuf).and write string to it,check it before close of flush the stream if(( fp = fopen("no_buf2.txt","w")) == NULL) { perror("file open failure!"); return(-1); } setvbuf( fp , NULL, _IONBF , 0 ); memset(buf,'\0',128); // clear the buff fwrite( msg1 , 7 , 1 , fp ); printf("test setvbuf(no buf)!check no_buf2.txt\n"); printf("now buf data is :buf=%s\n",buf); printf("press enter to continue!\n"); getchar(); fclose(fp); //open a file and set line buf(used setvbuf).and write string(include '\n') to it, // //check it before close of flush the stream if(( fp = fopen("l_buf.txt","w")) == NULL) { perror("file open failure!"); return(-1); } setvbuf( fp , buf , _IOLBF , sizeof(buf) ); memset(buf,'\0',128); fwrite( msg2 , sizeof(msg2) , 1 , fp ); printf("test setvbuf(line buf)!check l_buf.txt, because line buf ,only data before enter send to file\n"); printf("now buf data is :buf=%s\n",buf); printf("press enter to continue!\n"); getchar(); fclose(fp); //open a file and set full buf(used setvbuf).and write string to it for 20th time (it is large than the buf) //check it before close of flush the stream if(( fp = fopen("f_buf.txt","w")) == NULL) { perror("file open failure!"); return(-1); } setvbuf( fp , buf , _IOFBF , sizeof(buf) ); memset(buf,'\0',128); fwrite( msg2 , sizeof(msg2) , 1 , fp ); printf("test setbuf(full buf)!check f_buf.txt\n"); printf("now buf data is :buf=%s\n",buf); // check data of the current buff printf("press enter to continue!\n"); getchar(); fclose(fp);}
result:
ANSI C 檔案I/O操作
1.開啟關閉檔案三個函數:
fopen()
fclose()
fflush() // 重新整理流
具體代碼見stdio.h原始碼
2.讀寫檔案
字元單位
1.字元讀
從流中讀取
從stdin中:
/* Read a character from stdin. This function is a possible cancellation point and therefore not marked with __THROW. */extern int getchar (void);
2.字元寫
/* Write a character to STREAM. These functions are possible cancellation points and therefore not marked with __THROW. These functions is a possible cancellation point and therefore not marked with __THROW. */extern int fputc (int __c, FILE *__stream);extern int putc (int __c, FILE *__stream);/* Write a character to stdout. This function is a possible cancellation point and therefore not marked with __THROW. */extern int putchar (int __c);
行單位
行讀出&行寫入
/* Write a string to STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */extern int fputs (const char *__restrict __s, FILE *__restrict __stream);/* Write a string, followed by a newline, to stdout. This function is a possible cancellation point and therefore not marked with __THROW. */extern int puts (const char *__s);
塊單位
讀寫
/* Read chunks of generic data from STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */extern size_t fread (void *__restrict __ptr, size_t __size, size_t __n, FILE *__restrict __stream) __wur;/* Write chunks of generic data to STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */extern size_t fwrite (const void *__restrict __ptr, size_t __size, size_t __n, FILE *__restrict __s);
檔案流檢測
即是檢測檔案是否已經讀寫到末尾或者出錯.,使用feof函數.
對於ascii碼檔案,可以通過是否=EOF判斷
對於二進位檔案,則需要使用feof來判斷是否結束,結束返回1.否則返回0.
ferror函數判斷是否出錯,無錯返回0.
檔案流定位
ftell()函數返迴流的當前讀寫位置距離檔案開始的位元組數
fseek()函數修改當前讀寫位置
rewind()函數重設讀寫位置到開頭.
/* Seek to a certain position on STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */extern int fseek (FILE *__stream, long int __off, int __whence);/* Return the current position of STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */extern long int ftell (FILE *__stream) __wur;/* Rewind to the beginning of STREAM. This function is a possible cancellation point and therefore not marked with __THROW. */extern void rewind (FILE *__stream);
執行個體應用
為實現磁碟檔案的複製,在ANSI C 的標準下,首先需要將源檔案和目標檔案建立聯絡以讀的方式開啟源檔案,以寫的方式開啟目標檔案,先將源檔案的資料集中寫到緩衝區,然後從記憶體寫入目標檔案所在的磁碟.
其中最重要的是判斷檔案的是否結束.一種方式是使用feof函數,另一種方式是使用讀操作的返回值,比如,每次讀128位元組,只有讀到結束位置的時候毒的位元組數會小於128,如果出錯則返回-1.
一種實現代碼如下:
#include<stdio.h>int main(int argc,char *argv[]){ FILE *fp=NULL; char ch; if(argc<=1) { printf("check usage of %s \n",argv[0]); return -1; }if((fp=fopen(argv[1],"r"))==NULL)//以唯讀形式開啟argv[1]所指明的檔案 { printf("can not open %s\n",argv[1]); return -1; } while ((ch=fgetc(fp))!=EOF) //把已開啟的檔案中的資料逐位元組的輸出到標準輸出stdout fputc(ch,stdout); fclose(fp); //關閉檔案 return 0;}
具體結果就不示範了.可以自行編譯驗證.
ElSE
流的格式化輸入和輸出操作
其實就是幾個函數的講解,這個部分很多資料,所以不在講了,具體的可以自己google或者看原始碼了.
1.
printf()和scanf(0函數.
2.
fprintf()函數和fscanf()函數
3.sprintf函數
4.sscanf()函數
下面貼一下一個使用sscanf擷取cpu頻率的樣本程式:
#include <stdio.h> #include <string.h> float get_cpu_clock_speed () { FILE* fp; char buffer[1024]; size_t bytes_read; char* match; float clock_speed; fp = fopen ("/proc/cpuinfo", "r"); bytes_read = fread (buffer, 1, sizeof (buffer), fp); fclose (fp); if (bytes_read == 0 || bytes_read == sizeof (buffer)) return 0; buffer[bytes_read] = '\0'; match = strstr (buffer, "cpu MHz");//匹配 if (match == NULL) return 0; sscanf (match, "cpu MHz : %f", &clock_speed);//讀取 return clock_speed; } int main (void) { printf ("CPU clock speed: %4.0f MHz\n", get_cpu_clock_speed ()); return 0; }
result:
reference
關於二進位和文字檔 http://www.cnblogs.com/whutzhou/p/3215210.html
linux進階程式設計 李宗德
NEXT
POSIX 檔案及目錄管理
普通檔案\串連檔案及目錄檔案屬性管理
轉載請註明出處:http://blog.csdn.net/suool/article/details/38129201