linux编程学习笔记(八) 文件 定位 lseek pread pwrite

来源:互联网 发布:英文翻译软件 编辑:程序博客网 时间:2024/05/21 08:37

原地址:http://blog.csdn.net/a8887396/article/details/9009411


1IO的共享和效率

read与write其中数据缓冲的大小建设设置为:getpagesize (一页的大小)
或者4092


2 定位与读取数据(随机读取)

read和write时自动移动读取位置
lseek改变读取位置
pread/pwrite在指定位置读写

2.1lseek函数说明
       off_t lseek(int fd, //文件描述符 
off_t offset,//偏移 
int whence);//定位参数 开始SEEK_SET, 当前位置SEEK_CUR , 结束SEEK_END

返回值:当前读取在文件中的绝地位置


3 例子

[cpp] view plaincopy
  1. #include <sys/types.h>  
  2.    #include <sys/stat.h>  
  3.  #include <fcntl.h>  
  4. #include <unistd.h>  
  5. #include <stdlib.h>  
  6. #include <stdio.h>  
  7. //注意这里 为了以后读取方便 请人为对齐 不要让计算机来对齐  
  8. struct stu  
  9. {  
  10.     int no;  
  11.     char name[16];  
  12.     float score;  
  13. };  
  14.   
  15. int openfile(const char* filename)  
  16. {  
  17.     int fd = open(filename,O_WRONLY|O_CREAT|O_EXCL,0666);  
  18.     if(fd < 0)  
  19.     {  
  20.         perror("open error!");  
  21.     }  
  22.       
  23.     return fd;  
  24. }  
  25.   
  26. void input(struct stu *record)  
  27. {  
  28.         printf("请输入学生ID:");  
  29.         scanf("%d",&(record->no));  
  30.         printf("请输入学生姓名:");  
  31.         scanf("%s",record->name);  
  32.         printf("请输入学生成绩:");  
  33.         scanf("%f",&(record->score));  
  34. }  
  35.   
  36. void save(int fd,struct stu* record)  
  37. {  
  38.     write(fd,record,sizeof(struct stu));  
  39. }  
  40.   
  41. int  iscontinue()  
  42. {  
  43.     char c;  
  44.     printf("是否继续输入:y/n\n");  
  45.     scanf("%c",&c);  
  46.     scanf("%c",&c);  
  47.     if(c == 'y')  
  48.     {  
  49.         return 1;  
  50.     }  
  51.     else  
  52.         return 0;  
  53. }  
  54.   
  55. int main()  
  56. {  
  57.       
  58.     int fd =openfile("stu.dat");  
  59.     if(fd < 0)  
  60.     {  
  61.         return 1;  
  62.     }  
  63.     struct stu  record;  
  64.     while(1)  
  65.     {  
  66.         input(&record);  
  67.         save(fd,&record);  
  68.   
  69.         if(! iscontinue() )  
  70.         {  
  71.             break;  
  72.         }  
  73.     }  
  74.     close(fd);  
  75. }  


[cpp] view plaincopy
  1. /*读取文件中的姓名 
  2. 文件以结构体的形式写入 
  3. struct stu 
  4. { 
  5.     int no; 
  6.     char name[16]; 
  7.     float score; 
  8. }; 
  9. */  
  10. #include <stdio.h>  
  11. #include <unistd.h>  
  12. #include <fcntl.h>  
  13. #include <sys/types.h>  
  14. int main()  
  15. {  
  16.     int fd = open("stu.dat",O_RDONLY);  
  17.     if(fd < 0)  
  18.     {  
  19.         perror("open");  
  20.         return 1;  
  21.     }  
  22.     int i = 0;  
  23.     char buf[4092];  
  24.     lseek(fd,i*24+4,SEEK_SET);   
  25.     while(read(fd,buf,16))  
  26.     {  
  27.         printf("%s ",buf);  
  28.         i++;  
  29.         lseek(fd,i*24+4,SEEK_SET);  
  30.     }  
  31.     printf("\n");  
  32.     close(fd);    
  33. }  

4  lseek的定位位置超出文件大小时会发生什么?

1 lseek只要位置合法(绝对位置>=0),返回值都是当前位置

位置可以超出文件范围,只要不写入文件大小不会变化
[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <fcntl.h>  
  4. #include <sys/types.h>  
  5. int main()  
  6. {  
  7.     int fd = open("dat",O_RDWR|O_CREAT,0666);  
  8.     if(fd < 0)  
  9.     {  
  10.         perror("open");  
  11.         return 1;  
  12.     }  
  13.     int r = lseek(fd,2000,SEEK_SET);  
  14.     printf("%d\n",r);  
  15.     close(fd);    
  16. }  



zhao@ubuntu:~/unix/4$ ./lseek2 
2000
zhao@ubuntu:~/unix/4$ ls -l dat
-rw-r--r-- 1 zhao zhao 0 2013-06-01 04:59 dat


lseek超出文件范围,写入后文件大小会多出很多
[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <fcntl.h>  
  4. #include <sys/types.h>  
  5. int main()  
  6. {  
  7.     int fd = open("dat",O_RDWR|O_CREAT,0666);  
  8.     if(fd < 0)  
  9.     {  
  10.         perror("open");  
  11.         return 1;  
  12.     }  
  13.     int r = lseek(fd,2000,SEEK_SET);  
  14.     printf("%d\n",r);  
  15.     write(fd,"hello"5);  
  16.     close(fd);    
  17. }  


zhao@ubuntu:~/unix/4$ ls -l dat
-rw-r--r-- 1 zhao zhao 2005 2013-06-01 05:02 d

2 若是位置不合法 ,比如负数,返回-1





5  pread pwrite

函数描述
       #include <unistd.h>
       ssize_t pread(int fd, void *buf, size_t count, off_t offset); //注意offset是绝对位置
       ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);


pread=lseek+read
pwrite=lseek+write
返回值
读写的数据大小,出错返回-1


[cpp] view plaincopy
  1. //读取文件中的姓名    
  2. #include <stdio.h>  
  3. #include <unistd.h>  
  4. #include <fcntl.h>  
  5. #include <sys/types.h>  
  6.   
  7.   
  8. int main()  
  9. {  
  10.     int fd = open("stu.dat",O_RDONLY);  
  11.     if(fd < 0)  
  12.     {  
  13.         perror("open");  
  14.         return 1;  
  15.     }  
  16.     int i = 0;  
  17.     char buf[4092];  
  18.     while(pread(fd,buf,16,i*24+4))  
  19.     {  
  20.         printf("%s ",buf);  
  21.         i++;  
  22.     }  
  23.     printf("\n");  
  24.     close(fd);    
  25. }  



pread pwrite会改变读写位置吗?
    pread() reads up to count bytes from file descriptor fd at offset  off‐
       set  (from the start of the file) into the buffer starting at buf.  The
       file offset is not changed.


       pwrite() writes up to count bytes from the buffer starting  at  buf  to
       the  file  descriptor  fd  at  offset  offset.   The file offset is not

       changed.

记住 都不改变读写位置 , 这就是它们和lseek+read/write的区别



案例 读取/proc/$(pid)/mem 文件(虚拟内存 )


[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <unistd.h>  
  3. #include <fcntl.h>  
  4. #include <sys/types.h>  
  5. #include <string.h>  
  6.   
  7.   
  8. int a = 91119;  
  9. int main()  
  10. {  
  11.   
  12.   
  13.     char filename[20];  
  14.     memset(filename,0,20);  
  15.     sprintf(filename,"/proc/%d/mem",getpid());  
  16.     //mem文件 虚拟内存空间映射到mem上了  
  17.       
  18.       
  19.     int fd = open(filename,O_RDWR);  
  20.     if(fd < 0)  
  21.     {  
  22.         perror("open error");  
  23.         return 1;  
  24.     }  
  25.       
  26.     //读取&a这个位置的地址  
  27.     int t;  
  28.     pread(fd,&t,4,(off_t)&a);  
  29.     printf("t:%d\n",t); //91119  
  30.       
  31.       
  32.     t = 88888;  
  33.     pwrite(fd,&t,4,(off_t)&a);//往所在a的地方写数据  
  34.     printf("a=%d\n",a); //没有改变 因为系统没有给写的权限  
  35.       
  36. }  
0 0