linux系统编程之文件与io(二)
今天继续学习文件与io,话不多说,开始进入正题:
文件的read和write系统调用:
![](http://images0.cnblogs.com/blog/324374/201312/28204054-a14fdf6d35294f8abcf3052844933999.png)
![](http://images0.cnblogs.com/blog/324374/201312/28204140-eb69c26fbe5a4f3caa7b21ef7fdbf8a2.png)
说明:函数中出现在size_t和ssize_t是针对系统定制的数据类型:
![](http://images0.cnblogs.com/blog/324374/201312/29093117-ac417eb889b34b89a8f12a6b58f8ea94.png)
![](http://images0.cnblogs.com/blog/324374/201312/29093149-987cdbd8b7864cc0b5ce86eaecc1acbd.png)
下面以一个实现文件简单拷贝的示例(类似于cp命令,但是没cp命令强大),来对其文件的读写有个感性的认识:
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc/**参数总个数**/, char *argv[]/**具体参数值**/) { int infd;//读文件描述符 int outfd;//写文件描述符 if (argc != 3) { fprintf(stderr, "Usage %s src dest\n", argv[0]); exit(EXIT_FAILURE); } infd = open(argv[1], O_RDONLY); if (infd == -1) ERR_EXIT("open src error"); if ((outfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC/**以清空的方式打开**/, 0644)) == -1) ERR_EXIT("open dest error"); char buf[1024]; int nread;
//将读入的文件内容拷贝到新文件中 while ((nread = read(infd, buf, 1024)) > 0) { write(outfd, buf, nread); } close(infd); close(outfd); return 0; }
编译运行:
对于read和write,下面再来探讨一下它们之间细微的区别:
1、read读取过程中,有可能被某些信号给中断,这个在之后的信号中断时再学习。
2、read读指定字节的数据时,如果返回值大于0,表示已经从文件中将数据读到缓冲区当中了,但是write就不一定了,当我们写入时,如果返回大于0并非代表已经将缓冲区中的数据写入到磁盘当中了,仅仅只是表示数据缓冲区已经拷到内核缓冲区了,并未同步到磁盘上,如果想立即同步到磁盘中的话,可以利用下面这个函数既时同步:
![](http://images0.cnblogs.com/blog/324374/201312/28211155-64fa50b2aff84594ad68d9a6f8daa706.png)
实际上,我们也可以通过给open函数,设定一个flags,来达到同步的效果:
![](http://images0.cnblogs.com/blog/324374/201312/28211348-b23532574d694ff396bcd556795510eb.png)
这时写文件时,就会一直阻塞到数据缓冲区写到物理磁盘。
文件的随机读写:
![](http://images0.cnblogs.com/blog/324374/201312/29093609-97bd2d24e3cf46638083cab482fb3db0.png)
![](http://images0.cnblogs.com/blog/324374/201312/29093649-bb030db442524f1692d3cf4ef48e7097.png)
![](http://images0.cnblogs.com/blog/324374/201312/29093707-0f4bf8cfabd34b6ea7da47f122fdeb76.png)
说明:lseek对应于c语言fseek函数
下面用具体实例来理解一下lseek函数的用法:
实例一:
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(void) { int fd; fd = open("test.txt", O_RDONLY); if (fd == -1) ERR_EXIT("open error"); char buf[1024] = {0}; int ret = read(fd, buf, 5);//从文件中读取5个字节,这时文件指针就会偏移到5的位置 if (ret == -1) ERR_EXIT("read error"); printf("buf=%s\n", buf); ret = lseek(fd, 0, SEEK_CUR);//通过从当前文件的偏移值计算偏移,偏移量为0,就能计算文件当前的偏移量
if (ret == -1) ERR_EXIT("lseek"); printf("current offset=%d\n", ret); return 0; }
首先我们创建一个test.txt,以便进行程序测试:
编译运行:
实例二:利用lseek产生空洞文件
首先先了解下什么是空洞文件:
![](http://images0.cnblogs.com/blog/324374/201312/29101514-1c6c33f16c1e4ffcaa53f9ecffd1f416.png)
好了,下面用程序进行说明:
![](http://images0.cnblogs.com/blog/324374/201312/29102141-7fa155ef27bb4db3bfa0587eefe2d9d0.png)
编译运行:
![](http://images0.cnblogs.com/blog/324374/201312/29102251-59ae5e854a41464e8fb73688f08e5a29.png)
我们来查看一下它的内容:
![](http://images0.cnblogs.com/blog/324374/201312/29102427-c6d55a00639c40df8d7c5de98ca25f0f.png)
这时,采用另外一个命令:
![](http://images0.cnblogs.com/blog/324374/201312/29102642-bdf0d3e0b8de41f29999da2bc368528d.png)
这时,我们查看一下其大小:
![](http://images0.cnblogs.com/blog/324374/201312/29102934-62ade94bf8d94616b905bfeab9a4f171.png)
![](http://images0.cnblogs.com/blog/324374/201312/29103323-75239f11fa8d4b3fa97ccd527e41529c.png)
这时,为了说明空洞内容是没有存放在磁盘中的,这时,我们将偏移量加大:
![](http://images0.cnblogs.com/blog/324374/201312/29103611-0a2a647ffb154f148f63b87636f5e6e0.png)
编译运行,来查看下内容大小:
![](http://images0.cnblogs.com/blog/324374/201312/29103955-aac10cd1ad2842dc8b10c07a78479056.png)
总结:
一个文件的大小不等于一个文件在磁盘所占用的空间,下面再来简单说明下:
![](http://images0.cnblogs.com/blog/324374/201312/29104238-a9f3e2a6155e486ca3ea1672b582ae96.png)
目录访问:
![](http://images0.cnblogs.com/blog/324374/201312/29105214-3de23c1918944c2780e9417c26532692.png)
![](http://images0.cnblogs.com/blog/324374/201312/29105242-fe8077fbc94048d08ead80494b301963.png)
![](http://images0.cnblogs.com/blog/324374/201312/29105306-0b23df9eb400408c9afa2e219d8b297e.png)
说明:struct dirent目录信息结构体的核心结构如下:
![](http://images0.cnblogs.com/blog/324374/201312/29105443-25e56fcbc4744aef912c26b85e22d724.png)
下面以一个具体示例来使用上面的这些目录函数【功能跟ls命令类似,简易版】:
![](http://images0.cnblogs.com/blog/324374/201312/29110523-21bb5b05b8ff4ab2bd873cf8034cda8b.png)
编译运行:
![](http://images0.cnblogs.com/blog/324374/201312/29110652-3cda529f8ea14f2aa9f849ae3ef18eb8.png)
如果想过滤掉隐藏文件,则可以修下代码如下:
![](http://images0.cnblogs.com/blog/324374/201312/29110900-9c922a083afb4d9494b207144658ce13.png)
再次运行:
![](http://images0.cnblogs.com/blog/324374/201312/29111021-23e666d8c91a4462b480cc361507921d.png)
下面还有一些命令函数,比较简单,这里就不练习了,贴出来参考:
mkdir:
![](http://images0.cnblogs.com/blog/324374/201312/29111252-a57a6d291a4341d1974a27af3c21d18b.png)
rmdir:
![](http://images0.cnblogs.com/blog/324374/201312/29111315-2edb61b19c704d328d8976e75da19b77.png)
chmod和fchmod:
![](http://images0.cnblogs.com/blog/324374/201312/29111343-85c5aa58448649a2b5081ad98c43fcab.png)
chown和fchown:
![](http://images0.cnblogs.com/blog/324374/201312/29111409-ba6e0df63ea841a98c8998d5503e3170.png)
好了,今天的内容学到这,下回见!