今天继续学习文件与io,话不多说,开始进入正题:
文件的read和write系统调用:
![](https://i-blog.csdnimg.cn/blog_migrate/40118f3bf40aa56b625d49e118e70c14.png)
![](https://i-blog.csdnimg.cn/blog_migrate/904658e81f9f8e1fb014217ba0a4d9b3.png)
说明:函数中出现在size_t和ssize_t是针对系统定制的数据类型:
![](https://i-blog.csdnimg.cn/blog_migrate/d3141d38b247086f715d5914cc784c63.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3e027a9a0a5dc52680c77712d0196adb.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;
}
编译运行:
![](https://i-blog.csdnimg.cn/blog_migrate/fb20303add63840cc28186669381024f.png)
对于read和write,下面再来探讨一下它们之间细微的区别:
1、read读取过程中,有可能被某些信号给中断,这个在之后的信号中断时再学习。
2、read读指定字节的数据时,如果返回值大于0,表示已经从文件中将数据读到缓冲区当中了,但是write就不一定了,当我们写入时,如果
返回大于0并非代表已经将缓冲区中的数据写入到磁盘当中了,仅仅只是表示数据缓冲区已经拷到内核缓冲区了,
并未同步到磁盘上,如果想立即同步到磁盘中的话,可以利用下面这个函数既时同步:
![](https://i-blog.csdnimg.cn/blog_migrate/e87a9424deb02d7e46a68655243c3868.png)
实际上,我们也可以通过给open函数,设定一个flags,来达到同步的效果:
![](https://i-blog.csdnimg.cn/blog_migrate/c88865927c220b792f5b84a6b2090c30.png)
这时写文件时,就会一直阻塞到数据缓冲区写到物理磁盘。
文件的随机读写:
![](https://i-blog.csdnimg.cn/blog_migrate/336158197877a7d1c76138a6d2f24d15.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c36f3f36101a1f666b0e243171d46a5e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f30391d519c9142a68c30df7e5a99af1.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,以便进行程序测试:
![](https://i-blog.csdnimg.cn/blog_migrate/381fd56bc43a9f216658050ea1696dcc.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f90d7d05bf40331c50c9ccb8b60b260e.png)
编译运行:
![](https://i-blog.csdnimg.cn/blog_migrate/c4c2b3a6cba9056af80bb7616d43bee8.png)
实例二:利用lseek产生空洞文件
首先先了解下什么是空洞文件:
![](https://i-blog.csdnimg.cn/blog_migrate/3aa5ed4874746034040648b87f779dc7.png)
好了,下面用程序进行说明:
![](https://i-blog.csdnimg.cn/blog_migrate/dc163dcce54a1394e06f67316fe02022.png)
编译运行:
![](https://i-blog.csdnimg.cn/blog_migrate/292bd1cbc29d7445031fe1c3e8ee59c1.png)
我们来查看一下它的内容:
![](https://i-blog.csdnimg.cn/blog_migrate/a24b43e6bbfcf35ce5811d509b2c7f62.png)
这时,采用另外一个命令:
![](https://i-blog.csdnimg.cn/blog_migrate/dbcc58cef2b3df9bfae3125b1ecae81d.png)
这时,我们查看一下其大小:
![](https://i-blog.csdnimg.cn/blog_migrate/a9fb51b6a5a8c3325c8b7cbf0e68d42f.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c9e619694442b9ff2056873db0dd6f80.png)
这时,为了说明空洞内容是没有存放在磁盘中的,这时,我们将偏移量加大:
![](https://i-blog.csdnimg.cn/blog_migrate/5da3c996cb1fd68dd17b60d73cef28de.png)
编译运行,来查看下内容大小:
![](https://i-blog.csdnimg.cn/blog_migrate/edebc0296c8a3f43fd95fe12b43ba67a.png)
总结:
一个文件的大小不等于一个文件在磁盘所占用的空间,下面再来简单说明下:
![](https://i-blog.csdnimg.cn/blog_migrate/d9a4b8063d1d5e7345320c4809c3b6b8.png)
目录访问:
![](https://i-blog.csdnimg.cn/blog_migrate/066f3d885e980ba08fe0c24d503f64b6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9c76e07a97423af34ad1979566dbc198.png)
![](https://i-blog.csdnimg.cn/blog_migrate/987db8cedca8e69d3b95005ba5ec425f.png)
说明:struct dirent目录信息结构体的核心结构如下:
![](https://i-blog.csdnimg.cn/blog_migrate/c71b0ef7cfa1ead50af6557a24634188.png)
下面以一个具体示例来使用上面的这些目录函数
【功能跟ls命令类似,简易版】:
![](https://i-blog.csdnimg.cn/blog_migrate/09581ac6f0cdae765e88ead5de157fe3.png)
编译运行:
![](https://i-blog.csdnimg.cn/blog_migrate/8c1faa9e9bb991aa1595daeb4dde8614.png)
如果想过滤掉隐藏文件,则可以修下代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/90f2781aee9360039e3c5898f13dd7be.png)
再次运行:
![](https://i-blog.csdnimg.cn/blog_migrate/4b9cb4b95718c96ced3a624dba0325a0.png)
下面还有一些命令函数,比较简单,这里就不练习了,贴出来参考:
mkdir:
![](https://i-blog.csdnimg.cn/blog_migrate/d634eafa9ebce28ad4512a01e3a3be5a.png)
rmdir:
![](https://i-blog.csdnimg.cn/blog_migrate/17fa86fbd9e6baca3af4fca5f0568e98.png)
chmod
和
fchmod:
![](https://i-blog.csdnimg.cn/blog_migrate/2e4174c15426a34c4e64ce77364a312b.png)
chown
和
fchown:
![](https://i-blog.csdnimg.cn/blog_migrate/1a434b1375fbaa1f883356ee89de4496.png)
好了,今天的内容学到这,下回见!