1. 程式人生 > >開啟和關閉檔案以及讀取和回退字元的操作

開啟和關閉檔案以及讀取和回退字元的操作

1.開啟檔案

  函式功能: 開啟一個檔案

  函式原型:FILE * fopen(const char * path,const char * mode);

  相關函式:openfclose,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 "stdafx.h"
#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