C语言——IO操作(三)

3 系统调用

3.1 文件描述符原理

  • 文件描述符的概念
文件标识 inode(整型数, 数组下标)
    			open
    file[inode]  ->  文件结构体 -> pos 位置指针
    							 count 打开计数器
    文件流会存在一个进程空间的数组中  标准输入输出错误 会占用当前可使用地最小地三个文件描述符。

  • 文件IO操作

open, close, read, write, lseek

  • 文件IO与标准IO地区别

  • IO效率问题

3.2 open 和 close

  • open
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       int open(const char *pathname, int flags);//变参函数
       int open(const char *pathname, int flags, mode_t mode);

       int creat(const char *pathname, mode_t mode);

       int openat(int dirfd, const char *pathname, int flags);
       int openat(int dirfd, const char *pathname, int flags, mode_t mode);

DESCRIPTION
       The  argument  flags  must  include  one  of the following access 
       modes: O_RDONLY, O_WRONLY, or O_RDWR.  These request opening the file 
       read-only, write-only, or read/write, respectively.

       In addition, zero or more file creation flags and file status flags 
       can be bitwise-or'd in flags. The file creation flags are O_CLOEXEC, 
       O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE, and 
       O_TRUNC. The file status flags are all of the remaining flags listed 
       below. The distinction between these  two groups of flags is that the 
       file creation flags affect the semantics of the open operation itself, 
       while the file status flags affect the semantics of subsequent I/O 
       operations. The file status flags can be retrieved and (in some cases) 
       modified; see fcntl(2) for details.
           
flags 参数的实质就是位表,对应到标准IO的打开模式下如下:
------------------------------------------------------------------
       r  -> O_RDONLY
       r+ -> O_RDWR
       w  -> O_WRONLY|O_CREAT|O_TRUNC
       w+ -> O_RDWR|O_TRUNC|O_CREEAT
  • close
       #include <unistd.h>

       int close(int fd);

DESCRIPTION
       close() closes a file descriptor, so that it no longer refers to any 
       file and may be reused.  Any record locks (see fcntl(2)) held on the 
       file it was associated with, and owned by the process, are removed  
       (regardless of the file descriptor that was used to obtain the lock).

       If  fd  is  the  last  file  descriptor  referring  to the underlying 
       open file description (see open(2)), the resources associated with the 
       open file description are freed; if the file descriptor was the last   
       reference to a file which has been removed using unlink(2), the file 
       is deleted.
           

3.3 read 、write 和 lseek

基本原理用法与标准IO相同,是标准IO的支撑。

  • read
SYNOPSIS
       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);

DESCRIPTION
       read() attempts to read up to count bytes from file descriptor fd into 
       the buffer starting at buf.

       On  files that support seeking, the read operation commences at the 
       file offset, and the file offset is incremented by the number of bytes 
       read. If the file offset is at or past the end of file, no bytes are 
       read, and read() returns zero.

       If count is zero, read() may detect the errors described below. In 
       the absence of any errors, or if read() does not check for errors, 
       a read() with a count of 0 returns zero and has no other effects.

       According to POSIX.1, if count is greater than SSIZE_MAX, the result 
       is implementation-defined; see NOTES for the upper limit on Linux.
  • write
SYNOPSIS
       #include <unistd.h>

       ssize_t write(int fd, const void *buf, size_t count);

DESCRIPTION
       write()  writes up to count bytes from the buffer starting at buf to 
       the file referred to by the file descriptor fd.

       The number of bytes written may be less than count if, for example, 
       there is insufficient space on the  underlying  physical  medium, or 
       the RLIMIT_FSIZE resource limit is encountered (see setrlimit(2)), or 
       the call was interrupted by a signal handler after having written less 
       than count bytes. (See also pipe(7).)

       For a seekable file (i.e., one to which lseek(2) may be applied, for 
       example, a regular  file)  writing  takes place  at the file offset, 
       and the file offset is incremented by the number of bytes actually 
       written. If the file was open(2)ed with O_APPEND, the file offset is 
       first set to the end of the  file  before  writing. The adjustment of 
       the file offset and the write operation are performed as an atomic 
       step.

       POSIX  requires that a read(2) that can be proved to occur after a 
       write() has returned will return the new data. Note that not all 
       filesystems are POSIX conforming.

       According to POSIX.1, if count is greater than SSIZE_MAX, the result 
       is implementation-defined; see NOTES for the upper limit on Linux.
  • lseek
SYNOPSIS
       #include <sys/types.h>
       #include <unistd.h>

       off_t lseek(int fd, off_t offset, int whence);

DESCRIPTION
       lseek() repositions the file offset of the open file description 
       associated with the file descriptor fd to the argument offset 
       according to the directive whence as follows:

       SEEK_SET
              The file offset is set to offset bytes.

       SEEK_CUR
              The file offset is set to its current location plus offset 
              bytes.

       SEEK_END
              The file offset is set to the size of the file plus offset 
              bytes.

       lseek() allows the file offset to be set beyond the end of the file 
       (but this does not change the size of  the file). If data is later 
       written at this point, subsequent reads of the data in the gap (a 
       "hole") return null bytes ('\0') until data is actually written into 
       the gap.

文件IO没有缓存区相应速度快,标准IO有缓冲区吞吐量大。

标准IO与文件IO不可混用。

time 命令
指令运行的时间。

4 文件共享

  • 一个程序打开两次同一个文件。
  • 两个进程打开同一个文件。
  • 两个进程打开同一个文件。。

  • truncate
SYNOPSIS
       #include <unistd.h>
       #include <sys/types.h>

       int truncate(const char *path, off_t length);
       int ftruncate(int fd, off_t length);
DESCRIPTION
       The  truncate() and ftruncate() functions cause the regular file named 
       by path or referenced by fd to be truncated to a size of precisely 
       length bytes.

       If the file previously was larger than this size, the extra data is 
       lost.  If the file previously was shorter, it is extended, and the 
       extended part reads as null bytes ('\0').

       The file offset is not changed.

       If  the size changed, then the st_ctime and st_mtime fields 
       (respectively, time of last status change and time of last 
       modification; see inode(7)) for the file are updated, and the set-
       user-ID and set-group-ID mode bits may be cleared.

       With ftruncate(), the file must be open for writing; with truncate(), 
       the file must be writable.

例题:写程序删除文件的第10行。

4.1 原子操作

概念:不可分割的操作。

作用:解决竞争和冲突。

  • dup 和 dup2
SYNOPSIS
       #include <unistd.h>

       int dup(int oldfd);//重定向 非原子
       int dup2(int oldfd, int newfd);//重定向 原子

       #define _GNU_SOURCE             /* See feature_test_macros(7) */
       #include <fcntl.h>              /* Obtain O_* constant definitions */
       #include <unistd.h>

       int dup3(int oldfd, int newfd, int flags);

DESCRIPTION
       The  dup()  system  call  creates  a  copy of the file descriptor 
       oldfd, using the lowest-numbered unused file descriptor for the new 
       descriptor.

       After a successful return, the old and new file descriptors may be 
       used interchangeably. They refer to the same open file description 
       (see open(2)) and thus share file offset and file status flags; for 
       example, if the file offset is modified by using lseek(2) on one of 
       the file descriptors, the offset is also changed  for the other.

       The  two file descriptors do not share file descriptor flags (the 
       close-on-exec flag).  The close-on-exec flag (FD_CLOEXEC; see 
       fcntl(2)) for the duplicate descriptor is off.
   dup2()
       The dup2() system call performs the same task as dup(), but instead 
       of using the lowest-numbered unused file descriptor, it uses the file 
       descriptor number specified in newfd.  If the file descriptor newfd 
       was previously open, it is silently closed before being reused.

       The steps of closing and reusing the file descriptor newfd  are  
       performed  atomically. This is important, because  trying to 
       implement equivalent functionality using close(2) and dup() would be 
       subject to race conditions, whereby newfd might be reused between the 
       two steps. Such reuse could happen because the main program is 
       interrupted by a signal handler that allocates a file descriptor, or 
       because a parallel thread allocates a file descriptor.

       Note the following points:

       *  If oldfd is not a valid file descriptor, then the call fails, and 
          newfd is not closed.

       *  If oldfd is a valid file descriptor, and newfd has the same value 
          as oldfd, then dup2() does  nothing,  and returns newfd.

文件重定向示例:

/**
 * 文件重定向 dup dup2 
 * 
 * 将标准输出(控制台)重定向到 out 文件
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define FNAME   "out"

int main(){

#if 0    
    int fd;
    close(1);
    fd = open(FNAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
    if (fd < 0){
        perror("open()");
        exit(-1);
    }
#endif
//----------------一下虚线内容同条件注释内容-----------------------
    int fd;
    fd = open(FNAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
    if (fd < 0){
        perror("open()");
        exit(-1);
    }
    /* 以下注释内容非原子 可以被打断 */
    //close(1);
    //dup(fd);
    //close(fd);

    /* 原子操作 */
    dup2(fd, 1);
    if (fd != 1){
        close(fd);
    }
//---------------------------------------------------------------
    /*******************************************************/    
    puts("hello!");

    return 0;
}

4.2 同步 sync 和 syncfs

  • sync syncfs

同步数据,刷内核buf,接触挂载

同步文件只刷数据不刷亚数据。

SYNOPSIS
       #include <unistd.h>

       void sync(void);
       int syncfs(int fd);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       sync():
           _XOPEN_SOURCE >= 500
               || /* Since glibc 2.19: */ _DEFAULT_SOURCE
               || /* Glibc versions <= 2.19: */ _BSD_SOURCE

       syncfs():
           _GNU_SOURCE

DESCRIPTION
       sync() causes all pending  modifications to filesystem metadata and 
       cached file data to be written to the underlying filesystems.

       syncfs() is like sync(), but synchronizes just the filesystem 
       containing file referred to by the open file descriptor fd.

RETURN VALUE
       syncfs() returns 0 on success; on error, it returns -1 and sets errno 
       to indicate the error.
  • fcntl
SYNOPSIS
       #include <unistd.h>
       #include <fcntl.h>
	   /* 文件描述符的基础函数 */
       int fcntl(int fd, int cmd, ... /* arg */ );
  • ioctl
//设备相关内容
SYNOPSIS
       #include <sys/ioctl.h>

       int ioctl(int fd, unsigned long request, ...);

DESCRIPTION
       The  ioctl()  system  call manipulates the underlying device 
       parameters of special files. In particular, many operating
       characteristics of character special files  (e.g., terminals) may 
       be controlled with ioctl() requests. The argument fd must be an 
       open file descriptor.

       The  second  argument is a device-dependent request code. The third 
       argument is an untyped pointer to memory.
       It is traditionally char *argp (from the days before void * was valid 
       C), and will be so named for this discussion.

       An ioctl() request has encoded in it whether the argument is an in 
       parameter or out parameter, and the size of the argument argp in 
       bytes. Macros and defines used in specifying an ioctl() request are 
       located in the file <sys/ioctl.h>.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值