zoukankan      html  css  js  c++  java
  • 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>
    



  • 相关阅读:
    Android自己定义组件系列【2】——Scroller类
    ostringstream的使用方法
    什么是Spring?Spring是什么?
    天将降大任于斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱其所为,所以动心忍性,增益其所不能
    伤不起的戴尔台式机XPS8700脆弱的蓝牙
    cocos2d-x-3.1 事件分发机制 (coco2d-x 学习笔记七)
    SSL工作原理
    AfxMessageBox和MessageBox差别
    oninput,onpropertychange,onchange的使用方法和差别
    Bootstrap网站模板
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/6745006.html
Copyright © 2011-2022 走看看