linux系统编程(一)——标准IO

b站Linux系统编程(李慧琴)

fopen函数

函数参数与返回值

       #include <stdio.h>

       FILE *fopen(const char *pathname, const char *mode);

         其中pathname是文件的路径,mode是打开的模式,返回值是FILE类型指针,失败则返回NULL,并置全局私有化变量errno的值,返回报错信息。

mode模式

       //以只读形式打开,流位于文件的开头,需文件必须存在,否则返回NULL
       r      Open text file for reading.  The stream  is  positioned  at  the
              beginning of the file.

       //以读写的形式打开,流位于文件的开头 ,需文件必须存在,否则返回NULL 
       r+     Open  for  reading and writing.  The stream is positioned at the
              beginning of the file.

       //以只写的形式打开,流位于文件的开头,文件不存在会创建文件,文件存在会截取到0长度
       w      Truncate file to zero length or create text  file  for  writing.
              The stream is positioned at the beginning of the file.

       //以读写形式打开,流位于文件的开头,文件不存在会创建文件,文件存在会截取到0长度
       w+     Open  for  reading  and writing.  The file is created if it does
              not exist, otherwise it is truncated.  The stream is  positioned
              at the beginning of the file.

      (注意当以追加模式打开,会忽略fseek,写的时候还是在文件末尾写入)
       // 以只写的形式打开文件,文件不存在会创建文件,流位于文件最后一字节的下一位
       a      Open  for  appending (writing at end of file).  The file is cre‐
              ated if it does not exist.  The stream is positioned at the  end
              of the file.

       // 以读写的形式打开文件,文件不存在会创建文件,初始时写的流位于文件最后一字节的下一位
          读的流位于文件开头
       a+     Open  for  reading  and appending (writing at end of file).  The
              file is created if it does not exist.  The initial file position
              for  reading  is  at  the  beginning  of the file, but output is
              always appended to the end of the file.

          特别注意 ,mode只会识别输入的第一个字符及下一个字符是不是+,例如:

 fp=fopen("/tmp","wkvfsdkjkj"); //文件以w模式打开
 fp=fopen("/tmp","w+vfsdkjkj"); //文件以w+模式打开

errno全局变量

         报错会置errno值,不同值代表不同的报错信息。

打开/usr/include/asm-generic/errno-base.h可以看到报错号代表的信息。

#define EPERM            1      /* Operation not permitted */
#define ENOENT           2      /* No such file or directory */
#define ESRCH            3      /* No such process */
#define EINTR            4      /* Interrupted system call */
#define EIO              5      /* I/O error */
#define ENXIO            6      /* No such device or address */

  例子:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(){
    FILE*fp=NULL;
    fp=fopen("tmp","r");
    if(fp==NULL){
        fprintf(stderr,"fopen() errnu:%d\n",errno);
        exit(1);
    }
}

运行结果:

book@100ask:~/Desktop/linux$ ./fopen 
fopen() errnu:2

        表示没有此文件或目录。

perror函数

函数参数

    #include <stdio.h>

    void perror(const char *s);

        该函数会自动把errno信息转化为字符串信息输出。

例如:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(){
    FILE*fp=NULL;
    fp=fopen("tmp","r");
    if(fp==NULL){
        perror("fopen error :");
        //fprintf(stderr,"fopen() errnu:%d\n",errno);
        exit(1);
    }
}

运行结果:

book@100ask:~/Desktop/linux$ ./fopen 
fopen error :: No such file or directory

fclose 和文件权限

fclose

        对打开的文件进行关闭。

  #include <stdio.h>

  int fclose(FILE *stream);

打开文件个数

        ulimit 可以查看用户所用的资源。ulimit -n可以得到每个进程所能打开的文件的最大个数。

ubuntu@VM-8-8-ubuntu:~/linux$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7694
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1048576
pipe size            (512 bytes, -p) 8

文件权限

        计算文件权限 0666& ~umask  ,设置umask可以设置建立的文件的权限,以达到保护。

ubuntu@VM-8-8-ubuntu:~/linux$ umask
0002

        修改umask值。

ubuntu@VM-8-8-ubuntu:~/linux$ umask 3
ubuntu@VM-8-8-ubuntu:~/linux$ umask 
0003

stdin 、stdout、stderr

        在进程创建时,会创建并打开标准输入、标准输出、标准错误三个文件,标准输入一般指向终端输入,标准输出和标准错误一般指向终端输出。用户可以重定向这3个流指向其它文件。

fgetc、getc、getchar函数

 #include <stdio.h>

       int fgetc(FILE *stream);

       int getc(FILE *stream);

       int getchar(void);

        getchar函数从输入流中获取一个字符。fgetc和getc函数的功能是一样的,可以指定从某个流中获取一个字符,不同的是fgetc是函数,getc是宏。失败读取和读到文件末尾返回EOF(-1).

fputc、putc、putchar函数

#include <stdio.h>

       int fputc(int c, FILE *stream);

       int putc(int c, FILE *stream);

       int putchar(int c);

DESCRIPTION
       fputc() writes the character c, cast to an unsigned char, to stream.

       putc() is equivalent to fputc() except that it may be implemented as
               a macro which evaluates stream more than once.

       putchar(c) is equivalent to putc(c, stdout).

gets、fgets函数

       #include <stdio.h>
       
       char *fgets(char *s, int size, FILE *stream);

       char *gets(char *s);

        gets使用比较危险,不建议使用,不检查缓冲区的溢出,gets()将stdin中的一行读取到s指向的缓冲中,直到出现终止换行符或EOF;

        gets()在成功时返回s,在出现错误时或在未读取任何字符的情况下出现文件结尾时返回NULL。但是,由于缺少缓冲区溢出检查,因此无法保证函数会返回。

        fgets()从流中最多读取一个小于大小的字符,并将它们存储到s所指向的缓冲区中。在EOF或换行后停止读取。如果一个换行被读取,它就会被存储到缓冲区中。一个终止的空字节(“\0”)存储在缓冲区的最后一个字符之后。

        fgets()在成功时返回s,在出错时返回NULL,或者在未读取任何字符的情况下出现文件结尾时返回NULL。

        fgets()使用举例:

#define SIZE 5
char buf[SIZE];
fgets(buf,SIZE,stream);
//fgets最多可读取到SIZE-1个字符,最后一个字符补'\0',
//或者读到'\n'或EOF就结束一行读取
/*
假设读取
abcd
这一行,用上面的语句需要读取两次,才能读完,第一次读取“abcd”,第2次读取“\n”
*/

fputs、puts函数

       #include <stdio.h>

       int fputs(const char *s, FILE *stream);

       int puts(const char *s);

        fputs()将字符串s写入流,而不使用其终止的空字节(“\0”)。

        puts()将字符串s和一个尾随换行符写入stdout。

        puts()和fputs()在成功时返回一个非负数,在错误时返回EOF。

fread、fwrite函数

       #include <stdio.h>

       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

       size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

       size 是以字节为单位,假如是2的话,就是基本项是2个字节,fread表示从流中读取size乘以nmemb个字节的大小,返回成功读取到的基本项的个数;fwrite类似。

        fread和fwrite以二进制流的形式读写,即把一块空间的数据搬到另外一块空间上。

1->数据量足够时
2->只有5个字节

fread(buf,1,10,fp);
//第1条件时,返回值10,读取到10个字节
//第2条件时,返回值5,读取到5个字符

fread(buf,10,1,fp);
//第1条件时,返回值1,读取到10个字节
//第2条件时,返回值0,读取到5个字节

 mycopy示例

        实现把一个文件复制到另外一个文件上,把f1复制到f2上。

./mycopy   f1   f2

代码:

#include <stdio.h>
#include <stdlib.h>

int main(int argc ,char **argv){
    FILE*fp1=NULL,*fp2=NULL;
    int ch;
    if(argc<3) { //检查参数数量
        fprintf(stderr,"please enter more elements\n");
    }
    fp1=fopen(argv[1],"r");
    if(fp1==NULL){
        perror("f1 fopen() error:");
        exit(1);
    }
    fp2=fopen(argv[2],"w");
    if(fp2==NULL){
        perror("f2 fopen() error");
        fclose(fp1);
        exit(1);
    }
    while((ch=fgetc(fp1))!=EOF){
        fputc(ch,fp2);
    }
    fclose(fp1);
    fclose(fp2);
}

使用fputs和fgets实现mycopy,只需修改while部分内容即可: 

    while(fgets(buf,BUF_SIZE,fp1)!=NULL){
        fputs(buf,fp2)
    }

使用fread和fwrite实现mycopy,修改while内容:

//成功读取到多少就写多少
while((num=fread(buf,1,100,fp1))>0){
        fwrite(buf,1,num,fp2);
    }

运行结果:

ubuntu@VM-8-8-ubuntu:~/linux$ ls -l
-rw-rw-r-- 1 ubuntu ubuntu  208 Sep 14 22:34 fopen.c
-rwxrwxr-x 1 ubuntu ubuntu 8608 Sep 16 21:19 mycopy
-rw-rw-r-- 1 ubuntu ubuntu    0 Sep 14 22:22 tmp
ubuntu@VM-8-8-ubuntu:~/linux$ ./mycopy fopen.c tmp
ubuntu@VM-8-8-ubuntu:~/linux$ diff tmp fopen.c
ubuntu@VM-8-8-ubuntu:~/linux$ 

fssek、ftell,rewind 函数

        fseek用于修改文件指针,ftell返回当前文件指针位置,rewind把文件指针指向开头。

       #include <stdio.h>

       int fseek(FILE *stream, long offset, int whence);

       long ftell(FILE *stream);

       void rewind(FILE *stream);

        long型有的机器是32位,有的是64位,大部分是32位。由于long,所以使用ftell相关文件最大为2G。用的时候要小心。whence有3个参数SEEK_SET, SEEK_CUR, or SEEK_END,分别表示文件开头,当前文件位置,文件末尾。offset表示设置的偏移量。

        rewind没有返回值;fseek成功时返回0,ftell返回文件当前的偏移量,错误返回-1.

fseek(fp,-10,SEEK_CUR);  //把文件指针从当前位置往前移10(指向文件开始方向)

fseek(fp,-10,SEEK_END);  //把文件指针从文件末尾往前移10(指向文件开始方向)

fseek(fp,10,SEEK_SET);   //把文件指针从文件开头往后移10(指向文件末尾方向)

查看文件大小:

#include <stdio.h>
#include <stdlib.h>
int main(int num,char**argv){
    if(num<2) {
        fprintf(stderr,"need more argv\n");
        return 1;
    }
    for(int i=1;i<num;++i){
        FILE *fp=fopen(argv[i],"r");
        if(fp==NULL){
            perror("open error");
            exit(1);
        }
        fseek(fp,0,SEEK_END);
        printf("%s is %ld\n",argv[i],ftell(fp));
        fclose(fp);
    }
    return 0;
}

运行结果:

ubuntu@VM-8-8-ubuntu:~/linux$ ls -l
-rwxrwxr-x 1 ubuntu ubuntu 8656 Oct  2 22:26 file_stage
-rw-rw-r-- 1 ubuntu ubuntu  425 Oct  2 22:26 file_stage.c
-rw-rw-r-- 1 ubuntu ubuntu  208 Sep 14 22:34 fopen.c
-rw-rw-r-- 1 ubuntu ubuntu  291 Sep 17 21:46 fread.c
-rw-rw-r-- 1 ubuntu ubuntu  602 Sep 17 20:43 mycopy.c
ubuntu@VM-8-8-ubuntu:~/linux$ ./file_stage  mycopy.c fread.c file_stage.c
mycopy.c is 602
fread.c is 291
file_stage.c is 425

fflush函数

       #include <stdio.h>

       int fflush(FILE *stream);

        fflush函数的作用是强制刷新缓冲区。缓冲区的作用:大多数是好事,合并系统调用。

        行缓冲:换行时刷新,满了刷新,强制刷新(标准输出是这样的)

        全缓冲:满了刷新你,强制刷新(默认情况,只要不是终端设备)

        无缓冲:如stderr,需要立即输出的内容

使用举例:

        下面例子不会输出niaho,加上fflush才会输出nihao。如果fflush的参数是NULL,强制刷新所有打开的输出流。

#include <stdio.h>

int main(){
    printf("nihao");
    //fflush(NULL);
    while(1);
    printf("wohao");
    return 0;
}

getline函数

        getline的作用是完整的从流中读取一行。

       #include <stdio.h>

       ssize_t getline(char **lineptr, size_t *n, FILE *stream);

        第一个参数接受的是一个char*类型指针的地址,getline内部使用malloc申请空间,使用指针的指针已达到传递已申请的空间。第二个参数接受size_t类型地址,传回申请的空间的大小。第三个参数是要读取的流。成功时读取返回值是读取到的字符的个数,失败时,返回-1.

        如果输入*lineptr为NULL,*n为0,则初始时会分配给空间。如果*lineptr已经指向了已分配的空间,*n不为0,则不会再调用malloc分配空间,如果内存不足,会调用realloc分配更大的空间。

使用举例:读取文件每一行,输出每一行读取到的字符个数和空间大小。

#include <stdio.h>
#include <stdlib.h>
int main(int num,char**argv){
    if(num<2) {
        puts("need more argv");
        exit(1);
    }
    FILE*fp=fopen(argv[1],"r");
    char* linebuf=NULL;
    size_t linesize=0;
    while(1){
        int num=getline(&linebuf,&linesize,fp);
        if(num<0) break;
        printf("%d  %ld\n",num,linesize);

    }
    fclose(fp);

    exit(0);
}

运行结果:

ubuntu@VM-8-8-ubuntu:~/linux$ cat tmp
12345


ubuntu@VM-8-8-ubuntu:~/linux$ ./getline tmp
6  120
1  120
1  120

        第一行读取到6个字符是因为包含回车,2,3行有回车,所以算是1个字符。

临时文件

       #include <stdio.h>

       FILE *tmpfile(void);

        tmpfile可以创建一个临时文件,以w+b模式打开,直接返回FILE*类型文件指针,当使用fclose关闭文件或进程终止时,临时文件会自动销毁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值