Linux----文件I/O

1.文件描述符每次我们打开一个文件,就会得到一个对应于该文件的较小的整数,这个整数就是这个文件的文件描述符。在shell操作中,0,1,2这三个文件描述附总是打开的,通常是指向shell运行所在的终端。0对应于标准输入,1对应于标准输出,2对应于标准错误。因为0,1,2这三个文件描述符总是打开的,所以一般我们打开一个文件时,该文件所对应的文件描述符为3,再打开一个文件时,新打开的文件描述符为4,以此类推...

举例:

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
int main()
{
	int fd1, fd2, fd3;
	fd1 = open("1.txt", O_RDONLY);     //open the first file
	fd2 = open("2.txt", O_RDONLY);    //open the second file
	fd3 = open("3.txt", O_RDONLY);    //open the third file
	cout << fd1 << endl;                     //the first file describe
	cout << fd2 << endl;                     //the second file describe
	cout << fd3 << endl;                     //the third file describe
	return 0;
}
运行结果:

liu@liu:~$ ./fd
3
4
5
通过上述结果,可以得知,新打开的文件的文件描述符从3开始,依次为3,4,5,6...等等


2.与文件I/O相关最常用的系统调用:

   open()

   write()

   read()

   close()

   具体用法使用 man 2 open, man 2 write等具体查看。


3.文件I/O实例:

源码:

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
int main()
{
	int sourceFd, desFd;
	ssize_t sizeRead, sizeWrite;
	char buf[80];
	sourceFd = open("source.txt", O_RDONLY); //以只读方式打开source.txt
	desFd = open("des.txt", O_RDWR|O_TRUNC); //以读写方式打开des.txt,并且清空des.txt中的内容
	sizeRead = read(sourceFd, buf, sizeof(buf)); //读取source.txt中的内容
	sizeWrite = write(desFd, buf, sizeRead); //将读取的内容写入des.txt中
	close(sourceFd);
	close(desFd);
}
执行之前:

liu@liu:~$ cat source.txt 
......
liu@liu:~$ cat des.txt 
......
lllllllll
kkkkkkkkkk
执行之后:

liu@liu:~$ cat source.txt 
......
liu@liu:~$ cat des.txt 
......


4.文件偏移量

         对于每个打开的文件,系统内核都会记录其文件偏移量,文件偏移量是只下一个read()或write()操作文件的起始     位置,文件偏移量通过lseek()改变或获取。

     lseek()并不适用于所有类型的文件,不允许将lseek()应用于管道、FIFO、socket或者终端。

        文件空洞:如果程序的文件偏移量已经跨越了文件结尾,从文件结尾到新写入数据间的这段空间被称为文件空洞。


     lseek()使用实例:   

cur = lseek(fd, 0, SEEK_CUR); //获取当前文件偏移量
lseek(fd, 0, SEEK_SET);  //将文件偏移量移到文件开头
   

     lseek()实例:

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
int main()
{
	int fd;
	char buffer[10] = "hahaha";  //待写入的字符串
	fd = open("source.txt", O_RDWR); //打开source.txt
	lseek(fd, 5, SEEK_END); //SEEK_SET表示从头开始定位,10表示向后10位
	write(fd, buffer, sizeof(buffer)); //将buffer中的内容写入source.txt中
	close(fd);
}
代码执行前:

liu@liu:~$ cat source.txt 
fuck you.
代码执行后:

liu@liu:~$ cat source.txt 
fuck you.
hahaha


5.以上所述为通用文件I/O操作,除通用I/O操作之外,还有ioctl(),需要用到时自己查阅。


6.原子操作:所有的系统调用都是以原子操作方式执行的,也就是说,在系统调用执行期间,该系统调用不会被其他进程或者线程所中断。


7.设置或获取文件的访问模式和状态标记:使用fcntl()

实例:

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
int main()
{
	int fd, flags, accessMode;
	fd = open("source.txt", O_RDWR);  //以可读可写的方式打开source.txt
	
	//打开文件失败
	if(-1 == fd)
		cout << "open file error." << endl;
	
	//打开文件成功,通过fcntl获取source.txt的状态标记
	flags = fcntl(fd, F_GETFL); //第二个参数设为F_GETFL,表示此时fcntl系统调用用于获取source.txt的状态标记
	if(-1 == flags)  //获取source.txt的状态标记失败
	    cout << "can't get the configure of source.txt" << endl;
	if(flags & O_SYNC)   //如果open source.txt时设置了O_SYNC
	    cout << "writes are synchronized." << endl;
	else   //如果open source.txt时没有设置O_SYNC
	    cout << "writes are not synchronized." << endl;

	//通过fcntl设置source.txt的访问模式
	accessMode = flags & O_ACCMODE;
	if(accessMode == O_WRONLY || accessMode == O_RDWR)
	    cout << "source.txt is writable." << endl;

	//通过fcntl设置source.txt的状态标记,此处给sourge.txt添加O_APPEND标记
	flags |= O_APPEND;
	if(-1 == fcntl(fd, F_SETFL, flags))   //添加O_APPEND状态失败
	    cout << "config error" << endl;
	else                                  //添加O_APPEND状态成功
	    cout << "add the O_APPEND status success." << endl;
}

执行结果:

liu@liu:~$ ./fcntl1 
writes are not synchronized.
source.txt is writable.
add the O_APPEND status success.

7.文件描述符和打开文件之间的关系:

  • 两个不同的文件描述符,若指向同一个打开文件句柄,则共享同一文件偏移量
  • 文件描述符标志(即close-on-exec)为进程和文件描述符所有私有   

8.复制文件描述符:使用dup(), dup2(), fcntl() 都可以完成

 

  dup使用实例: 

<span style="font-family:SimSun;font-size:14px;">#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
int main()
{
	int oldFd, newFd;
	oldFd = open("1.txt", O_RDWR);
	newFd = dup(oldFd);   //复制文件描述符,使oldFd,newFd都指向1.txt
	cout << oldFd << " " << newFd << endl;
}</span>
     执行结果:

liu@liu:~$ ./dup 
3 4

    dup2()使用实例:

<span style="font-size:14px;">#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
int main()
{
	int oldFd, newFd;
	oldFd = open("1.txt", O_RDWR);
	newFd = dup2(oldFd, 10);  //复制文件描述符为10
	cout << "old file describe: " << oldFd << endl;
	cout << "new file describe: " << newFd << endl;
}</span>

     运行结果:

liu@liu:~$ ./dup2 
old file describe: 3
new file describe: 10

     使用fcntl()复制文件描述符实例:

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
int main()
{
	int oldFd, newFd;
	oldFd = open("1.txt", O_RDWR);
	newFd = fcntl(oldFd, F_DUPFD, 12); //复制文件描述符,从12开始取最小整数作为文件描述符
	cout << "old file describe: " << oldFd << endl;
	cout << "new file describe: " << newFd << endl;
}
    运行结果:

liu@liu:~$ ./fcntl
old file describe: 3
new file describe: 12

9.在文件特定偏移量处进行读写:使用pread()和pwrite()

   pwrite()使用实例:

<span style="font-size:14px;">#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using namespace std;
int main()
{
	int fd, curPos;
	char buf[80] = "i love china.";
	fd = open("1.txt", O_RDWR);
	curPos = lseek(fd, 0, SEEK_CUR);
	cout << curPos << endl;   //获取当前位置偏移量
	pwrite(fd, buf, sizeof(buf), 50); //在指定位置第50个字节处进行读写
}</span>
    运行之前:

<span style="font-family:SimSun;">liu@liu:~$ cat 1.txt
fuck you. what a big fuck!
i love beijing.</span>

    运行之后:

liu@liu:~$ cat 1.txt 
fuck you. what a big fuck!
i love beijing.
i love china.

10.分散输入和集中输出:readv()和writev()

     readv()是将一个文件读到几个分散的地方,即读到buf1, buf2处

     writev()是将几个分散的地方的内容连续的写到一个文件中去


     readv()和writev()使用实例:

#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <unistd.h>
using namespace std;
int main()
{
	int fd1, fd2;
	int wsize, rsize;
	char buf1[10], buf2[5];
	struct iovec iov[2];
	fd1 = open("a.txt", O_RDWR);
	if(-1 == fd1)
		cout << "open error." << endl;

	iov[0].iov_base = buf1;
	iov[0].iov_len = sizeof(buf1);
	iov[1].iov_base = buf2;
	iov[1].iov_len = sizeof(buf2);
	
	rsize = readv(fd1, iov, 2);   //将a.txt中的内容按序分别读出到buf1和buf2中,即buf1中写入a.txt的前10个字符,buf2中写入a.txt接着的5个字符
	cout << "read size : " << rsize << endl; //输出从a.txt中读到的字符总数
	
	fd2 = open("b.txt", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
	if(fd2 < 0)
	     cout << "open error." << endl;
	wsize = writev(fd2, iov, 2);   //将buf1和buf2中的内容写到b.txt中
	cout << "write size : " << wsize << endl;

	close(fd1);
	close(fd2);
}
    运行结果:

liu@liu:~$ ./readv 
read size : 15
write size : 15

11.将文件大小设置为指定的值:truncat(), ftruncate()

     原型: int truncate(const char *path, off_t length);
                 int ftruncate(int fd, off_t length);

     将文件大小设为 length 指定的值,如果文件的大小比指定的值大,则截去末尾的一部分;如果文件的大小比指定的值小,则在文件添加一系列空字节或一个文件空洞。


12.大文件的读写:

     在32位的体系结构中,文件的大小被限定在2GB之内; 然而磁盘驱动器的容量早已超过了这一限制,因此时常有处理超过2GB文件的需求。

    处理大文件I/O最常用的方法:

     在源文件添加  

#define _FILE_OFFSET_BITS 64

13.创建临时文件:mkstemp(), tmpfile()

       

     mkdtemp原型: char *mkdtemp(char *template);

              为了保证临时文件名的唯一,template的最后六位一定要是XXXXXX

     maktemp使用实例:

<span style="font-size:14px;">#include <iostream>
#include <stdlib.h>
#include <unistd.h>
using namespace std;
int main()
{
	int fd;
	char temp[] = "/tmp/somestringXXXXXX";
	fd = mkstemp(temp);
	if(-1 == fd)
		cout << "create template file fail." << endl;
	cout << "Generated file name is " << temp << endl
	if(-1 == close(fd))
		cout << "close fail." << endl;
} </span>
          运行结果:

<span style="font-size:14px;">liu@liu:~$ ./temp
Generated file name is /tmp/somestringG5ruj9</span>

        tmpfile使用实例:

<span style="font-size:14px;">#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
	FILE *temp;
	temp = tmpfile();
	if(temp)
		cout << "template file created." << endl;
	else
		cout << "template file created fail." << endl;
}</span>
     运行结果:

<span style="font-size:18px;">liu@liu:~$ ./temp2
template file created.</span>



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值