開啟和關閉檔案以及讀取和回退字元的操作
1.開啟檔案
函式功能: 開啟一個檔案
函式原型:FILE * fopen(const char * path,const char * mode);
相關函式:open,fclose,fopen_s[1]
,_wfopen
fopen_s:窄字元
errno_t fopen_s( FILE** pFile, const char *filename, const char *mode );
_wfopen:寬字元
errno_t _wfopen_s( FILE** pFile, const wchar_t *filename, const wchar_t *mode );
返回值: 檔案順利開啟後,指向該流的檔案指標就會被返回。若果檔案開啟失敗則返回NULL,並把錯誤程式碼存在errno 中。
一般而言,開啟檔案後會作一些檔案讀取或寫入的動作,若開啟檔案失敗,接下來的讀寫動作也無法順利進行,所以在fopen()後請作錯誤判斷及處理。
返回值說明如下:
Constant | System error message | Value |
---|---|---|
EPERM |
Operation not permitted |
1 |
ENOENT |
No such file or directory |
2 |
ESRCH |
No such process |
3 |
EINTR |
Interrupted function |
4 |
EIO |
I/O error |
5 |
ENXIO |
No such device or address |
6 |
E2BIG |
Argument list too long |
7 |
ENOEXEC |
Exec format error |
8 |
EBADF |
Bad file number |
9 |
ECHILD |
No spawned processes |
10 |
EAGAIN |
No more processes or not enough memory or maximum nesting level reached |
11 |
ENOMEM |
Not enough memory |
12 |
EACCES |
Permission denied |
13 |
EFAULT |
Bad address |
14 |
EBUSY |
Device or resource busy |
16 |
EEXIST |
File exists |
17 |
EXDEV |
Cross-device link |
18 |
ENODEV |
No such device |
19 |
ENOTDIR |
Not a directory |
20 |
EISDIR |
Is a directory |
21 |
EINVAL |
Invalid argument |
22 |
ENFILE |
Too many files open in system |
23 |
EMFILE |
Too many open files |
24 |
ENOTTY |
Inappropriate I/O control operation |
25 |
EFBIG |
File too large |
27 |
ENOSPC |
No space left on device |
28 |
ESPIPE |
Invalid seek |
29 |
EROFS |
Read-only file system |
30 |
EMLINK |
Too many links |
31 |
EPIPE |
Broken pipe |
32 |
EDOM |
Math argument |
33 |
ERANGE |
Result too large |
34 |
EDEADLK |
Resource deadlock would occur |
36 |
EDEADLOCK |
Same as EDEADLK for compatibility with older Microsoft C versions |
36 |
ENAMETOOLONG |
Filename too long |
38 |
ENOLCK |
No locks available |
39 |
ENOSYS |
Function not supported |
40 |
ENOTEMPTY |
Directory not empty |
41 |
EILSEQ |
Illegal byte sequence |
42 |
STRUNCATE |
String was truncated |
80 |
引數說明:
引數path字串包含欲開啟的檔案路徑及檔名,引數mode字串則代表著流形態。
mode有下列幾種形態字串:
r 開啟只讀檔案,該檔案必須存在。
r+ 開啟可讀寫的檔案,該檔案必須存在。
rb+ 讀寫開啟一個二進位制檔案,只允許讀寫資料。
rt+ 讀寫開啟一個文字檔案,允許讀和寫。
w 開啟只寫檔案,若檔案存在則檔案長度清為0,即該檔案內容會消失。若檔案不存在則建立該檔案。
w+ 開啟可讀寫檔案,若檔案存在則檔案長度清為零,即該檔案內容會消失。若檔案不存在則建立該檔案。
a 以附加的方式開啟只寫檔案。若檔案不存在,則會建立該檔案,如果檔案存在,寫入的資料會被加到檔案尾,即檔案原先的內容會被保留。(EOF符保留)
a+ 以附加方式開啟可讀寫的檔案。若檔案不存在,則會建立該檔案,如果檔案存在,寫入的資料會被加到檔案尾後,即檔案原先的內容會被保留。 (原來的EOF符不保留)
wb 只寫開啟或新建一個二進位制檔案;只允許寫資料。
wb+ 讀寫開啟或建立一個二進位制檔案,允許讀和寫。
wt+ 讀寫開啟或著建立一個文字檔案;允許讀寫。
at+ 讀寫開啟一個文字檔案,允許讀或在文字末追加資料。
ab+ 讀寫開啟一個二進位制檔案,允許讀或在檔案末追加資料。
上述的形態字串都可以再加一個b字元,如rb、w+b或ab+等組合,加入b 字元用來告訴函式庫開啟的檔案為二進位制檔案,而非純文字檔案。不過在POSIX系統,包含Linux都會忽略該字元。由fopen()所建立的新檔案會具有S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)許可權,此檔案許可權也會參考umask 值。
有些C編譯系統可能不完全提供所有這些功能,有的C版本不用"r+","w+","a+",而用"rw","wr","ar"等,讀者注意所用系統的規定。
例:
FILE* file = NULL;
if(0 == fopen_s(&file, fileName, "rb+" ))
2.關閉檔案
if(NULL != file)
{
fclose(file);
file = NULL;
}
3.讀取和回退字元:
getc(FILE *stream);
int ungetc(int c, FILE *stream);輸入引數 c 要寫入的字元,stream 檔案流指標 輸出引數 字元c - 操作成功,EOF - 操作失敗(int)
Stream.h
#pragma once
class Stream
{
public:
~Stream(void);
INT32 s_getc();
BOOL s_ungetc(INT32 c);
INT32 s_read(UINT8 * buf, INT32 len);
INT32 s_write(UINT8 * buf, INT32 len);
static Stream* createStreamInstance(const char* fileName);
private:
Stream(FILE* file);
INT32 trytoReadFromBuffer(unsigned char* buf, INT32 len);
FILE* fp;
unsigned char fRevertBuf[128];
int fRevertNum;
};
Stream.cpp
#include "Stream.h"
#include <assert.h>
Stream::Stream(FILE* file)
:fp(NULL), fRevertNum(0)
{
fp = file;
}
Stream::~Stream(void)
{
if(fp != NULL)
{
fclose(fp);
fp = NULL;
}
// MessageBoxW(NULL, _T("free file."), _T("File Free"), 0);
}
INT32 Stream::trytoReadFromBuffer(unsigned char* buf, INT32 len)
{
if(fRevertNum < 1)
return 0;
unsigned char* pStackTop = &fRevertBuf[fRevertNum-1];
unsigned char* pStack = pStackTop;
while(len-- > 0 && fRevertNum-- > 0 ) {
*buf++ = *pStackTop--;
}
return ( pStack - pStackTop);
}
INT32 Stream::s_getc()
{
INT32 c = EOF;
unsigned char ch = 0;
if( trytoReadFromBuffer(&ch, 1) >= 1) {
c = (INT32)ch;
} else {
if(fp != NULL) {
c = getc(fp);
if(c == EOF)
{
fclose(fp);
fp = NULL;
}
}
}
return c;
}
BOOL Stream::s_ungetc(INT32 c)
{
if(c != EOF) {
fRevertBuf[fRevertNum++] = c;
}
return TRUE;
}
INT32 Stream::s_read(UINT8 * buf, INT32 len)
{
INT32 readNum = trytoReadFromBuffer(buf, len);
if(readNum< len) {
if(NULL != fp) {
INT32 tobeRead = len-readNum;
INT32 readNum1 = fread(buf+readNum, 1, tobeRead, fp);
if(readNum1 < tobeRead)
{
fclose(fp);
fp = NULL;
}
readNum += readNum1;
}
}
return readNum;
}
INT32 Stream::s_write(UINT8 * buf, INT32 len)
{
assert(false);
int writeNum = 0;
if(NULL != fp) {
writeNum = fwrite(buf, 1, len, fp);
if(writeNum != len)
{
fclose(fp);
fp = NULL;
}
}
return writeNum;
}
Stream* Stream::createStreamInstance(const char* fileName)
{
FILE* file = NULL;
if(0 == fopen_s(&file, fileName, "rb+" ))
return new Stream(file);
return NULL;
}
參考:
http://www.cnblogs.com/whiteyun/archive/2009/08/08/1541822.html