Skip to content

Latest commit

 

History

History
115 lines (82 loc) · 4 KB

10.1.md

File metadata and controls

115 lines (82 loc) · 4 KB

10.1 Unix I/O

一个Unix的文件,是一个m个字节的序列,从B0~Bm-1
Unix的所以的I/O设备,如:网络,磁盘和终端,都被模型化成了文件
输入和输出就被抽象为文件的读和写

打开文件

程序通过内核打开相应的文件,表示它想访问一个I/O设备
内核打开文件时,会返回一个非负整数,叫做文件描述符,是对这个打开文件的标识,程序使用该打开的文件,直接通过文件描述符操作

读写文件

读操作就是 从文件拷贝 n > 0个字节到存储器,从当前文件位置k开始,然后增加到k+n,就把这n个字节拷贝到了存储器
如果k>=m,就是要读的字节数大于文件大小,会触发end-of-file(EOF),表示以后到文件末端。

写操作就是从存储器把n > 0个字节拷贝到文件中,从当前位置k开始,更新k

关闭文件

当程序完成使用这个文件后,通知内核关闭这个文件,然后内核就释放文件打开时创建的数据结构并把文件描述符恢复到可用的描述符池中

关于描述符限制

Unix的控制台对应的标准输入,标准输出和标准错误是在<unistd.h>文件中定义的:

/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */

文件描述符是一种资源,Linux下的最大文件描述符有两方面的限制:

  • 用户级的限制
  • 系统级的限制

用户级的限制: systcl和proc文件系统中查看到的数值,它是限制所有用户打开文件描述符的总和

[chapter10] sysctl -a | grep -i file-max      
fs.file-max = 49803

系统级限制:
ulimit命令看到的是用户级的最大文件描述符限制,也就是说每一个用户登录后执行的程序占用文件描述符的总数不能超过这个限制

[chapter10] ulimit -n                       
1024

修改限制:
用户级限制
临时修改:

      [root@iZ23jmq7pjaZ ~]# ulimit -n 10240
      [root@iZ23jmq7pjaZ ~]# ulimit -n
      10240

这种修改只能对当前会话起作用,永久修改,需要修改文件

永久修改:
/etc/security/limits.conf中修改或者添加

    * soft nofile 65535
    * hard nofile 65535

这里的hard数值需要大于等于soft的数值

系统级限制
临时修改:

sysctl -w fs.file-max=400000

echo 350000 > /proc/sys/fs/file-max

永久修改: 添加fs.file-max=400000/etc/sysctl.confsysctl -p

注意:/etc/sysctl.conf此文件也是tcp性能调优主要修改的文件

关于EOF

EOF在stdio.h中被定义为-1
EOF其实算是一种状态,这种状态有两种情况会发生:

  • 文件读完 发送信号 返回-1
  • 文件读取出错 windows Ctrl+z linux下ctrl+d kill消息 返回-1

在getchar时,代码如下:

  1 #include <stdio.h>
  2
  3 int main()
  4 {
  5         char c; //char c对么?
  6         while( (c=getchar() ) != EOF)
  7         {
  8                 putchar(c);
  9         }
 10
 11         return 0;
 12 }
~

在程序运行的时候,输入之后直接ctrl+d会输出缓冲区的字符

查看一下getchar()的说明:

 fgetc()  reads  the  next character from stream and returns it as an unsigned char cast to an int, or EOF on end of file or error.
 getc() is equivalent to fgetc() except that it may be implemented as a macro which evaluates stream more than once.
 getchar() is equivalent to getc(stdin).

发现,fgetc是返回一个unsigned char 转换为int 或者EOF 或者error
那么上面的程序使用char c来获取getchar的值是不是不对呢?
肯定不对,把一个负值赋给一个char c,应该使用int c

下面的坑很多人踩到了

    FILE *fp;
    unsigned char c; 
    while ((c = fgetc(fp)) != EOF) //死循环
    {
        putchar (c);
    }