嵌入式Linux学习笔记第三天(文件编程)

时间:2021-11-01 18:57:33

                             

                                                  嵌入式Linux学习笔记第三天

          ——文件编程

                 嵌入式Linux文件编程有两种方式:系统调用和库函数。常用的文件操作函数有,open、read、write、lseek。通常来说,当一个进程运行时,都会自动打开三个文件:标准输入(键盘)、标准输出(屏幕)、标准出错处理(屏幕)。这三个文件对应的文件描述符分别为0、1、2.(对应的宏为STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO)。

一:系统调用:

        所谓的系统调用其实就是操作系统提供给用户程序调用的一组“特殊的接口”,用户程序可以通过这个特殊的接口获得操作系统内核提供的服务。那么,为啥操作系统不直接让用户直接访问内核,还搞出个“特殊的接口”,Linux操作在安全方面考虑的比较周到,为了更好的保护内核空间,将程序运行空间分为用户空间(0-3G)和内核空间(3G-4G),它们分别运行在不同的等级上,在逻辑上是相互分离的。通常情况系,用户进程在通常情况下不允许访问内核数据,也就不能访问内核函数,它们只能操作用户数据,调用用户函数。下面介绍几个常用的函数。Creat() , open(), close(),read(), write(), lseek().

        1:创建文件:int creat(const char *filename, mode_t mode)

        所需头文件:#include<sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

 

                 Filename为创建文件的文件名(包含路径,缺省是默认为当前路径),

                 Mode为创建的文件属性,S_IRUSR 可读

                                                                            S_IWUSR  可写

                                                                            S_IXUSR  可执行

                                                                            S_IRWXU  可读可写可执行

       或者是用数字表示,0无任何权限,1可执行,2可写,4可读,6可读可写;

要创建一个用户可读、可写、可执行,但是组没有权限,其他人可以读、可以执行的文件,并设置用户ID位。那么,我们应该使用的模式是1(设置用户ID)、0(不设置组ID)、7(1+2+4,读、写、执行)、0(没有权限)、5(1+4,读、执行)即10705:

参考程序:

#include <stdio.h>

                   #include <stblib.h>

#include <sys/types.h>

                   #include <sys/stat.h>

                  #include <fcntl.h>

                        

              viod creat_file(char *filename) {

                             /*创建的文件具有什么样的属性?*/

                                  if(creat(filename,0755)<0){

printf(“creat file %sfailure!\n”,filename);

exit(EXIT_FAILURE);

} else {

printf(“creat file %ssuccess!\n”,filename);

                                          }

                                 

                          

 

int main(int argc,char *argv[]) {

int i;

if(argc<2){

perror("you haven'tinput the filename,please try again!\n");

exit(EXIT_FAILURE);

                              }

                                          for(i=1;i<argc;i++){

create_file(argv[i]);

}

exit(EXIT_SUCCESS);

}

        2:打开文件:int open(const char*pathname, flags, mode _t mode)

        所需头文件:#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

 

pathname:被打开文件名(可包括路径名,缺省时为当前目录)
flags:文件打开的方式,参数可以通过“|”组合构成,但前3个参数不能互相重合。
    O_REONLY:只读方式打开文件
    O_WRONLY:可写方式打开文件
   O_RDWR:读写方式打开文件
    O_CREAT:如果文件不存在时就创建一个新文件,并用第三个参数为其设置权限。
    O_EXCL:如果使用O_CREAT时文件存在,则可返回错误信息。这一参数可测试文件是否存在。
    O_NOCTTY:使用本参数时,如文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端。
    O_TRUNC:如文件已经存在,并且以只读或只写成功打开,那么会先全部删除文件中原因数据。
    O+APPEND:以添加方式打开文件,在打开文件的同时,文件指针指向文件末尾。
    mode _t mode:被打开文件的存取权限,为8进制表示法(调用O_CREAT才需要)。
函数返回值:成功:返回文件描述符

失败:-1

       

 

3:关闭文件:int close(int fd)

所需头文件:#include<unistd.h>

                 fd 为文件描述符,

                 函数返回值:    成功:0      

出错:-1

         例程:#include<stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

       

int main(int argc ,char *argv[]){

                               int fd;

                    if(argc<2){

                puts("please inputthe open file pathname!\n");

                            exit(1);

                               }

   

//如果flag参数里有O_CREAT表示,该文件如果不存在,系统则会创建该文件,该文件的权限由第三个参数决定,此处为0755

//如果flah参数里没有O_CREAT参数,则第三个参数不起作用.此时,如果要打开的文件不存在,则会报错.

                 //所以fd=open(argv[1],O_RDWR),仅仅只是打开指定文件

                        if((fd=open(argv[1],O_CREAT|O_RDWR,0755))<0){

                             perror("open file failure!\n");

                             exit(1);

                         }else{

                           printf("open file %d  success!\n",fd);

                

                      }

                       close(fd);

                     exit(0);

}

 

4:读取文件 int read(int fd, void *buf,size_t length)

所需头文件:#include<unistd.h>
函数传入值
fd:文件描述符
buf:指定存储器读出数据的缓冲区
size_t length:指定读出的字节数
函数返回值:成功:读出的字节数0:已到达文件尾 -1:出错
在读普通文件时,若读到要求的字节数之前已达到文件的尾部,则返回字节数会小于希望读出的字节数。

 

5:写入文件:int write(int fd,void*buf,size_t length)
所需头文件:#include<unistd.h>
函数传入值:
fd:文件描述符
Buf:指定存储器写入数据的缓冲区

length:指定读出的字节数
函数返回值:成功:已写的字节数-1:出错

 

6:、偏移函数:int lseek(int fd,off_t offset,int whence)
所需头文件:#include<unistd.h>
           #include<sys/types.h>
函数传入值:
fd:文件描述符
Offset:偏移量,每一读写操作所需要移动的距离,单位是字节的数量,可正可负(向前移,向后移)
Whence:当前位置的基点:
    SEEK_SET:当前位置为文件开头,新位置为偏移量的大小
   SEEK_CUR:当前位置为文件指针位置,新位置为当前位置加上偏移量
    SEEK_END:当前位置为文件的结尾,新位置为文件的大小加上偏移量大小

         返回值:      成功:文件相对开头的当前位移

                                          出错:-1

 

二:库函数编程

                   C库函数的文件操作实际上是独立于具体的操作系统平台的,不管是在DOS、

Windows、Linux还是在VxWorks中都是这些函数:

 

     1:创建和打开: FILE *fopen(const char *filename,const char *mode)

             所需头文件:#include<stdio.h>

             函数传入值:

             Filename:打开的文件名(包含路径,缺省时为当前路径)。

             Mode:打开模式,C语言中支持的打开模式如下表

             其中b用于区分二进制文件和文本文件,这一点在DOS、Windows系统中是有区分的,但Linux不区分二进制文件和文本文件。

             返回值:        成功:指向file的指针

                                      失败:NULL

 

2:关闭文件:int fclose(FILE *stream)

            

    需头文件

#include<stdio.h>

Stream:已打开的文件指针。

函数说明

fclose()用来关闭先前fopen()打开的文件。此动作会让缓冲区内的数据写入文件中,并释放系统所提供的文件资源。

返回值

   成功:返回0,

错误:返回EOF并把错误代码存到errno。

             例程:    #include<stdio.h>

                              int main()

                              {

                                      FILE *fp;

                                      fp = fopen(“HELLO.c”,”a++”);

                                      if(fp == NULL)  return 0;

                                      fclose(fp);

                              }

 

        3:读取文件:size_t fread(void *ptr,size_t size,size_tn, FILE *stream)

                 所需头文件:#include <stdio.h>

                 函数传入值:

                                  Ptr:存放读入数据的缓存区

                                  Size_t size :每段读取的记录大小

                                  Size_t n:读取的段数,

                                  Stream:要读取的文件流(对应文件指针)

                         返回值:        成功:返回实际读取到的n数目

                                                  失败:EOF

                         例程:

                                  #include<stdio.h>

#define nmemb 3

struct test

{

char name[20];

int size;

}s[nmemb];

main()

{

FILE * stream;

int i;

stream = fopen(“/tmp/fwrite”,”r”);

fread(s,sizeof(struct test),nmemb,stream);

fclose(stream);

for(i=0;i<nmemb;i++)

printf(“name[%d]=%-20s:size[%d]=%d\n”,i,s[i].name,i,s[i].size);

}

执行结果

name[0]=Linux! size[0]=6

name[1]=FreeBSD! size[1]=8

name[2]=Windows2000 size[2]=11

 

                 4:写入文件:size_t fwrite(const void *ptr,size_t size,size_t n, FILE * stream)       

                         所需头文件:#include <stdio.h>

                         函数传入值:

                                  Ptr:存放读入数据的缓存区

                                  Size_t size :每段读取的记录大小

                                  Size_t n:读取的段数,

                                  Stream:要写入的文件流(对应文件指针)

                         返回值:        成功:返回实际读取到的n数目

                                                  失败:EOF

                         例程:

#include<stdio.h>

#define set_s (x,y){strcoy(s[x].name,y);s[x].size=strlen(y);}

#define nmemb 3

struct test

{

char name[20];

int size;

}s[nmemb];

main()

{

FILE * stream;

set_s(0,”Linux!”);

set_s(1,”FreeBSD!”);

set_s(2,”Windows2000.”);

stream=fopen(“/tmp/fwrite”,”w”);

fwrite(s,sizeof(structtest),nmemb,stream);

fclose(stream);

}

 

                 5:由文件中读取一个字符:int getc(FILE * stream);

                         所需头文件:#include <stdio.h>

                         函数传入值:

                                  Stream:要读取的文件流(对应文件指针)                     

函数说明:fgetc()从参数stream所指的文件中读取一个字符。若读到文件尾而无数据时便返回EOF。

                         返回值:        成功:读取到的字符

                                                  失败:EOF(已到文件尾)

                         例程:    #include<stdio.h>

main()

{

FILE *fp;

int c;

fp=fopen(“exist”,”r”);

while((c=fgetc(fp))!=EOF)

printf(“%c”,c);

fclose(fp);

}

                 6:由文件中写入一个字符:int fputc(int c,FILE * stream)

                         所需头文件:#include <stdio.h>

                         函数传入值:

                                  Stream:要写入的文件流(对应文件指针)

                         返回值:        成功:写入的字符

                                                  失败:EOF

                         例程:#include<stdio.h>

main()

{

FILE * fp;

chara[26]=”abcdefghijklmnopqrstuvwxyz”;

int i;

fp= fopen(“noexist”,”w”);

for(i=0;i<26;i++)

fputc(a[i],fp);

fclose(fp);

}

 

                 7:移动文件流的读写位置:int fseek(FILE * stream,long offset,intwhence);

                         所需头文件:#include <stdio.h>

                         函数传入值:

                                  Stream:要移动的文件流(对应文件指针)

                                 Offset:移动的相对量

                                 Whence为移动的参考量。为下列其中一种:

SEEK_SET从距文件开头offset位移量为新的读写位置。SEEK_CUR 以目前的读写位置往后增加offset个位移量。

SEEK_END将读写位置指向文件尾后再增加offset个位移量。

当whence值为SEEK_CUR 或SEEK_END时,参数offset允许负值的出现。

下列是较特别的使用方式:

1) 欲将读写位置移动到文件开头时:fseek(FILE*stream,0,SEEK_SET);

2) 欲将读写位置移动到文件尾时:fseek(FILE *stream,0,0SEEK_END);

                         函数说明:

fseek()用来移动文件流的读写位置。参数stream为已打开的文件指针,参数offset为根据参数whence来移动读写位置的位移数。

返回值:        成功:0

                                                   失败:-1

附加说明:fseek()不像lseek()会返回读写位置,因此必须使用ftell()来取得目前读写的位置。

例程:

#include<stdio.h>

main()

{

FILE * stream;

long offset;

fpos_t pos;

stream=fopen(“/etc/passwd”,”r”);

fseek(stream,5,SEEK_SET);

printf(“offset=%d\n”,ftell(stream));

rewind(stream);

fgetpos(stream,&pos);

printf(“offset=%d\n”,pos);

pos=10;

fsetpos(stream,&pos);

printf(“offset =%d\n”,ftell(stream));

fclose(stream);

}

 

执行结果

offset = 5

offset =0

offset=10

 

                 8:格式化输出数据至文件:int fprintf(FILE * stream, const char *format,.......);

                         所需头文件:#include <stdio.h>

函数说明

fprintf()会根据参数format字符串来转换并格式化数据,然后将结果输出到参数stream指定的文件中,直到出现字符串结束('\0')为止。

返回值:        成功:实际输出的字符数,

失败:-1,错误原因存于errno中。

例程:

#include<stdio.h>

main()

{

int i = 150;

int j = -100;

double k = 3.14159;

fprintf(stdout,”%d %f %x \n”,j,k,i);

fprintf(stdout,”%2d %*d\n”,i,2,i);

}

 

 

执行

-100 3.141590 96

150 150

 

                 9:格式化字符串输入:int fscanf(FILE * stream ,const char*format,....);

                         所需头文件:#include <stdio.h>

函数说明

fscanf()会自参数stream的文件流中读取字符串,再根据参数format字符串来转换并格式化数据。格式转换形式请参考scanf()。转换后的结构存于对应的参数内。

返回值:        成功:参数数目,

失败:-1,错误原因存于errno中。

 

例程:

#include<stdio.h>

main()

{

int i;

unsigned int j;

char s[5];

fscanf(stdin,”%d%x %5[a-z] %*s %f”,&i,&j,s,s);

printf(“%d %d %s\n”,i,j,s);

}

执行

10 0x1b aaaaaaaaabbbbbbbbbb /*从键盘输入*/

10 27 aaaaa

 

                 10:取得当前的工作目录:char * getcwd(char * buf,size_t size)

所需头文件:#include<unistd.h>

函数说明

getcwd()会将当前的工作目录绝对路径复制到参数buf所指的内存空间,参数size为buf的空间大小。在调用此函数时,buf所指的内存空间要足够大,若工作目录绝对路径的字符串长度超过参数size大小,则回值NULL,errno的值则为ERANGE。倘若参数buf为NULL,getcwd()会依参数size的大小自动配置内存(使用malloc()),如果参数size也为0,则getcwd()会依工作目录绝对路径的字符串程度来决定所配置的内存大小,进程可以在使用完此字符串后利用free()来释放此空间。

返回值:成功:将结果复制到参数buf所指的内存空间,

或 是返回自动配置的字符串指针。

失败:NULL,错误代码存于errno。

例程:

#include<unistd.h>

main()

{

char buf[80];

getcwd(buf,sizeof(buf));

printf(“currentworking directory : %s\n”,buf);

}

执行

current workingdirectory :/tmp