天天看點

linux下C通過系統調用進行基本IO操作

一.Linux下通過系統調用對普通文本檔案進行I/O操作步驟:

    1. 調用open()獲得一個檔案描述符
    1. 利用獲得的檔案描述符作為read() 和write()的一個參數,進行I/O操作。
    1. 使用close()釋放檔案描述符及其相關資源。

檔案描述符:一個非負整數(無符号整數),用于引用在核心中打開的檔案。打開或建立一個檔案時,核心傳回一個檔案描述符。讀寫一個檔案時利用open、creat函數傳回的檔案描述符辨別該檔案,作為參數傳給read或write函數。

函數簡介:open()、read()、write()、close()

1. open()

#include <sys/stat.h>
#include <fcntl.h>
 int open(const char *path, int oflag, ...)  
           

1.1 return: 傳回檔案描述符,若發生錯誤傳回-1.

1.2 path: 要打開的檔案路徑.

1.3 oflag: 位掩碼,用于指定檔案通路模式,用下列一個或多個常數進行或運算構成oflag參數(這些常數定義在

以上三個常數應當隻制定一個,下列常數則是可選的:

  • O_EXCL 如果同時指定了O _ C R E AT,而檔案已經存在,則出錯。這可測試一個檔案是

    否存在,如果不存在則建立此檔案成為一個原子操作。

  • O_TRUNC 如果此檔案存在,而且為隻讀或隻寫成功打開,則将其長度截短為 0。
  • O_NOCTTY 如果p a t h n a m e指的是終端裝置,則不将此裝置配置設定作為此程序的控制終端。
  • O_NONBLOCK 如果p a t h n a m e指的是一個F I F O、一個塊特殊檔案或一個字元特殊檔案,

    則此選擇項為此檔案的本次打開操作和後續的 I / O操作設定非阻塞方式。

  • O_SYNC 使每次w r i t e都等到實體I / O操作完成。

2. read()

讀取檔案描述符指代的檔案中的資料。

#include <unistd.h>
ssize_t read(int fildes, void *buf, size_t nbyte);
           

2.1 return:傳回實際讀取的位元組數,如果讀到檔案末尾(遇到檔案結束符EOF)則會傳回0.如果出現錯誤則傳回-1.

2.2 filedes: 要打開檔案的檔案描述符.

2.3 *buf: 緩沖區(自己手動定義,因為linux系統調用不會配置設定記憶體緩沖區用來傳回資訊給調用者。是以需要先自己配置設定緩沖區,病将緩沖區指針傳遞給系統調用 。緩沖區大小自己設定,一般設為1024)

3. write()

将資料寫入一個已打開(檔案描述符指代)的檔案中。

#include <unistd.h>s
ssize_t write(int fildes, const void *buf, size_t nbyte);
           

3.1 return: 傳回實際寫入的位元組數。

3.2 fildes:要寫入檔案的檔案描述符

3.3 buf: 要寫入檔案中資料的記憶體位址。

4. close()

關閉一個已打開的檔案

#include <unistd.h>

int close(int fildes);
           

4.1 return:關閉檔案失敗時傳回-1。

4.2 fildes: 要關閉檔案的檔案描述符。

5. 檔案空洞: 所有已打開的檔案,核心中都有一個檔案偏移量用以制定下次讀或寫操作的起始位置。讀、寫操作隐式修改檔案偏移量。使用lseek()函數可以顯示修改檔案偏移量。在檔案結尾之後的某一個位置寫書資料将導緻檔案空洞,從檔案空洞處讀取檔案将傳回全0位元組。

二. copy指令的簡單實作:

1. copy.c

#include <sys/stat.h>
#include<fcntl.h>
#include "tlpi_hdr.h"

#ifndef BUF_SIZE
#define BUF_SIZE 1024
#endif
int main(int argc, char *argv[])
{
   int inputFd, outputFd, openFlags;
   mode_t filePerms;
   ssize_t numRead;
   char buf[BUF_SIZE];

   if(argc != || strcmp(argv[], "--hlep")==)
   usageErr("%s old-flie new-file\n",argv[]);

inputFd = open(argv[], O_RDONLY);
if(inputFd== -)
    errExit("opening file %s", argv[]);
printf("fd %d",inputFd);
openFlags = O_CREAT | O_WRONLY |O_TRUNC;
filePerms =S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |S_IROTH |S_IWOTH;
outputFd = open(argv[],openFlags, filePerms);
if(outputFd == -)
    errExit("opening file %s",argv[]);
    /* 開始讀取并将資料寫入到要複制到的檔案中*/
while((numRead =read(inputFd, buf, BUF_SIZE))>)
    if(write(outputFd,buf,numRead) != numRead)
        fatal("couldn't write whole buffer");
if(numRead== -)
    errExit("read");

if(close(inputFd) == -)
    errExit("close input");

if(close(outputFd) == -)
    errExit("close output");

    exit(EXIT_SUCCESS);
}
           

2. tlpi_hdr.h

#ifndef  TLPI_HDR_H
#define TLPI_HDR_H  /*防止包含2次"*/

#include <sys/types.h> 
#include <stdio.h>
#include <stdlib.h>

#include <unistd.h> /*常用系統調用原型*/
#include <errno.h> /*聲明錯誤代碼 ,定義錯誤常量*/
#include <string.h> /*常用字元串處理函數*/

#include "get_num.h" /*聲明我們數字參數處理函數*/

#include "error_functions.h" /*聲明我們的錯誤處理函數*/

typedef enum {FALSE,TRUE} Boolean;
#endif 
           

3. get_num.h

#ifndef  TLPI_HDR_H
#define TLPI_HDR_H  /*防止包含2次"*/

#include <sys/types.h> 
#include <stdio.h>
#include <stdlib.h>

#include <unistd.h> /*常用系統調用原型*/
#include <errno.h> /*聲明錯誤代碼 ,定義錯誤常量*/
#include <string.h> /*常用字元串處理函數*/

#include "get_num.h" /*聲明我們數字參數處理函數*/

#include "error_functions.h" /*聲明我們的錯誤處理函數*/

typedef enum {FALSE,TRUE} Boolean;
#endif 
           

4. get_num.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include "get_num.h"

static void gnFail(const char *fname, const char *msg, const char *arg, const char *name)
{
    fprintf(stderr, "%s error", fname);

    if(name !=NULL)
        fprintf(stderr, " (in %s)", name);
    fprintf(stderr, ": %s\n", msg);   
    if (arg !=NULL && *arg != '\0')
        fprintf(stderr, "       offending text: %s\n",arg);
        exit(EXIT_FAILURE);
}
static long getNum(const char *fname, const char *arg,int flags,const char *name)
{
    long res;
    char *endptr;
    int base;

    if (arg == NULL || *arg == '\0')
        gnFail(fname, "null or empty string", arg, name);

    base=(flags & GN_ANY_BASE) ?  : (flags & GNBASE_8 ?  :(flags & GN_BASE_16) ?  : );

    errno = ;
    res = strtol(arg, &endptr, base);
    if(errno != '\0')
        gnFail(fname, "strtol() failed", arg, name);

    if ((flags & GN_NONNEG) && res < )
        gnFail(fname, "negative value not allowed",arg, name);

    if((flags & GN_GT_0)&& res <= )
        gnFail(fname, "value must be > 0", arg, name);

    return res;
}

long getLong(const char *arg, int flags, const char *name)
{
    return getNum("getLong", arg, flags, name);
}
int getInt(const char *arg, int flags, const char *name)
{
    long res;
    res = getNum("getIn", arg, flags, name);
    if(res > INT_MAX || res <INT_MIN)
        gnFail("getInt", "integer out of range", arg, name);

    return (int)res;
}
           

5. error_functions.h

#ifndef ERROR_FUNCTIONS_H
#define ERROR_FUNCTIONS_H

void errMsg(const char *format, ...);
#ifdef  _GNUC

#define NORETURN _attribute_ ((_noreturn_))
#else
#define NORETURN
#endif 

void errExit(const char *format, ...) NORETURN;

void err_exit(const char *format, ...) NORETURN;

void errExitEN(int errnum, const char *format, ...) NORETURN;

void fatal(const char *format, ...) NORETURN;

void usageErr(const char *format, ...) NORETURN;

void cmdLineErr(const char *format, ...) NORETURN;
#endif
           

6. error_function.c

#include <stdarg.h>
#include "error_functions.h"
#include "tlpi_hdr.h"
#include "ename.c.inc"

#ifdef  _GNUC_
_attribute_ ((_noreturn_))
#endif
static void terminate(Boolean useExit3)
{
    char *s;
    s=getenv("EF_DUMPCORE"); //擷取環境變量

    if(s!=NULL && *s!= '\0')
        abort();
    else if (useExit3)
        exit(EXIT_FAILURE);
    else
        _exit(EXIT_FAILURE);
}
static void outputError(Boolean userErr, int err, Boolean flushStdout, const char *format,va_list ap)
{
    #define BUF_SIZE 500
    char buf[BUF_SIZE], userMsg[BUF_SIZE], errText[BUF_SIZE];

    vsnprintf(userMsg, BUF_SIZE,format, ap);

    if(userErr)
        snprintf(errText, BUF_SIZE," [%s,%s]",(err> && err<=MAX_ENAME)?ename[err]:"?UNKOWN?",strerror(err));
    else
        snprintf(errText,BUF_SIZE,":");
    snprintf(buf,BUF_SIZE,"ERROR%S %S\n",errText,userMsg);

    if(flushStdout)
        fflush(stdout);
    fputs(buf,stderr);
}
 void errMsg(const char *format, ...)
 {
     va_list argList;
     int savedErrno;

     savedErrno = errno;
     va_start(argList,format);
     outputError(TRUE,errno,TRUE,format,argList);
     va_end(argList);

     terminate(TRUE);
 }
 void errExit(const char *format, ...)
 {
     va_list argList;

     va_start(argList, format);
     outputError(TRUE, errno, TRUE, format, argList);
     va_end(argList);

     terminate(TRUE);
 }
 void err_exit(const char *format, ...)
 {
     va_list argList;

     va_start(argList, format);
     outputError(TRUE, errno, FALSE, format, argList);
     va_end(argList);

     terminate(FALSE);
 }
 void errExitEN(int errnum, const char *format, ...)
 {
     va_list argList;

     va_start(argList, format);
     outputError(TRUE, errnum,TRUE, format, argList);
     va_end(argList);

     terminate(TRUE);
 }

 void fatal(const char *format, ...)
 {
     va_list argList;

     va_start(argList, format);
     outputError(FALSE, , TRUE,format, argList);
     va_end(argList);

     terminate(TRUE);
 }
 void usageErr(const char *format, ...)
 {
     va_list argList;

     fflush(stdout);

     fprintf(stderr,"Usage: ");
     va_start(argList, format);
     vfprintf(stderr, format, argList);
     va_end(argList);

     fflush(stderr);
     exit(EXIT_FAILURE);
}
void cmdLineErr(const char *format, ...)
{
    va_list argList;

    fflush(stdout);

    fprintf(stderr, "Command-line usage error:");
    va_start(argList, format);
    vfprintf(stderr, format, argList);
    va_end(argList);

    fflush(stderr);
    exit(EXIT_FAILURE);
}
           

7. ename.c.inc

static char *ename[] = {
    /*  0   */ "",
    /*  1   */ "EPERM", "ENOENT", "ESRCH", "EIO", "EXIO", "E2BIG",
    /*  8   */ "ENOEXEC", "EBADF", "ECHILD", "EAGAIN/EWOULDBLOCK", "ENOMEM",
    /*  13  */ "EACCES", "EFAULT", "ENOTBLK", "EBUSY", "EEXIST", "EXDEV",
    /*  19  */ "ENODEV", "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE",
    /*  25  */ "ENOTTY", "ETXTBSY", "EFBIG",  "ENOSPC", "ESPIPE", "EROFS",
    /*  31  */ "EMLINK", "EPIPE", "EDOM", "ERANGE", "EDEADLK/EDEADLOCK",
    /*  36  */ "ENMAETOOLONG", "ENOLCK", "ENOSYS", "ENOTEMPTY", "ELPP", "",
    /*  42  */ "ENOMSG", "EIDRM", "ECHRNG", "EL2NSYNC", "EL3HLT", "EL3RST",
    /*  48  */  "ELNRNG", "EUNATCH", "ENOCSI", "EL2HLT", "EBADE", "EBADR",
    /*  54  */ "EXFULL", "ENOANO", "EBADRO", "EBADSLT", "", "EBFONT", "ENOSTR",
    /*  61  */ "ENODATA", "ETIME", "ENOSR", "ENONET", "ENOPKG", "EREMOTE",
    /*  67  */ "ENOLINK", "EADV", "ESRMNT", "ECOMM", "EPROTO", "EMULITIHOP",
    /*  73  */ "EDOTDOT", "EBADMSG", "EOVERFLOW", "ENOTUNIQ", "EBADFD",
    /*  78  */ "EREMCHG", "ELIBACC", "ELIBBAD", "ELIBSCN", "ELIBMAX",
    /*  83  */ "ELIBEXECC", "EILSEQ", "ERESTART", "ESTRPIPe", "EUSERS",
    /*  88  */ "ENOTSOCK", "EDESTADDRREQ", "EMSGSIZE", "EPROTOTYPE",
    /*  92  */ "ENOPROTOOPT", "EPROTONOSUPPORT", "ESOCKTNOSUPPORT",
    /*  95  */ "EOPNOTSUPP/ENOTSUP", "EPFNOSUPPORT", "EAFNOSUPPORT",
    /*  98  */ "EADDRINUSE", "EADDRNOTAVAIL", "ENETDOWN", "ENETUNREACH",
    /*  102 */ "ENETRESET", "ECONNABORTED", "ECONNRESET", "ENOBUFS", "EISCONN",
    /*  107 */ "ENOTCONN", "ESHUTDOWN", "ETOOMANYREFS", "ETIMEDOUT",
    /*  111 */ "ECONNREFUSED", "EHOSTDOWN", "EHOSTUNREACH", "EALREADY",
    /*  115 */ "EINPROGRESS", "ESTALE", "EUCLEAN", "ENOTNAM", "ENAVAIL",
    /*  120 */ "EISNAM", "EREMOTEIO", "EDQUOT", "ENOMEDIUM", "EMEDIUMTYPE",
    /*  125 */ "ECANCELED", "ENOKEY", "EKEYEXPIRED", "EKEYREVOKED",
    /*  129 */ "EKEYREJECTED", "EOWNERDEAD", "ENOTRECOVERABLE", "ERFKILL"
};
#define MAX_ENAME 132
           

繼續閱讀