Linux输入输出与文件_第1页
Linux输入输出与文件_第2页
Linux输入输出与文件_第3页
Linux输入输出与文件_第4页
Linux输入输出与文件_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C/C+教程 作者:高亚清LINUX输入输出与文件目 录1. 基于文件指针的文件操作(缓冲)21.1. 文件的创建,打开与关闭21.2. 读写文件31.3. 目录操作51.4. 标准输入/输出流62. 基于文件描述符的文件操作(非缓冲)62.1. 文件描述符62.2. 打开、创建和关闭文件72.3. 读写文件72.4. 文件定位82.5. 获取文件信息82.6. 文件的锁定92.7. 文件描述符的复制102.8. 标准输入输出文件描述符12 1. 基于文件指针的文件操作(缓冲)在Linux中,大多数的资源都可以以文件的方式进行处理,常见的文件类型有:l 普通文件l 无名管道和命名管道l 目录l

2、 设备l 符号连接l 套接字普通文件:也称磁盘文件,并且能够进行随机的数据存储(能够自由seek定位到某一个位置);管道:是一个从一端发送数据,另一端接收数据的数据通道;目录:也称为目录文件,它包含了保存在目录中文件列表的简单文件。设备:也称为特殊文件,该类型的文件提供了大多数物理设备的接口。它又分为两种类型:字符型设备和块设备。字符型设备一次只能读出和写入一个字节的数据,包括调制解调器、中端、打印机、声卡以及鼠标;块设备必须以一定大小的块来读出或者写入数据,块设备包括CD-ROM、RAM驱动器和磁盘驱动器等,一般而言,字符设备用于传输数据,块设备用于存储数据。符号链接:类似于Windows的

3、快捷方式和Linux里的别名,指包含到达另一个文件路径的文件。套接字:在Linux中,套接字也可以当作文件来进行处理。基于文件指针的文件操作函数是ANSI标准函数库的一部分。1.1. 文件的创建,打开与关闭原型为:#include <stdio.h>FILE *fopen(const char *pach,const char *mode);FILE *fdopen(int fd,const char *mode);int fclose(FILE *stream);fopen以mode的方式打开或创建文件,如果成功,将返回一个文件指针,失败则返回NULL.fopen创建的文件的访问

4、权限将以0666与当前的umask结合来确定。 mode的可选模式列表模式读写位置截断原内容创建rbYN文件头NNr+bYY文件头NNwbNY文件头YYw+bYY文件头YYabNY文件尾NYa+bYY文件尾NY在Linux系统中,mode里面的b(二进制)可以去掉,但是为了保持与其他系统的兼容性,建议不要去掉。ab和a+b为追加模式,在此两种模式下,无论文件读写点定位到何处,在写数据时都将是在文件末尾添加,所以比较适合于多进程写同一个文件的情况下保证数据的完整性。fdopen根据已经打开的文件描述符打开一文件指针,对同一个文件既打开文件描述符又打开文件指针,将容易出现问题,但是在多进程程序中,

5、往往需要传递文件描述符,所以此类混合文件操作必须掌握。1.2. 读写文件基于文件指针的数据读写函数较多,可分为如下几组:数据块读写:#include <stdio.h>size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);fread从文件流stream 中读取nmemb个元素,写到ptr指向的内存中,每个元素的大小为size个字节fwrite从ptr指向的内存中读取nmemb个

6、元素,写到文件中,每个元素size个字节。所有的文件读写函数都从文件的当前读写点开始读写,读写完以后,当前读写点自动往后移动size*nmemb个字节。格式化读写:#include <stdio.h>int printf(const char *format, .); int fprintf(FILE *stream, const char *format, .); int sprintf(char *str, const char *format, .); int snprintf(char *str, size_t size, const char *format, .); #

7、include <stdarg.h> int vprintf(const char *format, va_list ap); int vfprintf(FILE *stream, const char *format, va_list ap);int vsprintf(char *str, const char *format, va_list ap);int vsnprintf(char *str, size_t size, const char *format, va_list ap);其中printf相当于fprintf(stdout,format,.);以f和vf开头的将

8、格式化后的字符串写入到文件流stream中,以s和vs开头的将格式化后的字符串写入到字符串str中.以v开头的函数往往用在可变参数个数的函数内部调用,例如: int MyPrintf(const char *format,.)va_list lstArg;FILE *pStream=fopen(“a.txt”,”ab”);va_start(lstArg,pszFormat);vfprintf(pStream,pszFormat,lstArg);va_end(lstArg);fclose(pStream);字符读写:使用下列函数可以一次读写一个字符#include <stdio.h>

9、int fgetc(FILE *stream);int fputc(int c, FILE *stream);int getc(FILE *stream); int putc(int c, FILE *stream);int getchar(void); int putchar(int c);getchar和putchar从标准输入输出流中读写数据,其他函数从文件流stream中读写数据。注意此组每次只会读写一个字节的数据,但是类型是以整型表示的。行读写: char *fgets(char *s, int size, FILE *stream); int fputs(const char *s

10、, FILE *stream); int puts(const char *s); char *gets(char *s);fgets和fputs从文件流stream中读写一行数据;puts和gets从标准输入输出流中读写一行数据。fgets可以指定目标缓冲区的大小,所以相对于gets安全,但是fgets调用时,如果文件中当前行的字符个数大于size,则下一次fgets调用时,将继续读取该行剩下的字符,fgets读取一行字符时,保留行尾的换行符。fputs不会在行尾自动添加换行符,但是puts会在标准输出流中自动添加一换行符。文件定位:文件定位指读取或设置文件当前读写点,所有的通过文件指针读写

11、数据的函数,都是从文件的当前读写点读写数据的。常用的函数有:#include <stdio.h>int fseek(FILE *stream, long offset, int whence);long ftell(FILE *stream);void rewind(FILE *stream);fseek设置当前读写点到offset处,whence可以是SEEK_SET,SEEK_CUR,SEEK_END,这些值决定是从文件头、当前点和文件尾计算偏移量offset.ftell获取当前的读写点rewind将文件当前读写点移动到文件头01.3. 目录操作获取、改变当前目录:原型为:#i

12、nclude <unistd.h>char *getcwd(char *buf, size_t size);/获取当前目录int chdir(const char *path);/修改当前目录int fchdir(int fd);/用文件描述符的方式修改当前目录创建和删除目录:原型为:#include <sys/stat.h>#include <sys/types.h>#include <unistd.h>int mkdir(const char *pathname, mode_t mode);/创建目录,mode是目录权限int rmdir(c

13、onst char *pathname);/删除目录获取目录信息:原型为:#include <sys/types.h>#include <dirent.h>DIR *opendir(const char *name);/打开一个目录 struct dirent *readdir(DIR *dir);/读取目录的一项信息,并返回该项信息的结构体指针void rewinddir(DIR *dir);/重新定位到目录文件的头部int closedir(DIR *dir);/关闭目录文件读取目录信息的步骤为:1、 用opendir函数打开目录;2、 使用readdir函数迭代读

14、取目录的内容,如果已经读取到目录末尾,又想重新开始读,则可以使用rewinddiw函数将文件指针重新定位到目录文件的起始位置;3、 用closedir函数关闭目录示例:#include <stdio.h>#include <sys/types.h>#include <dirent.h>int main(int argc,char *argv) dirent *pDirInfo; DIR *pDir; / if(argc<2) pDir=opendir("."); else pDir=opendir(argv1); if(pDir=N

15、ULL) perror("open dir fail!"); return -1; while(pDirInfo=readdir(pDir) printf("%sn",pDirInfo->d_name); closedir(pDir); return 0;1.4. 标准输入/输出流在进程一开始运行,就自动打开了三个对应设备的文件,它们是标准输入、输出、错误流,分别用全局文件指针stdin、stdout、stderr表示,stdin具有可读属性,缺省情况下是指从键盘的读取输入,stdout和stderr具有可写属性,缺省情况下是指向屏幕输入数据。示例

16、:#include <stdio.h>#include <unistd.h>int main() char szBuf32; printf("Input string:");/向屏幕输出一字符串 fgets(szBuf,sizeof(szBuf),stdin);/从键盘读入一行字符串 fprintf(stdout,"The string is:%s",szBuf);/向屏幕输出一行字符串 return 0;2. 基于文件描述符的文件操作(非缓冲)2.1. 文件描述符内核为每个进程维护一个已打开文件的记录表,文件描述符是一个较小的正

17、整数,它代表记录表的一项,通过文件描述符和一组基于文件描述符的文件操作函数,就可以实现对文件的读、写、创建、删除等操作。常用的基于文件描述符的函数有open、creat、close、read、write、ftruncate、lseek、fsync、fstat、fchown、flock、fcntl、dup、dup2、select和ioctl。基于文件描述符的文件操作并非ANSI C的函数。2.2. 打开、创建和关闭文件open和creat都能打开和创建函数,原型为#include <sys/types.h>#include <sys/stat.h>#include <

18、;fcntl.h>int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);int creat(const char *pathname, mode_t mode);flags和mode都是一组掩码的合成值,flags表示打开或创建的方式,mode表示文件的访问权限。flags的可选项有掩码含义O_RDONLY以只读的方式打开O_WRONLY以只写的方式打开O_RDWR以读写的方式打开O_CREAT如果文件不存在,则创建文件O_EXCL仅与O_CREAT

19、连用,如果文件已存在,则强制open失败O_TRUNC如果文件存在,将文件的长度截至0O_APPEND已追加的方式打开文件,每次调用write时,文件指针自动先移到文件尾,用于多进程写同一个文件的情况。O_NONBLOCK非阻塞方式打开O_NODELAY非阻塞方式打开O_SYNC只有在数据被真正写入物理设备设备后才返回int creat(const char *pathname,mode_t mode);等价于open(pathname,O_CREAT|O_TRUNC|O_WRONLY,mode);文件使用完毕后,应该调用close关闭它,一旦调用close,则该进程对文件所加的锁全都被释放,

20、并且使文件的打开引用计数减1,只有文件的打开引用计数变为0以后,文件才会被真正的关闭,文件引用计数主要用于多进程之间文件描述符的传递。2.3. 读写文件读写文件的函数原型为:#include <unistd.h>ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count);2.4. 文件定位函数lseek将文件指针设定到相对于whence,偏移值为offset的位置#include <sys/types.h>#include <u

21、nistd.h>off_t lseek(int fildes, off_t offset, int whence);whence 可以是下面三个常量的一个SEEK_SET 从文件头开始计算SEEK_CUR 从当前指针开始计算SEEK_END从文件尾开始计算2.5. 获取文件信息可以通过fstat和stat函数获取文件信息,调用完毕后,文件信息被填充到结构体struct stat buf中,原型为:#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>int stat(const ch

22、ar *file_name, struct stat *buf);int fstat(int filedes, struct stat *buf);结构体stat的定义为: struct stat dev_t st_dev; /*如果是设备,返回设备表述符,否则为0*/ ino_t st_ino; /* i节点号 */ mode_t st_mode; /* 文件类型 */ nlink_t st_nlink; /* 链接数 */ uid_t st_uid; /* 属主ID */ gid_t st_gid; /* 组ID */ dev_t st_rdev; /* 设备类型*/ off_t st_s

23、ize; /* 文件大小,字节表示 */ blksize_t st_blksize; /* 块大小*/ blkcnt_t st_blocks; /* 块数 */ time_t st_atime; /* 最后访问实际*/ time_t st_mtime; /* 最后修改实际*/ time_t st_ctime; /* 创建时间 */ ;对于结构体的成员st_mod,有一组宏可以进行文件类型的判断宏描述S_ISLNK(mode)判断是否是符号链接S_ISREG(mode)判断是否是普通文件S_ISDIR(mode)判断是否是目录S_ISCHR(mode)判断是否是字符型设备S_ISBLK(mode

24、)判断是否是块设备S_ISFIFO(mode)判断是否是命名管道S_ISSOCK(mode)判断是否是套接字2.6. 文件的锁定在多进程对同一个文件进行读写访问时,为了保证数据的完整性,有时需要对文件进行锁定。可以通过fcntl对文件进行锁定和解锁。#include <unistd.h>#include <fcntl.h>int fcntl(int fd, int cmd, struct flock *lock);参数cmd置为F_GETLK或F_SETLK可以获取或设置文件锁定信息。参数struct flock为文件锁信息。文件锁有两种类型,读取锁(共享锁)和写入锁(

25、互斥锁)。对于已经加读取锁的文件,再加写入锁将会失败,但是允许其它进程继续加读取锁;对于已经加写入锁的文件,再加读取锁和写入锁都将会失败。注意:文件锁只会对其它试图加锁的进程有效,对直接访问文件的进程无效。示例:#include <string.h>#include <stdlib.h>#include <stdio.h>#include <fcntl.h>#include <errno.h>#include <unistd.h>#include <sys/types.h>#include <sys/st

26、at.h>bool LockFile(int fd,int iType)struct flock lock;lock.l_whence=SEEK_SET;/从文件头开始lock.l_pid=getpid();/当前进程IDlock.l_start=0;/开始锁定点,lock.l_len=0;/结束锁定点,0表示整个文件锁定lock.l_type=iType;/锁定类型if(fcntl(fd,F_SETLK,&lock)=0)return true;perror("lock fail");return false;int main(int argc,char *

27、argv)int fd=open("./a.txt",O_CREAT|O_RDWR);int iLock=0;if(fd<0)printf("errno:%dn",errno);perror("open fail");return -1;fchmod(fd,0666);if(argc>1)if(strstr(argv1,"write")if(!LockFile(fd,F_WRLCK)return -3;else if(strstr(argv1,"read")if(!LockFile(

28、fd,F_RDLCK)return -3;lseek(fd,0,SEEK_END);if(write(fd,"abc",3)<0)perror("write fail");return -2;sleep(10);close(fd);return 0;2.7. 文件描述符的复制函数dup和dup2可以实现文件描述符的复制。原型为:#include <unistd.h>int dup(int oldfd);int dup2(int oldfd, int newfd);文件描述符的复制是指用另外一个文件描述符指向同一个打开的文件,它完全不同于

29、直接给文件描述符变量赋值,例如:描述符变量的直接赋值:char szBuf32;int fd=open(“./a.txt”,O_RDONLY);int fd2=fd;close(fd);/导致文件立即关闭printf(“read:%dn”,read(fd2),szBuf,sizeof(szBuf)-1);/读取失败close(fd2);/无意义了在此情况下,两个文件描述符变量的值相同,指向同一个打开的文件,但是内核的文件打开引用计数还是为1,所以close(fd)或者close(fd2)都会导致文件立即关闭掉。描述符的复制:char szBuf32;int fd=open(“./a.txt”,

30、O_RDONLY);int fd2=dup(fd);close(fd);/当前还不会导致文件被关闭,此时通过fd2照样可以访问文件printf(“read:%dn”,read(fd2),szBuf,sizeof(szBuf)-1);close(fd2);/内核的引用计数变为0,文件正式关闭dup2(int fdold,int fdnew)也是进行描述符的复制,只不过采用此种复制,新的描述符由用户用参数fdnew显示指定,而不是象dup一样由内核帮你选定。对于dup2,如果fdnew已经指向一个已经打开的文件,内核会首先关闭掉fdnew所指向的原来的文件。如果成功dup2的返回值于fdnew相同,否则为-1思考下面程序的结果:#include <stdlib

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论