文件I/O操作(1)

linux系统调用和用户编程接口(api)

系统调用是指在操作系统提供给用户程序调用的一组“特殊”的接口,用户程序可以通过这组特殊的接口来获取操作系统内核提供的服务,例如用户可以通过进程控制相关的系统调用来创建进程,实现进程调度,进程管理

为什么用户不能直接访问系统内核提供的服务?这是因为在linux中,为了更好地保护内核空间,将程序运行的空间分为内核空间和用户空间(也就是常称为的内核态和用户态)

内核态和用户态运行在不同的级别上,在逻辑上也是相互隔离的,新词用户进程在通常情况下是不允许范围内核数据,也无法使用内核的函数,他们只能在用户空间操作用户数据,调用用户空间的函数

但是,在有些情况下,用户空间的进程需要获得一定的系统服务,调用内核空间程序,这时操作系统就必须利用系统提供给用户的特殊接口,系统调用规定用户进程进入内核空间的具体位置,进行系统调用的时,程序从用户空间进入内核空间,处理完后在返回用户空间

linux系统调用部分是非常精简的系统调用(只有250)他继承了unix系统调用最基本和最有用的部分,这些系统调用按照功能和逻辑大致可以分为

进程控制,进程间通信,文件系统控制,系统控制,存储管理,网络管理,socket控制,用户管理

 

用户编程的api

前面讲到的系统调用便不是直接与程序员进行交互,它仅仅是一个软中断机制向内核提出请求,以获取内核服务的接口,在实际使用中,程序员调用的是用户编程对应的接口--api

linux中文件及文件描述符概述

在linux中对目录和设备的操作都等同于对文件的操作,因此大大简化了系统对不同设备的处理,linux中的文件主要分为4种,普通文件,目录文件,链接文件和设备文件,对于linux而言,所有对设备和文件的操作都是使用文件描述符来进行的

文件描述符是一个非负整数,他是一个索引值,并指向内核中每个进程打开文件的记录表,当打开一个现存文件,或者是创建一个新的文件时,内核就像进程返回一个文件描述符,但需要写入文件时,也需要吧文件描述符作为参数传递给相应的函数

 

通常一个进程启动时,都会打开三个文件,标准输入,标准输出,标准出错处理,对应文件描述符为0,1,2。

基于文件描述符的I/0操作虽然不能移植到类linux以外的系统上去(如windows)但它往往是实现某些I/0操作的唯一途径,基于文件描述符的I/O操作时linux中对常用的操作之一

 

底层文件I/O操作

这里主要是5个函数open(),read(),write(),lseek(),和close()这些函数的特点是不带缓存,直接对文件(包括设备)进行读写操作

open()函数用于打开或创建文件,在打开或创建文件时,可以指定文件的属性和用户的权限等各种参数。

close()是一个用于关闭一个被打开的文件。当一个进程终止时,所有被他打开的文件都由内核自动关闭,很多程序都使用这一功能而不显示的关闭一个文件

read()函数用于将从指定的文件描述符中读取数据放到缓存区,并返回实际读入的字节数,若返回0,则表示没有数据可读,即已经达到文件尾,读操作文件从文件的当前指针位置开始,当从终端设备文件中读取数据时,通常一次最多读取一行

write()函数用于向打开的文件中写入数据,写操作从文件的当前指针位置开始,对磁盘文件进行写操作,若磁盘已经写满,或者超出文件的长度,则write()函数返回失败

lseek()函数用于在指定的文件描述符中将文件的指针定位到相应的位置,它只能用在可定位(可随机访问)文件操作中,管道,套接字,和大部分字符设备文件是不可定位的,所以在这些文件的操作中无法使用lseek

open函数的原型 int open(const char *pathname ,int flags);pathname是指文件的路径名和名称,可以是绝对路径或者是相对路径,flag 是指定了文件的打开方式

O_RDONLY 以只读方式,要求文件存在

O_WRONLY以只写的方式打开,要求文件存在

O_RDWR可读可写的方式打开,要求文件存在

O_CREAT 创建文件

O_EXCL创建互斥

O_APPEND 以追加的方式写入首先要有写权限

O_TRUNC 清空原文件内容

返回值 为文件描述符,非负整数,文件后续操作的标志

open的另外一种原型为int open(const char *pathname,int flags,mode_t mode)前面的参数和一样,mode是指创建文件时的权限0x777 0x644 0x664等等

打开文件失败的原因分析:1文件不存在时指定可读,2文件所在目录无操作权限 3其他原因,文件操作权限,文件是否可用

close函数 函数原型为int close (int fd);

fd为open返回值的文件描述符,关闭文件后,该文件描述符将不可再用,返回值表示关闭是否成功,但我们编程时不处理该返回值,打开文件必须关闭,否则会造成文件描述符的泄漏,特别是异常情况,可以关闭0,1,2;

示例代码:

 

read 函数原型为 int read(int fd, void *buf,int count);fd为文件描述符(注意此处不能是文件名),buf为存储读取的内容的内存地址(指针),一定不能是野指针或者是空指针,count是本次读取的字节数,要求count要小于等于buf的大小,如果存储字符串时,返回值为成功读取的字节数,如果读取失败,返回小于0的值,返回值为0表示读取到文件末尾

示例代码:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

int main(void)
{
              int fd1,size;
              char buf[128];

              fd1 = open("/etc/net/works",O_RDONLY);
              if(fd1<0)
                     {
                        printf("open fail\n");
                        exit(0);
                     }
              while(1)
                      {
                         size = read(fd1,buf,64);
                         if(size<0)
                                {
                                 printf("read error\n");
                                 exit(1);
                                 }
                         if(size ==0break;
                         buf[size+1] = '\0';
                         printf("%s",buf);

                       } 
              close(fd1);
       
              return 0;  
}                                                                                        

memset用于在某段内存中填充那一个数,函数包含的头文件是#include<string.h>函数原型为

void *memset(void *s,int c,size_t n);例如memset(buf,0,,128);

注意 :read函数会自动对文件的操作位置进行偏移,读完几个字节,之后就偏移几个字节,自动偏移,如果到达文件末尾,不能再次偏移

如果读取失败的原因:

1文件的读取权限问题

2,文件没有内容,需要注意,如果使用O_TRUNC时,文件内容已经被清楚

3:如果该处出现段错误,这主要考虑内存指针是否为野指针或者是否越界

 

write函数;函数原型为 int write(int fd, void *buf,int count);

fd为写入的文件描述符,buf为需要写入的内容的指针,count是写入的字节数,这里的buf要小于buf的有效值,返回值为成功写入的字节数,返回值小于0表示写入失败

write也会对文件的操作位置进行偏移,如果为追加方式时,从文件的末尾开始写入,如果写入失败,如果写入失败,这分析原因为:1)文件是否有写权限,2)文件写入多错误时,可以查看内存是否越界,3)注意使用)O_TRUNC会清空原内容

#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<string.h>
#include<unistd.h>

int main(void)
{
        int fd1,fd2,size,f3;
        char buf[128];

        fd1 = open("/etc/xinetd.d/daytime",O_RDONLY);
        if(fd1<0)
        {
                printf("open fail\n");
                exit(1);
        }

        fd2 = open(""daytime1",O_RDWR|O_CREAT,777);
        if(fd2<0)
        {
                                                              1,1           Top
          printf("create daytime1 fail\n");
                exit(1);
        } 
        
        while(1)
        {
                memset(buf,0,127);
                size = read(fd1,buf,127);

                if(size<0)
                {
                        printf("read fail\n");
                        exit(1);
                }
                
                if(size==0)
                        break;

                buf[128]='\0';
                printf("%s",buf);


                f3 = write(fd2,buf,size);
                if(f3<0)
                {
                        printf("write fail\n");
                        exit(1);
                }

        }

        close(fd1);
        close(fd2);

        return 0;
}

 

 

 

 

 版权所有,转载请注明转载地址:http://www.cnblogs.com/fengdashen/p/3300614.html

 

 

posted @ 2013-09-04 16:48  跨七海的风  阅读(1307)  评论(0编辑  收藏  举报