文件IO-进线程

一、io和文件

> 1、标准io 
> 2、文件io 
> 3、库的封装 
> 4、文件: 	相关数据的有序集合;
> 5、文件名: 	数据的有序集合的名称。

二、进线程

    多进程编程
    多线程编程
    线程间通信
    进程间通信:管道、信号,套接字

三、文件类型

    文件概念:相关数据的有序集合,存放在磁盘上。
    - 普通文件
    d目录文件
    c字符设备文件:键盘,鼠标;读取数据的大小。
    b块设备文件:(磁盘等存储设备文件)
    p管道文件:pine(有名管道文件)
    l符号链接文件:快捷方式
    s套接字文件:(UNIX域套接字的文件)
        块设备和字符设备的区别:读取数据的大小
注意:不同的操作系统使用的文件类型不同

四、标准IO

    标准IO遵循 --->ANSI C标准,
    实质:使用标准IO就是调用标准的C库函数
    特点:标准IO通过缓冲机制减少系统调用的次数,从而提高程序运行的效率。
    标准io是文件IO的再封装。
    标准IO是高级IO:一般用于普通文件数据读写
    文件IO是低级IO

五、流的类型

    1、文本流:以ascii码的方式进行存储。
    2、二进制流:如果是字符数字,将字符数据转换位对应的二进制进行存储,非字符数字通过转换为ASCII码进行存取。
    文本流处理换行符的方式:
        文本流:会将换行符‘\n’转换位'\r''\n'
        二进制流:没有区分,不进行转换。
    linux下没有做区分

六、缓冲区类型

    1、全缓存:文件打开,默认使用全缓存。
        全缓存特点:当全缓存区满的时候,才会真正的实现IO操作。或者强行刷新缓冲区。
    2、行缓存
        当IO操作跟终端相关的时候,使用行缓存。
        当遇到换行符或者缓冲区满才会输出输入,或者强行刷新。
    3、无缓存
        当IO操作时跟错误相关时,使用无缓存。
        标准IO三个特殊流(流指针);
        (1)标准输入流(键盘)0 stdin
        (2)标准输出流(终端)1stdout
        (3)标准错误流    2 stderr

> 刷新缓冲区的5种方法;
> 1、‘\n’
> 2、fflush(FILE *stream);
> 3、fclose(FILE *stream);
> 4、程序正常结束或者exit结束程序。
> 5、特殊情况,当输出流遇到输入流时,会刷新行缓冲区。

练习:C语言输出行缓存 1024

    printf("hello\n");
    printf("行缓存:%d\n",stdou->_IO_buf_end - stdout->_IO_buf_base);
    man手册
        第一页:shell指令和可执行程序
        第二页:系统调用函数
        第三页:标准C库函数

七、标准IO相关库函数

    fopen()/fclose()--打开关闭文件
    fget()/fput()--按字节输入输出
    fgets()/fputs()--按行输入输出
    fread()/fwrite()--按对象输入输出
    fflush()--刷新流
    foef()/ferror()--判断错误流
    ftell()/fseek()/rewind()--定位流
## 利用fseek和ftell定位

    函数的查找:EOF对应的宏就是 -1int  fseek(FILE  *stream,  long  offset,  int whence);
        参数功能:
            FILE *stream:自己定义的流指针;
            long offset:偏移量
            whence:何处
        返回值:
            整型int

练习:打开文件的上限

    int count=0;
    while(fopen ("count.txt","w"))
    {
        count++;
    }
    printf("count:%d\n",count+3);

练习:利用fgetc and fputc 完成文件的复制cp,并且计数 源文件的字符个数(包括空格);

    #include<stdio.h>

int main(int argc, char *argv[])
{
    printf("argc:%d\n",argc);
    printf("argv:%s\n",argv[0]);
    FILE *a = fopen(argv[1],"r");
    FILE *b = fopen(argv[2],"w");
    char ch;
    int count=0;
    while((ch = fgetc(a)) != -1)
    {
        count++;
         fputc(ch,b);
    }
    printf("count:%d\n",count-1);
    fclose(a);
    fclose(b);
    return 0;
}

练习:用fgets fputs

//复制照片
	FILE *fp = fopen(argv[1],"r");
	FILE *fp2 = fopen(argv[2],"w");
	char buf[2] = {0};
	int line = 0;
	while(1){
		fgets(buf,sizeof(buf),fp);
		if( feof(fp) || ferror(fp)){
			perror("fgets");
			break;
		}
		if(buf[0] == '\0')
		{
			fputc('\0',fp2);
			line++;
		}
		//遇见‘0’就立即停止,
		line +=fputs(buf,fp2);
		
	}
	printf("line:%d\n",line);
	fclose(fp);
	fclose(fp2);
//记录行数
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
    char buf[36] = {0};
    int count=0;
    FILE *a=fopen("1.txt","r");
    FILE *b=fopen("2.txt","w");
    while( (fgets(buf,36,a)) != NULL)
    {
        if
        count++;
        fputs(buf,b);
    }
    printf("行数:%d\n",count);
    fclose(a);
    fclose(b);
    return 0;
}

重要问题理解

 问题:
	**1、文件里面写满了以后,4096哪里是什么。
		如果一行写满了的话,必须要有一个‘\n’作为结束。
	2、fgets读出来的是什么,fputs放回去的是什么。
		fgets是要遇到‘\n’,或者读满才会结束。
		fputs是遇到'\0'或者‘0’值就会结束,为什么可以直接用来文件拷贝。
		因为文件分为文本流和二进制流,二进制流,和图片(混合存储)。
	3、怎么解决fputs放回去的时候,自己增加一个‘\n’
		‘\n'不用去管,主要是'\0'要主动强行添加进去(遇到二进制流,或者混合存储);**

八、文件IO

 **1、不带缓存的IO操作,是系统调用的接口函数。
	2、文件描述符:
		是系统最小的、未用的非负整数,(是内核向进程返回的 操作文件的标识符)
		
		标准输入、标准输出、标准错误输出(0, 1, 2)
		
	3、接口函数
		1、函数原型:
			int open(const char *path, int oflag, mode_t mode);
			功能:
				打开或者创建打开文件
			头文件:
				#include <sys/types.h>
				#include <fcntl.h>
			参数:
				path	:待操作的文件名(可包含路径)
				oflag	:文件的操作方式:
						O_RDONLY、O_WRONL、O_RDWR | O_CREAT | O_APPEND.....
				mode	:文件的存根权限(8进制表示法)
			返回值:
				成功:文件描述符
				失败:-1,并设置错误信息
				
		2、函数原型:
			ssize_t read(int filedes, void *buf, size_t n);
			功能:
				从 filedes 对应的文件中,读取前 n个字节的数据到 buf地址上。
			头文件:
				#include <unistd.h>
			参数:
				filedes		:文件描述符
				buf			:存储数据的缓冲区首地址
				n			:要读取的字节数
			返回值:
				成功	:实际读取的字节数
				文件末尾:0
				失败	:-1,并设置错误信息
				
		3、函数原型:
			ssize_t write(int filedes, void *buf, size_t n);
			功能:
				将buf 地址上前 n个字节数据 写入 filedes对应的文件中。
			头文件:
				#include <unistd.h>
			参数:
				filedes		:文件描述符
				buf			:存储数据的缓冲区首地址
				n			:要写入取的字节数
			返回值:
				成功	:实际写入的字节数
				失败	:-1,并设置错误信息
				
		4、函数原型:
			int close(int filedes);**

九、获取文件信息(包括目录信息);

这里是引用

首先-->获取文件的属性:
	我们要用到的函数是,系统调用的函数。
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <unistd.h>
	int stat(const char *pathname, struct stat * statbuf);
	返回值:
		成功返回 0;
		失败返回 -1;
	参数:
		pathname: 文件路径和文件名称,就是一个字符串或者传入一个字符串的首地址。
		statbuf:结构体指针的首地址。
	struct stat buf详解:
		struct stat
{
    dev_t     st_dev;     /* ID of device containing file */文件使用的设备号
    ino_t     st_ino;     /* inode number */    索引节点号 
    mode_t    st_mode;    /* protection */  文件对应的模式,文件,目录等
    nlink_t   st_nlink;   /* number of hard links */    文件的硬连接数  
    uid_t     st_uid;     /* user ID of owner */    所有者用户识别号
    gid_t     st_gid;     /* group ID of owner */   组识别号  
    dev_t     st_rdev;    /* device ID (if special file) */ 设备文件的设备号
    off_t     st_size;    /* total size, in bytes */ 以字节为单位的文件容量   
    blksize_t st_blksize; /* blocksize for file system I/O */ 包含该文件的磁盘块的大小   
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */ 该文件所占的磁盘块  
    time_t    st_atime;   /* time of last access */ 最后一次访问该文件的时间   
    time_t    st_mtime;   /* time of last modification */ /最后一次修改该文件的时间   
    time_t    st_ctime;   /* time of last status change */ 最后一次改变该文件状态的时间   
};
	st_mode权限:
st_mode 主要包含了 3 部分信息:

15-12 位保存文件类型

11-9 位保存执行文件时设置的信息

8-0 位保存文件访问权限
	    S_IFMT   0170000    文件类型的位遮罩
    S_IFSOCK 0140000    套接字
    S_IFLNK 0120000     符号连接
    S_IFREG 0100000     一般文件
    S_IFBLK 0060000     区块装置
    S_IFDIR 0040000     目录
    S_IFCHR 0020000     字符装置
    S_IFIFO 0010000     先进先出
​
    S_ISUID 04000     文件的(set user-id on execution)位
    S_ISGID 02000     文件的(set group-id on execution)位
    S_ISVTX 01000     文件的sticky位
​
    S_IRUSR(S_IREAD) 00400     文件所有者具可读取权限
    S_IWUSR(S_IWRITE)00200     文件所有者具可写入权限
    S_IXUSR(S_IEXEC) 00100     文件所有者具可执行权限
​
    S_IRGRP 00040             用户组具可读取权限
    S_IWGRP 00020             用户组具可写入权限
    S_IXGRP 00010             用户组具可执行权限
​
    S_IROTH 00004             其他用户具可读取权限
    S_IWOTH 00002             其他用户具可写入权限
    S_IXOTH 00001             其他用户具可执行权限
​
    上述的文件类型在POSIX中定义了检查这些类型的宏定义:
    S_ISLNK (st_mode)    判断是否为符号连接
    S_ISREG (st_mode)    是否为一般文件
    S_ISDIR (st_mode)    是否为目录
    S_ISCHR (st_mode)    是否为字符装置文件
    S_ISBLK (s3e)        是否为先进先出
    S_ISSOCK (st_mode)   是否为socket
    若一目录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名,在linux中,最典型的就是这个/tmp目录啦。
## 练习利用读取目录信息和文件信息 完成一部分ls功能

```c
/*===============================================
*   文件名称:2_homework.c
*   创 建 者:     
*   创建日期:2022年07月17日
*   描    述:
================================================*/
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <time.h> 
#include <pwd.h>//getpwuid
#include <grp.h>
#include <sys/stat.h>
#include <unistd.h>
void print(char *str,char *name);
struct stat buf;//读取文件信息,需要的缓冲区。
struct tm *tm;//存放时间信息的结构体指针。
int ret;//
struct dirent *p;//读取目录信息的结构体指针,可以通过它访问目录结构体里面的信息。
char buf2[64] = {0};//save path and name,我用来把文件的目录和名称拼接到一起,定义的字符串。
int main(int argc, char *argv[])
{ 
    DIR *dir;
    dir = opendir(argv[1]);
    if(dir == NULL)
    {
        perror("opendir");
        return -1;
    }
    while( (p = readdir(dir)) )
    {
        strcat(buf2,argv[1]);
        if(argv[1][strlen(argv[1])-1] != '/')
        {
        	strcat(buf2,"/");
        }
        strcat(buf2,p->d_name);
       print(buf2,p->d_name);
        memset(buf2,0,sizeof(buf));
    }
    return 0;
} 
int print(char *str,char *name)//
{
	if(name[0] != '.')
{
	 ret = stat(str,&buf);
	 if(ret == -1)
	 {
	 	perror("stat");
	 	return -1;
	 }
    switch (buf.st_mode & S_IFMT)
    {
        case S_IFBLK:printf("b");break;
        case S_IFCHR:printf("c");break;
        case S_IFDIR:printf("d");break;
        case S_IFIFO:printf("p");break;
        case S_IFLNK:printf("l");break;
        case S_IFREG:printf("-");break;
        case S_IFSOCK:printf("s");break;
        default:printf("unkownfile");break;
    }
    for(int i = 8;i >= 0;i--)
    {
        if(buf.st_mode & (1<<i))
        {
            switch(i%3)
            {
                case 2:printf("r");break;
                case 1:printf("w");break;
                case 0:printf("x");break;
            }
        }
        else
        {
            printf("-");
        }
    }
    printf(" %ld",buf.st_nlink);//show number of link;
    struct passwd *uid;
    struct group *gid;
    gid = getgrgid(buf.st_gid);
    uid = getpwuid(buf.st_uid);
    printf(" %s",uid->pw_name);
    printf(" %s",gid->gr_name);
    int size = (int)buf.st_size;//print size of file
    printf(" %5d",size);
    
    tm = localtime(&buf.st_mtime);//print time and filename
    printf("%2d月%4d %02d:%02d %s",tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,name);
    printf("\n");
}
return 0;
}

10、静态库和动态库制作

静态库
第一步–>要gcc -c x.c得到材料
第二步–> arc crs libx.a x.o
第三步–> gcc text.c -lx -L指定路径
动态库
第一步–>gcc -fPIC -c x.c
第二步–>gcc -share -o libx.so x.o
第三步–>gcc text.c -lx -L指定路径

11、printf宏定义调试

#define LINK		//这是方法一
#ifdef LINK
#define Debug(info) printf(info)
#else
#define Debug(info)
#endif
				//方法二:在编译时gcc -DLINK 生成一个全局的宏定义

练习 解析txt文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
	char buf[36] = {0};
	char name[20] = {0};
	int flag = 1;
	gets(name);
	FILE *fp = fopen("1.txt","r");
	while(!feof(fp))
	{
		memset(buf,sizeof(buf),0);
		fgets(buf,sizeof(buf),fp);
		if(strcmp(name,strtok(buf,"=")) == 0)
		{
			flag = 0;
			printf("%s\n",strtok(NULL,"\0"));
		}
			
	}
	fclose(fp);
	return 0;
}

练习 利用hash提高查询速度

//首先讲解一下hash查找,就是根据键值hash[key][data],存放数据,先确定一个数组大小,一般数据数量/0.75;然后%得到的值;
//这个时候就可以提高查找效率到常数级;
## hash.h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值