该文章转载http://blog.csdn.net/yx_l128125/article/details/7618435,其中加入部分自己验证和理解内容。
库函数
在输入输出操作中,直接使用底层系统调用的问题使它们的效率非常低。为什么呢?
& 系统调用会影响系统的性能。与函数调用相比,系统调用的开销要大些,因为在执行系统调用时,Linux必须从用户代码切换到内核代码运行,然后再返回用户代码。减少这种开销的一个好方法是,在程序中尽量减少系统调用的次数,并且让每次系统调用完成尽可能多的工作。
例如:每次读写大量的数据而不是每次仅读写一个字符。
& 硬件会对底层系统调用一次所能读写的数据块做出一定的限制。例如:磁带机通常的写操作数据块的长度为10k,所以如果卸的数据量不是10k的整数倍,磁带机还是会以10k为单位卷绕磁带,这就在磁带上留下了空隙。
为了给设备和磁盘文件提供更高层的接口,与Unix一样,Linux发行版提供了一系列的标准函数库。它们是一些由函数构成的集合,你可以把它们包括在自己的程序中去处理呢些与设备和文件有关的问题。提供输出缓冲功能的标准IO库就是一个这样的例子。你可以高效地写任意长度的数据块,库函数则在数据满足数据块长度要求时安排执行底层系统调用。这就极大的降低了系统调用的负面影响。
库函数会有一个与之相对应的标准头文件,例如:与标准IO库对应的头文件stdio.h
图:显示了Linux系统中各种文件函数与用户、设备驱动程序、内核和硬件之间的关系。
5.底层文件访问
每个运行中的程序被称为进程(process),它有一些与之相关联的文件描述符。这是一些小值整数,你可以通过它们访问打开的文件或设备。有多少文件描述符可用取决于系统的配置情况。当开始运行程序时,它一般会有三个已经打开的文件描述符。它们是:
0:标准输入
1:标准输出
2:标准出错
二. Linux中文件编程可以使用两种方法:
(1) Linux 系统调用
(2) C语言库函数
前者依赖于Linux系统,后者与操作系统是独立的,在任何操作系统下,使用C语言库函数操作文件的方式都是相同的。
系统调用open () ,read(),write(),lseek();
库函数fopen(), fread(),fwrite(),flseek();
库函数
1.fopen()函数
函数功能 | 打开文件 |
头文件 | #include<stdio.h> |
函数原型 | FILE *fopen(const char *path ,const char *mode) |
参数说明 | §path:欲打开的文件路径与文件名 §mode:打开方式: “r”:以只读方式打开文件 “r+”:以可写可读方式打开文件 “w”:以只写方式打开文件 “w+”:以可读可写的方式打开文件,若文件不存在则建立文件 “a”:以追加的方式打开文件,若文件不存在则建立文件; 若文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。 “a+”:相对“a”功能的基础上,以追加方式打开可读可写的文件。 |
返回值 | 文件打开成功,返回文件指针; 文件打开失败,则返回NULL,并把错误码存在errno中 |
范例: #include<stdio.h> Main() { FILE *fp; fp=fopen(“hell.txt”,”a+”); if(fp==NULL) return: fclose(fp); } |
1. open()函数
所需头文件 | #include <sys/types.h> #include <sys/stat.h > #include <fcntl.h>
| |
函数原型 | (1)Int open(const char *pathname, int flags); (2)Int open(const char *pathname, int flags, mode_t mode ); | |
区别当flag使用了O_CREAT标志,则使用第二种形式,这时需要mode来指定访问权限
| ||
函数传入值 | Pathname | §Pathname:要打开的文件路径和文件名
|
§flags:打开方式,必须从下面三个中选一个: | O_RDONLY:只读模式; | |
O_WRONLT:只写模式 | ||
O_RDWR:读写模式; | ||
§flags:另外,还可以附加选项,通过与上面3个选项通过”|”连接 | O_APPEND:每次写操作都写入文件的末尾; | |
O_CEAT:如果指定文件不存在,则创建这个文件; | ||
O_EXCL:如果要创建的文件已存在,则返回-1,并且修改errno的值,需要与O_CREAT配对使用以确保文件是新建的。 | ||
O_TRUNC:如果文件存在,并且以只写/读写方式打开,则清空文件全部内容(即长度截短为0)。 | ||
O_NOCTTY:如果路径名指向终端设备,不要把这个设备用作控制中端; | ||
函数返回值:成功返回文件描述符; 失败返回:-1; |
范例:
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
main()
{
int fd,size;
char s [ ]=”Linux Programmer!\n”,buffer[80];
fd=open(“/tmp/temp”,O_WRONLY|O_CREAT);
write(fd,s,sizeof(s));
close(fd);
fd=open(“/tmp/temp”,O_RDONLY);
size=read(fd,buffer,sizeof(buffer));
close(fd);
printf(“%s”,buffer);
}
2.fseek()函数
函数功能 | 移动文件流的读写位置 |
头文件 | #include<stdio.h> |
函数原型 | Int fseek(FIEL * stream , long offset , int origin) |
参数说明 | §stream:文件指针 §offset:偏移量,正数表示正向偏移,负数表示负向偏移 §origin:设定从文件的哪里开始偏移,可能取值为: SEEK_SET:文件开头 SEEK_CUR:当前位置 SEEK_END:文件结尾 |
返回值 | 成功,返回0; 失败,返回-1; |
范例: #include<stdio.h> Long filesize(FILE *stream) { FILE *stream; Stream=fopen(“MYFILE.txt”,“w+”); fprintf (stream ,“this is a test”); printf(“filesize of MYFILE.txt is %ld bytes\n” ,filesize(stream) ); return 0; } Long filesize(FILE *stream) { Long curpos ,length; Curpos=ftell(stream); Fseek(stream, 0L ,SEEK_END); Length=ftell(stream); //*ftell(fd)求文件总长度 fseek=(stream ,curpos ,SEEK_SET); return length; } |
2. lseek()函数
函数功能 | 移动文件读写指针 |
头文件 | #include <sys/types.h> #include <unistd.h> |
函数原型 | Off_t lseek(int fd, off_t offset, int whence) |
参数说明 | §Fd:文件描述符 §offset:偏移量,正数表示正向偏移量,负数表示负向偏移量 §whence:设定从文件的哪里开始偏移,可取值为: SEEK_SET:文件开头 SEEK_CUT:当前位置 SEEK_END:文件结尾 (其中SEEK_SET、SEEK_CUT、SEEK_END:0,1和2) |
返回值 | 当调用成功则返回目前的读写位置相对头文件的偏移量,(即距文件开头多少字节,若有错误则返回-1,errno会存放错误代码) |
范例 | 1. 欲将读写位置移到文件开头时: lseek(int fd, 0, SEEK_SET) 2. 欲将读写位置移到文件结尾时: lseek(int fd, 0, SEEK_CUT) 3. 欲将读写位置移到当前位置时: lseek(int fd, 0, SEEK_END) |
3.fread()函数
函数功能 | 从一个流中读数据 |
头文件 | #include<stdio.h> |
函数功能 | Int fread(void *ptr ,int size ,int nitems, FILE *stream) |
函数说明 | §ptr:用于接收数据的地址(指针) §size:每个字段中所含字节数 §nitems:要读取的总字段数; §stream:提供数据的文件指针 |
返回值 | 成功返回读取的元素个数 |
范例:
|
3.read()函数
函数功能 | 由打开的文件读写数据 |
头文件 | #include <unistd.h> |
函数原型 | Ssize_t read(int fd, void *buf , size_t count) |
参数说明 | §fd:文件描述符 §buf:存放读取数据的缓冲区 §count:读取的最大长度(字节数) |
返回值 | 成功返回实际读取的字节数,失败返回-1 |
4.write()函数
函数功能 | 向文件写入一个数据块 |
函数原型 | Ssize_t write(int fd ,const void *buf ,size_t count) |
参数说明 | §fd:文件描述符 §buf:写入数据的缓冲区 §count:写入数据的最大长度(总字节数) |
返回值 | 成功返回实际写入字节数,当有错误发生时则返回-1,错误代码存入errno |
4.fwrite()函数
函数功能 | 向文件写入一个数据块 |
头文件 | #include<stdio.h> |
函数功能 | Int fwrite(const void* buffer ,size_t size , size_t count, FILE *stream) |
函数说明 | §buffer:用于输入的数据的地址(指针) §size:每个字段中所含字节数 §nitems:要读取的总字段数; §stream:提供数据的文件指针 |
返回值 | 成功返回写入的元素个数 |
其注意点和其他的一些对比 1.文件描述符的对比:区别: 系统调用:中开打文件返回的是一个整型数;文件描述符是整数 库函数:中是用FILE 类型的指针来代表文件,文件描述符是FILE类型的指针 2.b用于区分二进制文件和文本文件,这一点在DOS、Windows系统中式有区分的,但linux不区分二进制文件和文本文件。
|
****库函数方式访问文件***
库函数---格式化读
fscanf (FILE *stream ,char * format[,argument…])
从一个流中进行格式化输入
(//format是格式,流就是文件;从文件中进行格式化的输入,实际上就是一个读取)
- <SPAN style="FONT-SIZE: 12px">#include <stdib.h>
- #include <stdio.h>
- int main(void)
- { int i;
- printf(“input an integer ”);
- if(fscanf(stdin, “%d”,&i)) // 从标准输入(键盘) 以%d(整数)的形式写入到 &i的地址空间中
- {
- printf(“the integer read was : %i \n” ,i);
- return 0;
- }
- }
#include <stdib.h>
#include <stdio.h>
int main(void)
{ int i;
printf(“input an integer ”);
if(fscanf(stdin, “%d”,&i)) // 从标准输入(键盘) 以%d(整数)的形式写入到 &i的地址空间中
{
printf(“the integer read was : %i \n” ,i);
return 0;
}
}
库函数---格式化写
Int fprintf(FILE *stream ,char *format[,argument,…])
格式化输出到一个流中
- #include <stdio.h>
- #include <process.h>
- FILE *stream;
- Void main()
- {
- int i=10;
- double fp=1.5;
- char s[]=”this is a string”;
- char c=’\n’;
- stream =fopen(“fprintf.out ”, “w”);
- fprintf(stream ,”s%c%”, s, c); //把s数组中的字符串写入到stream—即fprintf.out 文件中
- fprintf(stream,“%d\n”, i); //把i整数写入stream—即fprintf.out文件中
- fprintf (stream, “%f\n”, fp); //把fp值以浮点数的格式写入fprintf.out文件中
- fclose (stream);
- }
#include <stdio.h>
#include <process.h>
FILE *stream;
Void main()
{
int i=10;
double fp=1.5;
char s[]=”this is a string”;
char c=’\n’;
stream =fopen(“fprintf.out ”, “w”);
fprintf(stream ,”s%c%”, s, c); //把s数组中的字符串写入到stream—即fprintf.out 文件中
fprintf(stream,“%d\n”, i); //把i整数写入stream—即fprintf.out文件中
fprintf (stream, “%f\n”, fp); //把fp值以浮点数的格式写入fprintf.out文件中
fclose (stream);
}
库函数—定位
int fseek (FILE *stream, long offset , int whence)
whence :(基准点)
SEEK_SET 从文件的开始处开始搜索
SEEK_CUR 从当前位置开始搜索
SEEK_END 从文件的结束处开始搜索
路径获取:
在编写程序的时候,有时需要得到当前路径。C库函数提供了getcwd来解决这个问题。
Char *getcwd(char *buffer ,size_t size)
我们提供一个size 大小buffer , getcwd 会把当前的路径名copy到buffer中。如果buffer太小,函数会返回 -1
- #include <unistd.h>
- main()
- {
- char buf [80];
- getcwd(buf,sizeof(buf));
- printf(“current working directory:%s\n”,buf);
- }
创建目录:
#include <sys/stat>
int mkdir(char *dir ,int mode)
功能:创建一个新目录
返回值:0表示:成功; -1表示:失败;
***系统调用方式访问文件***@系统调用---文件访问
系统调用---创建
int creat (const char *filename ,mode_t mode)
(1)filename :要创建的文件名(包含路径,缺省为当前路径)
(2)mode :创建模式
常见创建模式:
S_IRUSR 可读
S_IWUSR 可写
S_IXUSR 可执行
S_IRWXU 可读、可写、可执行
除了可以使用上述宏以外,还可以直接使用数字来表示文件的访问权限:
(1) 可执行à1
(2) 可写à2
(3) 可读à 4
上述值的和,如可写、可读à6 ; 无任何权限à0 ; 可读、可执行à5
第二次观看,附加:
权限0755 是什么意思?
0 :只是一个占位符;
7 :“文件的所有者”拥有可读、可写、可执行
5 :“文件所有者所在的组”,拥有可读、可执行
5 :“其他用户”拥有可读、可执行
Gcc hello .c –o hello
如果没有用 –o 去指定输出应用程序的名字,则输出的应用程序默认为 a .out
文件描述符:
在Linux系统中,所有打开的文件都对应一个文件描述符。文件描述符的本质是一个非负整数。当打开一个文件时,该整数由系统来分配。问件描述符的范围是0~OPEN_MAX。(早期的UNIX版本OPEN_MAX=19),即允许每个进程同时打开20个文件,现在很多系统则将其增加到1024.
- 代码:
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- void create_file(char *filename){
- /*创建的文件具有什么样的属性?*/
- if(creat(filename,0755)<0){
- printf("create file %s failure!\n",filename);
- exit(EXIT_FAILURE);
- }else{
- printf("create file %s success!\n",filename);
- }
- }
- int main(int argc,char *argv[])
- {
- int i;
- if(argc<2){
- perror("you haven't input the filename,please try again!\n");
- //perror();函数打印出错原因信息字符串
- exit(EXIT_FAILURE);
- }
- for(i=1;i<argc;i++){
- create_file(argv[i]);
- }
- exit(EXIT_SUCCESS);
- }
系统调用---定位
int lseek(int fd ,offset_t offset , int whence)
功能:将文件读写指针对whence移动offset个字节。操作成功时,返回文件指针相对于头文件的位置。
(1) whence :表示从什么地方开始移动指针(基准点)
(2) 先前移动3个字节offset= -3;
Whence可使用下述值:
SEEK_SET:相对文件开头
SEEK_CUR :相对文件读写指针的当前位置
SEEK_END:相对文件末尾
Offset可取负值,表示向前移动。例如下述调用可将文件指针相对当前位置向前移动5个字节:
Lseek (fd ,-5 ,SEEK_CUR)
如何利用lseek来计算文件长度?
由于lseek函数的返回值为文件指针相对于文件头位置,因此下面调用的返回值就是文件的长度:
lseek(fd ,0 ,SEEK_END)
(因为操作成功时,返回文件指针相对于头文件的位置)
系统调用----访问判断
有时我们需要判断文件是否可以进行某种操作(读,写等),这时可以使用access函数:
int access(const char *pathname ,int mode)
pathname:文件名称
mode: 要判断的访问权限。可以取以下值或者是他们的组合。
R_OK :文件可读 W_OK :文件可写 X_OK :文件可执行;F_OK文件存在
返回值:当我们测试成功时,函数返回0,否则如果一个条件不符合,返回 -1;
- 例程:(判断文件是否可读)
- #include <unistd.h>
- int main ()
- {
- If (access(“/etc/passwd”, R_OK)==0)
- printf(“/etc/passwd can be read!\n”);