操作系统是一个用来和计算机硬件打交道并为用户程序提供一个有限服务集的低级支撑软件。一个计算机系统是一个由硬件和软件组成的共生体,它们互相依赖,不可分割。但是硬件若没有软件来操作和控制,它们自身是不能工作的,而完成上述控制工作的软件就称为操作系统(Operation System)
Linux操作系统是最受欢迎的计算机操作系统之一,它是一个用C语言写成并符合POSIX标准的类UNIX操作系统。Linux操作系统最早是1991年由芬兰黑客Linus Torvalds为尝试在英特尔x86架构上提供自由免费的类UNIX操作系统而开发的。为了让LINUX系统支持网络通信功能,TCP/IP协议被集成到了LINUX操作系统的内核之中。
在LINUX操作系统中,所有的设备都看作是一种具体的文件,LINUX操作系统提供了以下一组(共包括六个)基本的系统函数,用来对本地设备或文件进行I/O操作。
1、open()函数
该函数用于打开一个文件(设备),其返回值为一个整形变量,若返回值为-1,则表示调用open函数打开文件时出错;否则,则表示打开成功,此时,返回值也成为所打开文件的文件描述符(File Descriptor)。
函数原型:
#include <sys/types.h> //基本数据类型头文件,含有基本系统数据类型的定义
#include <sys/stat.h> //文件状态头文件,含有文件或文件系统状态结构和常量的定义
#include <fcntl.h> //文件控制头文件,含有文件及其描述符的操作控制常数符号的定义
int open(const char * pathname,int flags,mode_t mode);
各参数含义:
pathname: 指向欲打开的文件路径字符串。
flags:文件打开方式的标志,主要包括以下几种。
① O_RDONLY: 以只读的方式打开文件。
② O_WRONLY: 以只写的方式打开文件。
③ O_RDWR: 以可以读写的方式打开文件。
*上述三种文件打开方式标志是互斥的,不可以同时使用,但可与下列文件打开方式标志利用OR( | )运算符进行组合
④ O_CREAT: 若欲打开的文件不存在则自动建立该文件。
⑤ O_APPEND: 当写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件末尾。
⑥ O_TRUNC: 若文件存在并且以可写的方式打开时,此标志会令文件长度清零。
mode: 被打开文件的存取权限,只有在新建文件时才会生效,即只有当flags取值中有O_CREAAT时才有效。
2、close()函数
该函数用于关闭open()函数所打开一个文件(设备),若调用成功时将返回0;若调用出错则返回-1。
函数原型:
#include <unistd.h> //LINUX标准头文件,包含了各种LINUX系统服务函数原型、符号常数和类型定义
int close(int fd);
各参数含义:
fd: 欲要关闭文件的文件描述符。
3、read()函数
该函数用于从指定的文件(由文件描述符参数fd指定)中读取制定的字节数据(由参数count指定)存放到指定的缓存区(由参数buf指定)之中。调用成功时返回读取的字符数;若返回0表示已到达文件尾;若返回-1则表示调用时出错。
函数原型:
#include <unistd.h>
ssize_t read(int fd,void *buf,size_t count);
各参数含义:
fd:指定文件的文件描述符。
buf:指定用来存储所读取数据的缓冲区。
count:指定要读取的字节数。在读取普通文件时,若读取到要求的字节数之前已达到文件尾部,则返回的字节数将会小于 希望读取的字节数count。
* 数据类型ssize_t 是signed size_t,而数据类型size_t是标准c库中定义的,表示unsigned int。
4、write()函数
该函数用于向指定的文件中写入指定的字节数据存放到指定的缓存区之中。调用成功时返回实;际写入的字节数;若调用出错则返回-1。
函数原型:
#include <unistd.h>
ssize_t write(int fd, const void *buf,size_t count);
各参数含义:
fd:指定文件的文件描述符。
buf:指定存储写入数据的缓冲区。
count:指定写入的字节数。
5、lseek()函数
该函数用于移动文件的读写指针,,更改打开文件的偏移量,实现在文件内部的定位。调用成功时返回所设置的新的偏移量;若调用出错则返回-1。
函数原型:
#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fd,off_t offset,int whence);
各参数含义:
fd:文件描述符。
offset:偏移量,每一次读写操作所需要移动的距离,单位是字节的数量,可正可负(为正时表示从当前基点位置向前移动,为负时表示从当前基点位置向后移动)。
whence:表示当前基点位置,取值如下。
① SEEK_SET: 当前基点位置为文件的开头,新位置为偏移量的大小。
② SEEK_CUR: 当前基点位置为文件指针位置,新位置为当前位置加上偏移量。
③ SEEK_END: 当前基点位置为文件结尾,新的位置为文件的大小加上偏移量。
6、ioctl()函数
该函数是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对设备的I/O通道进行管理,就是对设备的一些特性进行控制。尽管多数情况下硬件设备的操作可以通过文件的read、write、lseek等操作来实现,但总由一些特例,如弹出光盘、让磁带机倒带、设置声卡的采样率等,当需要对设备的上述这类特性进行控制时,就需要用到ioctl()函数。若调用成功时返回0;若调用出错则返回-1;
函数原型:
#include <sys/ioctl.h> //该头文件包含了I/O控制函数的定义
int ioctl(int fd,int cmd,...);
各参数含义:
fd:文件(设备)的文件描述符。
cmd:用户程序对设备的控制命令。
* ioctl是一个可变长参数的函数。可变长参数的原型为type VAFunction(type arg1,arg2,...);参数可以分为个数确定的固定参数和个数可选的可变参数两部分。函数至少需要一个固定参数,固定参数的声明和普通函数一样;可选参数 由于个数不确定,可有可无,需要根据实际情况而定,声明时用"..."表示。固定参数和可选参数共同构成一个函数的参数列表。
用法示例:
1、open()、read()、write()、lseek()、close()示例:
#include <unistd.h> //文件操作函数需要的头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char *buf = "Hello! I'm writing to this file"; //定义一个指向包含有十个字符的字符常量的字符型指针
char buf_r[11]; //定义一个长度为11的字符型数组变量
int fd,size,len;
len = strlen(buf);
if((fd = open("hello.c",O_CREAT|O_TRUNC|O_RDWR,0666))<0)
{
perror("open faild"); //
exit(1);
}
else printf("open is ok\n");
if((size=write(fd,buf,len))<0)
{
perror("write:");
exit(1);
}else{
printf("write is ok");
}
lseek(fd,0,SEEK_SET); //定位到文件开头位置
if((size=read(fd,buf_r,10))<0)
{
perror("write");
exit(1);
}else printf("write ok\n");
lseek(fd,0,SEEK_SET);
if((size = read(fd,buf_r,10))<0)
{
perror("read faild");
exit(1);
}else printf("read ok %s\n",buf_r);
if(close(fd)<0)
{
perror("close faild");
exit(1);
}else printf("close ok");
return 0;
}
2、 ioctl()示例
以下例程介绍了如何通过对/dev/audio编程来对声卡的采样频率进行设置。
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/soundcard.h> //声卡支持函数头文件
//对声卡采样频率进行设置
int audio_fd;
int format;
audio_fd = open("/dev/audio",O_WRONLY,0); //打开声音采集/播放设备
format = AFMT_S16_LE; //设置采样频率
ioctl(audio_fd,SNDCTL_DSP_SETFMT,&format);