Linux_1:命令

目录

linux目录结构及文件操作

linux命令

linux文件目录分布

常用linux命令

Vim编辑器

vi常用两种模式

命令行模式

文本输入模式

linux文件函数

open函数

Close函数 

Write函数

Read函数

main函数参数

实现CP指令

lseek函数

文件IO与标准IO 

缓存

验证库缓存的存在

fopen函数

fread函数

memset函数

fwrite函数

fseek函数

fclose函数

三类读写函数

行缓存的读写函数fgets和fputs

刷新缓存函数

调整读写位置指针函数

行缓存的读写函数gets和puts

一个字符读写函数fgetc和fputc

cat命令的实现

​编辑

静态库和动态库

静态库的制作

动态函数库的制作


linux目录结构及文件操作

linux命令

Windows采用的命令:DOS命令

Linux采用的命令:Shell命令

linux文件目录分布

Linux文件目录是呈现一个树状的数据结构

根目录: / 也就是说目录的一个源头

用户目录:~ 或者 /home/username

常用linux命令

cd + 文件夹名字: 访问某个文件夹

ls:显示当前所在目录的文件

touch + 文件名:创建文件

rm + 文件名:删除文件

mkdir + 目录名:创建目录

rm -rf + 目录名:删除目录

TAB键:补全

sudo + 命令:用管理员权限执行命令

pwd: 显示当前目录的绝对路径

Vim编辑器

vi和vim的区别:vim是vi的升级版,基础功能两者一致,不过在嵌入式开发板中 只有vi没有vim,但是在Ubuntu上我们可以使用vim编辑器,它的功能更加丰富。

sudo apt‐get install vim

vi + 文件名 用vi打开/创建某个文本文件

vi常用两种模式

命令行模式

按ESC进入,在这个状态下,可以输入命令常用命令

: + 行号:跳转到某一行

G:跳转到文本末尾

yy: 复制某一行,复制的位置由光标所在位置决定

yx:复制若干行,x代表行数,输入2,就是复制当前行和它下面的两行(总共三行), 复制的位置由光标所在位置决定

p:把刚刚复制的内容进行粘贴,粘贴的位置由光标所在位置决定

:+wq 保存文本并退出

:+q 正常退出文本

:+q! 强制退出文本

:set nu 程序显示行号

:dd 删除一行

ESC: gg=G 自动整理代码

文本输入模式

按i进入

安装 gcc linux编译器: sudo apt‐get install gcc

将写完的程序 进行编译,生成二进制文件 gcc test.c

a.out:编译完之后默认生成的文件

指定生成的文件名 gcc test.c  –o  hello

linux文件函数

open函数

1.Linux自带的工具:man手册

man 1 是普通的shell命令,比如ls

man 2 是系统调用函数,比如open,write说明

在Linux系统库的定义:

int open(const char *pathname, int flags);   /* 比较常用*/

int open(const char *pathname, int flags, mode_tmode);

包含的头文件:

#include <sys/types.h>//这里提供类型pid_t和size_t的定义

#include <sys/stat.h>

#include <fcnt1.h>

2.返回值:

成功,返回句柄,我们后面对于文件的读写,关闭等都通过句柄来操作。

失败,返回-1

3.参数说明:

grep -nr "xxxx"./    cd - 返回上级工作目录

在 /usr/include 中查找

pathname:文件的路径名,如果只写文件名,就默认当前目录,如果在文件名加上路径,就按照绝对路径来打开文件。

flags:表示打开文件后用的操作

底层是一个宏,它可能以十六进制的形式存放。

O_RDONLY:只读模式 0x 0000 0000

O_WRONLY:只写模式 0x 00000001

O_RDWR:可读可写 0x 00000002

O_APPEND:表示追加,如果原来文件里面有内容,则这次写入会写在文件的最末尾。0x00002000

O_CREAT:表示如果指定文件不存在,则创建这个文件 0x0000 0100

O_EXCL:表示如果要创建的文件已存在,则出错,同时返回-1,并且修改errno 的值。

O_TRUNC:表示截断,如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。

O_NOCTTY:如果路径名指向终端设备,不要把这个设备用作控制终端

Close函数 

在Linux系统库的定义:

int close(int fd);

包含的头文件:

#include <unistd.h>

功能就是简单的关闭文件

 Linux文件权限:Linux 系统中采用三位十进制数表示权限,如0755, 0644.

ABCD

A - 0, 表示十进制  |  B-用户  |  C-组用户  |  D-其他用户

‐‐‐  ‐> 0   (no excute , nowrite ,no read)

‐‐x  ‐> 1   execute, (nowrite, no read)

‐w‐ ‐> 2   write 

‐wx ‐> 3   write, execute

r‐‐  ‐> 4   read

r‐x ‐> 5   read, execute

rw‐ ‐> 6   read, write

rwx ‐> 7   read, write , execute

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
        int fd;     //file describe
        fd = open("/home/u/procedure/mm",O_RDONLY | O_CREAT);
        if( fd == -1)
        {
                printf("open failed\n");
                return -1;
        }

        printf("open successod\n");

        close(fd);

        return 0;

}

Write函数

write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。

ssize_twrite (int fd,const void * buf, size_t count);

fd: 文件描述符

*buf: 写入的数据的首地址

count: 写入数据个数

返回值:如果顺利write()会返回实际写入的字节数(len)。当有错误发生时则返回-1,错误代码存入errno中

Read函数

从打开的fd设备或文件中读取count个字节到buf中

ssize_t read(int fd,void * buf, size_tcount);

fd: 文件描述符

*buf: 读入数据的首地址

count: 读入数据的个数

返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read 返回0

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define fileName "mm"
#define writeNum 108
#define readNum 12

//int open(const char *pathname, int flags);
//int open(const char *pathname, int flags, mode_t mode);
//ssize_t write(int fd, const void *buf, size_t count);
//ssize_t read(int fd, void *buf, size_t count);

int main()
{
        int fd;
        char writebuff[writeNum] = {0};
        char readbuff[readNum] = {0};
        char *p = "hello world!";


        if(writeNum < (strlen(p) + 1))
        {
                printf("Error:writeBuff less than p\n");
                return -1;
        }

        strcpy(writebuff,p);

        fd = open(fileName,O_RDWR | O_CREAT,0755);
        if(fd == -1)
        {
                printf("open file failded\n");
                perror("why");
                return -1;
        }
        printf("open file successed\n");

        //write(fd,writebuff,11);

        read(fd,readbuff,11);
        printf("%s\n",readbuff);
        close(fd);

        return 0;
}

注:1.write和read函数不能一起使用,光标的偏移

2.如果readnum中没有‘\0’,会出错

main函数参数

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

{

        return 0;

}

1.C语言规定了main函数的参数只能有两个,一个是argc,一个是argv并且,argc只能是整数,第二个必须是指向字符串的指针数组。

2.main函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时, 在DOS提示符下键入文件名,再输入实际参数即可把这些实参传送到main的形参中去。

DOS提示符下命令行 的一般形式为: C:>可执行文件名 参数 参数……; 但是应该特别注意的是,main 的两个形参和命令行中的参数在 位置上不是一一对 应的。

#include <stdio.h>

int main(int argc,char *argv[])
{
        printf("parameter toral %d\n",argc);
        printf("parameter first %s\n",argv[0]);
        printf("parameter second %s\n",argv[1]);
        printf("parameter third %s\n",argv[2]);
        return 0;
}

3.argc: 参数表示命令行中参数的个数(注意 文本名本身也是一个参数),argc的值是在输入命令行时由系统按实际参数的个数自动赋予的。

argv :参数是字符串指针数组,其各元素值为命令行中各字符串(参数均按字符串处理)的首地址。 指针数组 的长度即为参数个数。数组元素初值由系统自动赋予。

实现CP指令

src 源文件,des 目标文件

执行流程:

打开源文件(src)open

打开目标文件(des) open

写入目标文件 write

读取src文件到缓存数组 read

关闭目标文件和源文件 close

./a.out   src.c   des.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char *argv[])
{
        int src_fd;
        int des_fd;
        int nRet = 0;
        char readBuff[120] = {0};

        if(argc != 3)
        {
                printf("ERROR\n");
                return -1;
        }

        src_fd = open(argv[1],O_RDWR);
        if(src_fd < 0)
        {
                printf("open file %d  failed\n",src_fd);
                return -2;
        }

        des_fd = open(argv[2],O_RDWR | O_CREAT,0755);
        if(des_fd < 0)
        {
                printf("open file %d  failed\n",des_fd);
                return -3;
        }

        while(1)
        {
                nRet = read(src_fd,readBuff,128);
                if(nRet < 128)
                        break;
                write(des_fd,readBuff,nRet);
                memset(readBuff,128,0);
        }

        write(des_fd,readBuff,nRet);

        close(src_fd);
        close(des_fd);

        return 0;
}

lseek函数

off_t lseek(int fd, off_t offset, int whence);  //光标的偏移量

fd : 文件描述符

Offset :偏移量

Whence :

        SEEK_SET: 参数offset即为新的读写位置

        SEEK_CUR: 以目前的读写位置往后增加offset个偏移量

        SEEK_END: 将读写位置指向文件尾后再增加offset个位移量,当whence值为SEEK_CUR或SEEK_END时, 参数offset允许负值的出现。

返回值: 文件读写距离文件开头的字节大小,出错返回 -1

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define fileName "mm"
#define writeNum 108
#define readNum 12


int main()
{
        int fd;
        int offset;
        char writebuff[writeNum] = {0};
        char readbuff[readNum] = {0};

        char *p = "hello world!";

        if(writeNum < (strlen(p) + 1))
        {
                printf("Error:writeBuff less than p\n");
                return -1;
        }

        strcpy(writebuff,p);


        fd = open(fileName,O_RDWR | O_CREAT,0755);
        if(fd == -1)
        {
                printf("open file failded\n");
                perror("why");
                return -1;
        }
        printf("open file successed\n");

        offset = lseek(fd,-2,SEEK_END);
        printf("offset is %d\n",offset);

        write(fd,writebuff,12);

        read(fd,readbuff,12);
        printf("%s\n",readbuff);

        return 0;
} 

文件IO与标准IO 

1.linux标准文件描述符

文件IO:是直接调用内核提供的系统调用函数, 头文件是unistd.h

标准IO:是间接调用系统调用函数,头文件是: stdio.h

之前学过:输入输入相关的函数,都是和标准的输入(键盘),标准的输出(显示器) 

getchar(),putchar() ‐‐‐‐一个字符

gets(buf),puts(buf) ‐‐‐‐一串字符

scanf(),printf()    ‐‐‐‐ 一个字符,一串字符都可以

与一些普通文件的读写没有关系,也即这些函数不能读写普通文件。

标准IO中的相关函数,不仅可以读写普通文件,也可以向标准的输入或标准的输出中读或写

缓存

1.我们的程序中的缓存,就是你想从内核读写的缓存(数组)----用户空间的缓存

2.每打开一个文件,内核在内核空间中也会开辟一块缓存,这个叫内核空间的缓存

文件IO中的写即是将用户空间中的缓存写到内核空间的缓存中。

文件IO中的读即是将内核空间的缓存写到用户空间中的缓存中。

3.标准IO的库函数中也有一个缓存,这个缓存称为----库缓存

C库缓存的特点:

1.遇到\n 时,会将库缓存的内容写到内核缓存中,即调用了系统调用函数。

2.库缓存写满时,会调用系统调用函数,将库缓存内容写到内核缓存中。1024 

3.调用系统函数,write   

4.fflush

验证库缓存的存在

#include <stdio.h>
#include <unistd.h>

int main()
{
        char readBuff[] = "hello,world!";
        printf("%s",readBuff);
        while(1);
        return 0;
}

无法显示

#include <stdio.h>
#include <unistd.h>

int main()
{
        char readBuff[] = "hello,world!";
        printf("%s\n",readBuff);
        while(1);
        return 0;
}

#include <stdio.h>
#include <unistd.h>

int main()
{
        char readBuff[] = "hello,world!";
        //printf("%s\n",readBuff);
        write(1,readBuff,sizeof(readBuff));//STDOUT
        while(1);
        return 0;
}
                                          

系统调用,跳过缓存区

fopen函数

fopen fwrite fread fclose ... 属于标准C库

open close write read 属于Linux系统调用

include<stdio.h>   standard io lib

可移植性:fopen 强过于 open ...

fopen 在用户态是缓存的

open 在用户态是没有缓存的

FILE * fopen(constchar *path , cost char *mode)

/*

* @description       : 打开一个文件,返回指向该文件的指针

* @param ‐ path    :  指定文件路径,如:"./test.txt"

* @param ‐ mode  :指定文件的打开方式,如下图:

* @return                :  成功,返回指向该文件的文件指针; 若失败,返回NULL

*/

参数说明:第一个参数为欲打开文件的文件路径及文件名,第二个参数表示对文件的打开方式

注:mode有以下值:

r:只读方式打开,文件必须存在

r+:可读写,文件必须存在

rb+:打开二进制文件,可以读写

rt+:打开文本文件,可读写

w:只写,文件存在则文件长度清0,文件不存在则建立该文件

w+:可读写,文件存在则文件长度清0,文件不存在则建立该文件

a:附加方式打开只写,不存在建立该文件,存在写入的数据加到文件尾,EOF符保留

a+:附加方式打开可读写,不存在建立该文件,存在写入的数据加到文件尾,EOF符不保留

wb:打开二进制文件,只写

wb+:打开或建立二进制文件,可读写

wt+:打开或建立文本文件,可读写

at+:打开文本文件,可读写,写的数据加在文本末尾

ab+:打开二进制文件,可读写,写的数据加在文件末尾

由mode字符可知,上述如r、w、a在其后都可以加一个b,表示以二进制形式打开文件

例:

FILE *pfile=fopen(constchar *filename,"rb");

返回值: 文件打开了,返回一个指向该打开文件的指针(FILE结构);文件打开失败,错误上存errorcode(错误代码)。

注意:在fopen操作后要进行判断,是否文件打开,文件真正打开了才能进行后面的读或写操作,如有错误要进行错误处理。

fread函数

size_t fread(void*buff , size_t size, size_t count , FILE* stream)

/*

* @description  :对已打开的流进行数据读取 //从文件中读入数据到指定的地址中

* @param ‐ ptr  :指向数据块的指针

* @param ‐ size  :指定读取的每个数据项的字节数

* @param ‐ nmemb  : 指定要读取的数据项的个数

* @param ‐ stream  :要读取的文件流

* @return   : 返回实际读取数据项的个数;

*/

参数:

第一个参数为接收数据的指针(buff),也即数据存储的地址

第二个参数为单个元素的大小,即由指针写入地址的数据大小,注意单位是字节

第三个参数为元素个数,即要读取的数据大小为size的元素个素

第四个参数为提供数据的文件指针,该指针指向文件内部数据

返回值:读取的总数据元素个数

int num,count;

int* pr=new int[num*count];

fread(pr, num*4, count, stream); //stream为fopen中返回的FILE指针

要将数据写入pr中,必须为pr分配内存,一个int为4个字节,所以要x4

memset函数

int fread(void *buffer,int size,int count,FILE*fp)

void *memset(void*buffer, int c, int count) 

buffer:为指针或是数组

c:是赋给buffer的值

count:是buffer的长度

memset(void*buff,0,sizeof(buff));  用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ’或‘/0’;

fwrite函数

int fwrite(void*buffer,int size,int count,FILE*fp)

/*

* @description  :对已打开的流进行写入数据块

* @param ‐ ptr  :指向 数据块的指针

* @param ‐ size  :指定写入的每个数据项的字节数,如调用sizeof(char)

* @param ‐ nmemb  :指定写入的数据项的个数

* @param ‐ stream  :要写入的文件流

* @return   : 返回实际写入的数据项的个数

*/

fread()──从fp所指向文件的当前位置开始,一次读入size个字节,重复count次,并将读入的数据存放到从buffer开始的内存中; buffer是存放读入数据的起始地址(即存放何处)。

fwrite()──从buffer开始,一次输出size个字节,重复count次,并将输出的数据存放到fp所指向的文件中。buffer是要输出数据在内存中的起始地址(即从何处开始输出)。

一般用于二进制文件的处理。

fseek函数

//重定位文件内部的指针

函数原型: int fseek(FILE *stream,long offset,int framewhere) 

参数:

第一个为文件指针,第二个是指针的偏移量,第三个是指针偏移起始位置

返回值:重定位成功返回0,否则返回非零值

需要注意的是该函数不是重定位文件指针,而是重定位文件内部的指针,让指向文件内部数据的指针移到文件中我们感兴趣的数据上,重定位主要是这个目的。

说明:执行成功,则stream指向以fromwhere为基准,偏移offset个字节的位置。执行失败(比方说offset偏移的位置超出了文件大小),则保留原来stream的位置不变

分别用3个宏

SEEK_SET 既0 文件开头

SEEK_CUR 既1 文件当前位置

SEEK_END 既2 文件结尾

但不推荐用数字,最好用宏

简言之:

1. fseek(fp,100L,SEEK_SET);把fp指针移动到离文件开头100字节处;

2. fseek(fp,100L,SEEK_CUR);把fp指针移动到离文件当前位置100字节处;

3. fseek(fp,100L,SEEK_END);把fp指针退回到离文件结尾100字节处。

fclose函数

//关闭一个文件流,使用fclose就可以把缓冲区内最后剩余的数据输出到磁盘文件中并释放文件指针和有关的缓冲区

函数原型:int fclose(FILE*stream)

/*

* @description  :关闭一个已打开的流

* @param ‐ stream                 

* @return          : 成功,返回0; 若失败,返回EOF

*/

#include <stdio.h>
#include <string.h>

int main()
{
        FILE *fp = NULL;
        int nRet = 0;
        char readBuff[12];
        memset(readBuff,0,12);
        char *writeBuff = "hello world";

        fp = fopen("mm","r+");
        if(fp == NULL)
        {
                printf("open file failed\n");
                return -1;
        }
        printf("oprn success\n");

        nRet = fread(readBuff,4,2,fp);
        if(nRet <= 0)
        {
                printf("read failed\n");
                return -2;
        }
        printf("read success\n");
        printf("read %s\n",readBuff);

        nRet = fseek(fp,1,SEEK_SET);
        if(nRet)
        {
                printf("fseek failed\n");
        }

        nRet = fwrite(writeBuff,4,1,fp);
        if(nRet <= 0)
        {
                printf("wrote failed\n");
        }

        nRet = fclose(fp);
        if(nRet)
        {
                printf("close failed\n");
                return -2;
        }
        printf("close success\n");

        return 0;
}
     

三类读写函数

1.行缓存 ,遇到换新行(\n),或者写满缓存时,即调用系统调用函数

读:fgets,gets,printf,fprintf,sprintf

写:fputs,puts,scanf

2.无缓存,只要用户调这个函数,就会将其内容写到内核中

stderr

3.全缓存,只有写满缓存再调用系统调用函数

读:fread

写:fwrite

行缓存的读写函数fgets和fputs

char *fgets (char *s, int size,FILE *stream)

第一个参数:缓存,即读到哪里去

第二个参数:读多少个字节

第三个参数:从什么地方读

返回值:若成功则为s(缓存的地址),若已处文件尾端或出错则为null

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

第一个参数:缓存,即写什么内容

第二个参数:写到哪里去

若成功则为非负值,若出错则为EOF -1 。

#include <stdio.h>

int main()
{
        FILE *fp;
        char writeBuff[] = "hello world";

        fp = fopen("aa","w+");
        fputs(writeBuff,fp);
        while(1);
        fclose(fp);
        return 0;
}

 注:没有while(1),fputs会写入,fclose会清缓存

刷新缓存函数

fflush(FIFE *fp)

把库函数中的缓存内容强制写到内核中。

#include <stdio.h>

int main()
{
        fputs("hello",stdout);
        fflush(stdout);
        while(1);
        return 0;
}

调整读写位置指针函数

1.fseek()参数与lseek是一样的但是返回值不一样

lseek的返回值是:当前文件的位置指针值;

fseek()的返回值是:成功返回0,失败返回-11;

#include <stdio.h>

int main()
{
        FILE *fp;
        char writeBuff[128] = "hello world";
        char readBuff[128] = {0};

        fp = fopen("aa","w+");
        if(fp == NULL)
        {
                printf("open file failed\n");
                return -1;
        }

        fputs(writeBuff,fp);

        fseek(fp,0,SEEK_SET);
        fgets(readBuff,128,fp);
        printf("%s\n",readBuff);

        fclose(fp);

        return 0;
}

2.rewind(FILE *fp) 用于设定流的文件位置指示为文件开始,该函数调用成功无返回值。

rewind()等价于(void)fseek(fp 0, SEEK_SET);  

3.ftell(FILE *fp) 用于取得当前的文件位置,调用成功则为当前文件位置指示,若出错则为-1L

#include <stdio.h>

int main()
{
        FILE *fp;
        int r;
        char writeBuff[128] = "hello world";
        char readBuff[128] = {0};

        fp = fopen("aa","w+");
        if(fp == NULL)
        {
                printf("open file failed\n");
                return -1;
        }

        fputs(writeBuff,fp);

        rewind(fp);
        fgets(readBuff,128,fp);
        printf("%s\n",readBuff);

        r = ftell(fp);
        printf("ftell is %d\n",r);

        fclose(fp);

        return 0;
}                  

行缓存的读写函数gets和puts

1.char *gets(char*s); 

int puts(const char *s);

2.gets 与fgets的区别:

gets()时不能指定缓存的长度,这样就可能造成缓存越界(如若该行长于缓存长度),写到缓存之后的存储空间中,从而产生不可预料的后果;

gets()只能从标准输入中读

gets()与fgets()的另一个区别是:gets()并不将新行符存入缓存中, fgets 将新行符存入缓存中;

3.puts 与fputs的区别:

puts()只能向标准输出中写

puts()与fputs()的另一个区别是: puts 输出时会添加一个新行符,fputs不会添加

4.fprintf、printf、sprintf 行缓存的函数

int fprintf(FILE *stream,”字符串格式”)

fprintf可以输出到文件中,也可输出到显示器, printf 只能输出到显示器中

int sprintf(str *, “字符串格式”) 输出内容到一个字符串中

#include <stdio.h>
#include <string.h>

int main()
{
        char readBuff[128] = {0};
        int len;

        fgets(readBuff,128,stdin);

        len = strlen(readBuff);
        printf("len is %d\n",len);

        fputs(readBuff,stdout);

        return 0;
}

#include <stdio.h>
#include <string.h>

int main()
{
        char readBuff[128] = {0};
        int len;

        //fgets(readBuff,128,stdin);
        gets(readBuff);

        len = strlen(readBuff);
        printf("len is %d\n",len);

        //fputs(readBuff,stdout);
        puts(readBuff);

        return 0;
}

#include <stdio.h>

int main()
{
        FILE *fp;
        int i = 10;

        fp = fopen("aa","w+");
        if(fp == NULL)
        {
                printf("open file failed\n");
                return -1;
        }

        fprintf(fp,"hello,you is %d!",i);

        return 0;
}

#include <stdio.h>

int main()
{
	char buf[128] = {0};
	int i = 10;

	sprintf(buf,"i id %d\n",i);

	printf("%s\n",buf);

	return 0;
}

一个字符读写函数fgetc和fputc

int fgetc(FILE *fp)

功能:从文件中读取一个字符;

参数:文件流

返回值:正确为读取的字符,到文件结尾或出错时返回EOF

int fputc(int c, FILE *fp)

功能:写一个字符到文件中

参数:第一个参数为要写的字符,第二个参数为文件流

返回值:成功则返回输入的字符,出错返回EOF。

是否是行缓存函数? 证明 fputc有缓存,但不是行缓存函数

#include <stdio.h>

int main()
{
        FILE *fp;

        fp = fopen("aa","w+");
        if(fp == NULL)
        {
                printf("open filr failed\n");
                return -1;
        }

        fputc('a',fp);

        //验证是不是行缓存
        fflush(fp);
        while(1);
        fclose(fp);

        return 0;
}
#include <stdio.h>

int main()
{
	FILE *fp;
	int nRet;

	fp = fopen("aa","w+");
	if(fp == NULL)
	{
		printf("open file failed\n");
		return -1;
	}

	fputc('a',fp);

	rewind(fp);

	nRet = fgetc(fp);
	printf("nRet is %c\n",nRet);
	
	nRet = fgetc(fp);
	printf("nRet is %d\n",nRet);

	fclose(fp);

	return 0;
}

int feof(FILE *stream);  

功能:判断是否已经到文件结束

参数:文件流

返回值:到文件结束,返回为非0,没有则返回0

int ferror(FILE *stream); 

功能:判断是否读写错误

参数:文件流

返回值:是读写错误,返回为非0,不是则返回0

void clearerr(FILE *stream); 

功能:清除流错误

参数:文件流

#include <stdio.h>

int main()
{
        FILE *fp;
        int nRet;

        fp = fopen("aa","w+");
        if(fp == NULL)
        {
                printf("open file failed\n");
                return -1;
        }

        fputc('a',fp);

        rewind(fp);

        nRet = fgetc(fp);
        printf("nRet is %c\n",nRet);

        nRet = fgetc(fp);
        printf("nRet is %d\n",nRet);

        printf("feof is %d,ferror is %d\n",feof(fp),ferror(fp));
        clearerr(fp);
        printf("feof is %d,ferror is %d\n",feof(fp),ferror(fp));

        fclose(fp);

        return 0;
}

#include <stdio.h>

int main()
{
        FILE *fp;
        char *nRet;
        char writeBuff[128] = "hello world";
        char readBuff[128] = {0};

        fp = fopen("aa","w+");
        if(fp == NULL)
        {
                printf("open file failed\n");
                return -1;
        }

        fputs(writeBuff,fp);

        rewind(fp);
        nRet = fgets(readBuff,128,fp);
        printf("%s\n",readBuff);

        nRet = fgets(readBuff,128,fp);
        printf("nRert = %p\n",nRet);

        printf("feof is %d,ferror is %d\n",feof(fp),ferror(fp));
        clearerr(fp);
        printf("feof is %d,ferror is %d\n",feof(fp),ferror(fp));

        fclose(fp);

        return 0;
}

cat命令的实现

#include <stdio.h>

int main(int argc,char *argv[])
{
        FILE *fp;
        int nRet = 0;

        if(argc != 2)
        {
                printf("failed\n");
                return -1;
        }

        fp = fopen(argv[1],"r");
        if(fp == NULL)
        {
                printf("open file failed\n");
                return -2;
        }

        while(1)
        {
                nRet = fgetc(fp);
                if(feof(fp))
                {
                        break;
                }
                fputc(nRet,stdout);
        }

        fclose(fp);

        return 0;
}

静态库和动态库

Linux操作系统支持的函数库分为:

静态库,libxxx.a,在编译时就将库编译进可执行程序中。

优点:程序的运行环境中不需要外部的函数库。

缺点:可执行程序大

动态库,又称共享库,libxxx.so,在运行时将库加载到可执行程序中。

优点:可执行程序小。

缺点:程序的运行环境中必须提供相应的库。

函数库目录:/usr/lib

静态库的制作

1.生成目标文件:gcc -c file.c  .o         (gcc sub.c -c -o sub.o)

2.静态函数库创建命令ar

        ar  ‐cr  libfile.a file.o     =     ar libfile.a -cr file.o  (ar -cr -o libsub.a sub.o)

‐c: create的意思 ,只编译不链接,生成目标文件

‐r: replace的意思,表示当插入的模块file.o已经存在libfile.a中,则覆盖。反之ar显示一个错误消息。

  1. 如果 libfile.a 不存在:创建新库并将 file.o 添加进去

  2. 如果 libfile.a 已存在:用新的 file.o 替换库中同名的目标文件

3.操作静态库的几个实例:

如果从别处得到一个静态库libunknown.a,想知道其中包含哪些模块。 命令:ar -t libunknown.a

静态库的编译:gcc -o main main.c -L. -lfile

编译main.c就会把静态函数库整合进main。

其中:-L指定静态函数库的位置供查找,注意L后面还有'.',表示静态函数库在本目录下查找

-l则指定了静态函数库名,由于静态函数库的命名方式是lib***.a,其中的lib和.a忽略。

删除libaddsub.a后main依然可以运行,因为静态库的内容已经整合进去了

#include <stdio.h>

int main()
{
        int x,y;
        int nRet;

        x = 10;
        y = 5;

        nRet = sub(x,y);
        printf("%d\n",nRet);
        return 0;
}
int sub(int x,int y)
{
        return (x + y);
}

gcc sub.c -c -o sub.o

ar -cr -o libsub.a sub.o

gcc main.c -L. -lsub

动态函数库的制作

1.生成目标文件:gcc -c file.c

2.gcc -shared -fpic -o libfile.so file.o

‐fpic:产生位置无关代码。 

‐shared:生成共享库。 

用上述命令生成libaddsub.so 动态函数库。 

gcc ‐o out  main.c  ‐L. ‐lfile

gcc -c -o sub.o sub.c

gcc -fpic -shared -o libsub.so sub.o

gcc -o main main.c -L. -lsub

此时还不能立即./out,因为在动态函数库使用时,会查找/usr/lib  /lib目录下的动态函数库,而此时我们生成的库不在里边。

第一种方法:

libaddsub.so放到/usr/lib或/lib中去。

mv libsub.so   /usr/lib

第二种方法,假设libfile.so在/home/linux/file 环境变量方法

export LD_LIBRARY_PATH=/home/linux/addsub

echo $LD_LIBRARY_PATH //查看当前环境变量

export LD_LIBRARY_PATH=/home/u/procrdure(当前路径)

echo $LD_LIBRARY_PATH

第三种方法:

在/etc/ld.so.conf文件里加入我们生成的库的目录,然后/sbin/ldconfig。

/etc/ld.so.conf是非常重要的一个目录,里面存放的是链接器和加载器搜索共享库时要检查的目录,默认是从/usr/lib  /lib中读取的,所以想要顺利运行,可以把我们库的目录加入到这个文件中并执行/sbin/ldconfig。

sudo vi /etc/ld.so.conf

加入当前路径

sudo ldconfig  /etc/ld.so.conf  使用ldconfig编译进去

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值