本文章将详细的讲解Linux下基本的文件I/O操作,以及文件的高级操作。
本文代码运行在codeblocks的IDE中,Linux系统采用的是Ubuntu12.04
1.1 文件描述符
文件描述符就相当于文件的身份证号,通过它来标示文件,文件描述符是一个非负整数。表示为int类型的对象,它是一个索引值,指向内核中每个进程打开文件的记录表。
每个进程都可以拥有若干个文件描述符,Linux中每个进程可以拥有1024个文件描述符。
文件描述符中0是标准输入文件,对应键盘,符号常量为STDIN_FILENO;1是标准输出文件,对应显示器,符号常量为STDOUT_FILENO ; 2是标准错误输出文件,符号常量为STDERR_FILENO,他们都定义在<unistd.h>中
1.2 基本文件I/O操作
这些基本的I/O操作函数的头文件如下:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
1.2.1 open函数
功能:打开或者创建一个文件,open函数是一个进程存取一个文件中的数据必须首先完成的系统调用。
格式:int open( const char* pathname, int flag, .../* mode_t mode */ );
返回值:成功时返回一个int的非负整数,此时是最小编号的文件描述符,失败时返回-1
参数说明:pathname表示要打开或者创建的文件名;
flag表示打开方式,其中常用的O_RDONLY,O_WRONLY,O_RDWR分别表示只读、只写、可读/写方式打开文件。常用的标志还有O_CREAT,表示若此文件不存在,则创建,使用此选项时,要用到mode参数以设定新文件的访问权限。其他不常用的标志还有:
O_APPEND(在文件尾端追加)
O_EXCL 测试一个文件是否存在。
O_TRUNC 如果文件成功打开,则将其长度截短为0。
O_NOCTTY 如果pathname参数指的是终端设备,则不将该设备作为此进程的控制终端。
O_NONBLOCK 如果pathname指的是一个FIFO,块特殊文件或字符特殊文件,则该选项为文件的本次打开操作和后续的I/O操作设置非阻塞模式。
O_DSYNC 使该文件所有的write操作等待,直到对该文件所有的I/O操作都完成之后,但是如果write操作不影响读取刚写入的数据时,不用等待文件属性被更新。
O_RSYNC 使该文件所有的read操作等待,直到对该文件所有的write操作都完成之后。
O_SYNC 使该文件所有的write操作等待,直到对该文件所有的I/O操作都完成之后。
在这儿注意:除了常用的三种标志外,其他的标志可以通过&来结合使用,三种读写的标志只能使用一个!!!!
mode表示在创建一个新文件时设定的新文件的权限。
1.2.2 close 函数
功能:关闭不再使用的文件
格式:int close( int fd );
返回值:成功返回0,反之返回-1
1.2.3 read 函数
功能:从文件中读取指定长度的数据到内存中。
格式:ssize_t read( int fd, void *buf, size_t count);
返回值:成功返回读到的字节数,若已到文件结尾返回0,出错返回-1。
参数说明:fd表示文件描述符;buf表示输入缓冲区指针;count表示要读入的字节数。
备注:read函数是从fd指定的文件中读取count个字节到buf中,如果count为0,那么该系统调用返回0;如果该count大于SSIZE_MAX,则结果不能确定。
1.2.4 write 函数
功能:从内存中写指定长度的数据到文件中。
格式:ssize_t write( int fd, void *buf, size_t count);
返回值:成功返回已写的字节数,出错返回-1。。
参数说明:fd表示文件描述符;buf表示输出缓冲区指针;count表示要写的字节数。
1.2.5 creat 函数
功能:创建一个文件。
格式:int creat(const char * pathname,mode_t mode)
返回值:成功返回该文件的文件描述符,出错返回-1。
参数说明:pathname表示创建的文件名,创建的文件以只读方式打开。mode表示该文件的权限
1.2.6 lseek 函数
功能:文件偏移
格式:off_t lseek( int fd, off_t offset, int whence );
返回值:成功时返回新的文件偏移量,失败时返回-1
参数说明:fd表示文件描述符。offset表示偏移量,whence表示当前位置的基点,其中取值为如下三种:
SEEK_SET 将文件的读写偏移量设置为距离文件首段offset个字节处。
SEEK_CUR 将文件的读写偏移量设置为距离当前值加offset个字节处,offset可为正负。
SEEK_END 将文件的读写偏移量设置为距离文件尾端offset个字节处,offset可为正负。
下面是关于这些基本函数的两个例子:
其中,下面的这个程序实现同样的功能
本文代码运行在codeblocks的IDE中,Linux系统采用的是Ubuntu12.04
1.1 文件描述符
文件描述符就相当于文件的身份证号,通过它来标示文件,文件描述符是一个非负整数。表示为int类型的对象,它是一个索引值,指向内核中每个进程打开文件的记录表。
每个进程都可以拥有若干个文件描述符,Linux中每个进程可以拥有1024个文件描述符。
文件描述符中0是标准输入文件,对应键盘,符号常量为STDIN_FILENO;1是标准输出文件,对应显示器,符号常量为STDOUT_FILENO ; 2是标准错误输出文件,符号常量为STDERR_FILENO,他们都定义在<unistd.h>中
1.2 基本文件I/O操作
这些基本的I/O操作函数的头文件如下:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
1.2.1 open函数
功能:打开或者创建一个文件,open函数是一个进程存取一个文件中的数据必须首先完成的系统调用。
格式:int open( const char* pathname, int flag, .../* mode_t mode */ );
返回值:成功时返回一个int的非负整数,此时是最小编号的文件描述符,失败时返回-1
参数说明:pathname表示要打开或者创建的文件名;
flag表示打开方式,其中常用的O_RDONLY,O_WRONLY,O_RDWR分别表示只读、只写、可读/写方式打开文件。常用的标志还有O_CREAT,表示若此文件不存在,则创建,使用此选项时,要用到mode参数以设定新文件的访问权限。其他不常用的标志还有:
O_APPEND(在文件尾端追加)
O_EXCL 测试一个文件是否存在。
O_TRUNC 如果文件成功打开,则将其长度截短为0。
O_NOCTTY 如果pathname参数指的是终端设备,则不将该设备作为此进程的控制终端。
O_NONBLOCK 如果pathname指的是一个FIFO,块特殊文件或字符特殊文件,则该选项为文件的本次打开操作和后续的I/O操作设置非阻塞模式。
O_DSYNC 使该文件所有的write操作等待,直到对该文件所有的I/O操作都完成之后,但是如果write操作不影响读取刚写入的数据时,不用等待文件属性被更新。
O_RSYNC 使该文件所有的read操作等待,直到对该文件所有的write操作都完成之后。
O_SYNC 使该文件所有的write操作等待,直到对该文件所有的I/O操作都完成之后。
在这儿注意:除了常用的三种标志外,其他的标志可以通过&来结合使用,三种读写的标志只能使用一个!!!!
mode表示在创建一个新文件时设定的新文件的权限。
1.2.2 close 函数
功能:关闭不再使用的文件
格式:int close( int fd );
返回值:成功返回0,反之返回-1
1.2.3 read 函数
功能:从文件中读取指定长度的数据到内存中。
格式:ssize_t read( int fd, void *buf, size_t count);
返回值:成功返回读到的字节数,若已到文件结尾返回0,出错返回-1。
参数说明:fd表示文件描述符;buf表示输入缓冲区指针;count表示要读入的字节数。
备注:read函数是从fd指定的文件中读取count个字节到buf中,如果count为0,那么该系统调用返回0;如果该count大于SSIZE_MAX,则结果不能确定。
1.2.4 write 函数
功能:从内存中写指定长度的数据到文件中。
格式:ssize_t write( int fd, void *buf, size_t count);
返回值:成功返回已写的字节数,出错返回-1。。
参数说明:fd表示文件描述符;buf表示输出缓冲区指针;count表示要写的字节数。
1.2.5 creat 函数
功能:创建一个文件。
格式:int creat(const char * pathname,mode_t mode)
返回值:成功返回该文件的文件描述符,出错返回-1。
参数说明:pathname表示创建的文件名,创建的文件以只读方式打开。mode表示该文件的权限
1.2.6 lseek 函数
功能:文件偏移
格式:off_t lseek( int fd, off_t offset, int whence );
返回值:成功时返回新的文件偏移量,失败时返回-1
参数说明:fd表示文件描述符。offset表示偏移量,whence表示当前位置的基点,其中取值为如下三种:
SEEK_SET 将文件的读写偏移量设置为距离文件首段offset个字节处。
SEEK_CUR 将文件的读写偏移量设置为距离当前值加offset个字节处,offset可为正负。
SEEK_END 将文件的读写偏移量设置为距离文件尾端offset个字节处,offset可为正负。
下面是关于这些基本函数的两个例子:
简单复制函数:用于从一个文件中复制数据到一个新建的文件中,该程序是用于命令行中输入的
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h>
#define PERMS 0666 //文件权限
#define DUMMY 0 //mode 参数默认值
#define BUFSIZE 1024 //缓冲区大小
int main(int argc,char *argv[])
{
int source_fd,target_fd;//文件描述符
int num; //读取的数据大小
char iobuf[BUFSIZE];//缓冲区
if(argc!=3)
{
printf("参数错误\n");
return 1;
}
if((source_fd=open(*(argv+1),O_RDONLY,DUMMY))==-1)
{
printf("原文件打开失败\n");
return 2;
}
if((target_fd=open(*(argv+2),O_CREAT|O_WRONLY,PERMS))==-1)
{
printf("目标文件打开失败\n");
return 3;
}
while((num=read(source_fd,iobuf,BUFSIZE))>0)
{
if(write(target_fd,iobuf,num)!=num)
{
printf("目标文件写操作失败\n");
return 4;
}
}
close(source_fd);
close(target_fd);
return 0;
}
其中,下面的这个程序实现同样的功能
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<fcntl.h>
#define DUMMY 0
#define PERMS 0666
#define BUFSIZE 1024
int main()
{
int source_fd,target_fd;
int num;
char iobuf[BUFSIZE];
if((source_fd=open("tz.txt",O_RDONLY,DUMMY))==-1)
{
printf(" 打开原文件失败\n");
return 1;
}
if((target_fd=open("dq.txt",O_CREAT|O_WRONLY,PERMS))==-1)
{
printf("打开目标文件失败\n");
return 2;
}
while((num=read(source_fd,iobuf,BUFSIZE))>0)
{
if(num!=(write(target_fd,iobuf,num)))
{
printf("目标文件写操作失败\n");
return 3;
}
printf("%s\n",iobuf);
}
close(source_fd);
close(target_fd);
return 0;
}
对于结构体的复制:
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>
#define LNAME 9 //用户名长度
#define PERMS 0666 //文件权限
#define DATAFILE "datafile.txt" //写入数据的文件名
#define USERS 10 //用户结构大小
typedef struct user
{
int uid;
char login[LNAME+1];
}RECORD;
char *user_name[10]={"u1","u2","u3","u4","u5","u6","u7","u8","u9","admin"};
int main()
{
int i,fd;
RECORD rec;
if((fd=open(DATAFILE,O_WRONLY|O_TRUNC|O_CREAT,PERMS))==-1)
{
perror("open");
return 1;
}
for(i=USERS-1;i>=0;i--)
{
rec.uid=i;
strcpy(rec.login,user_name[i]);
lseek(fd,(long)i*sizeof(RECORD),SEEK_SET);
write(fd,(char *)&rec,sizeof(RECORD));
//printf("%d %s\n",rec.uid,rec.login);
}
lseek(fd,0L,SEEK_END);
close(fd);
return 0;
}