标准IO、目录IO

一、printf函数输出问题。
1.printf函数的对象是谁?
printf()功能就是输出一个字符串到屏幕上,屏幕对象有两个,分别是标准输出、标准出错。
printf()其对象就是标准输出。

2.标准输出与标准出错有什么区别?
标准输出是有缓冲区的,其内容是先放在缓冲区,再输出。
标准出错是没有缓冲区的,其内容是直接输出。

3.研究一下printf()的输出问题。
例子1: 
int main(int argc,char *argv[])
{
    printf("helloworld");
    printf("appletree");
    while(1);
    return 0;
}

执行结果:不会输出任何的内容,然后卡在死循环中。
分析: 因为printf函数是一个行缓冲区函数,所以必须要在标准输出缓冲区中遇到'\n'就可以输出东西。

例子2:
int main(int argc,char *argv[])
{
    printf("helloworld");
    printf("appletree\n");
    printf("yueqian");
    while(1);
    return 0;
}

执行结果:输出helloworld和appletree,但是yueqian并没有输出。
分析:证明必须要遇到\n才可以将\n之前的全部东西输出。

例子3:
int main(int argc,char *argv[])
{
    printf("helloworld");
    printf("appletree");
    return 0;
}

执行结果:输出helloworldappletree
分析:程序退出时,会刷新标准输出缓冲区。


例子4:
int main(int argc,char *argv[])
{
    while(1)
    {
        printf("helloworld");
        usleep(100000);  //0.1s
    }
    return 0;
}

执行结果:等到缓冲区满了(1024B),就会将缓冲区中所有的数据全部输出。
分析:标准输出的缓冲区满了,即使没有'\n',程序也没有退出,也是会全部输出的。
   

例子5:
int main(int argc,char *argv[])
{
    int x;
    printf("helloworld");
    printf("appletree");
    scanf("%d",&x);
    while(1);
    return 0;
}

执行结果:输出helloworldappletree
分析:键盘输入的函数也会刷新printf的缓冲区。

例子6:主动刷新缓冲区   ---> fflush()  -->  man 3 fflush
功能: 刷新一个流。
fflush - flush a stream
#include <stdio.h>
int fflush(FILE *stream);
参数:
    stream: 文件指针    如果要刷新标准输出缓冲区,这里填stdout。
返回值:
    成功:0
    失败:-1

int main(int argc,char *argv[])
{
    printf("helloworld");
    printf("appletree");
    fflush(stdout);   ---> 主动刷新标准输出缓冲区
    while(1);
    return 0;
}

例子7: 将printf的输出对象修改为标准出错,你想输出什么东西,就会马上输出。
修改输出对象: fprintf()  --> man 3 fprintf
#include <stdio.h>

int fprintf(FILE *stream, const char *format, ...);
参数:
    stream: 输出对象的文件指针。  stderr
    format: 输出的内容。
返回值: 输出的字符个数
         return the number of characters printed

printf("hello");          --> 默认的对象是标准输出
fprintf(stdout,"hello");  --> 将hello放在标准输出的缓冲区中,等价于上面那句话。
fprintf(stderr,"hello");  --> 将hello直接存放在标准出错中,而标准出错没有缓冲区的,所以会直接输出。

-------------------------------
int main(int argc,char *argv[])
{
    //fprintf(stderr,"hello");
    fprintf(stdout,"hello");  //等价于printf("hello")
    while(1);
    
    return 0;
}
-------------------------------
二、标准IO函数。
格式输入:scanf() fscanf() sscanf()    
格式输出:printf() fprintf() sprintf()           <按指定格式读写文件>
字符输入:getchar()  getc()  fgetc()      <按字符读写文件> ---char
字符输出:putchar()  putc()  fputc()  
字符串输入:gets()  fgets()          <按行读写文件>----string
字符串输出:puts() fputs()

1.sprintf()    ---> (常用)保存一个字符串到一个缓冲区中,作用:拼接字符串。
#include <stdio.h>
int sprintf(char *str, const char *format, ...);
参数:
   str: 保存字符串的缓冲区的地址。  (注意:必须要足够大接受数据)
   format: 保存的内容。
返回值:
   保存的内容的字符串长度。
例子1:
   int a = 10;
   printf("a = %d\n",a);          //将a的值存放到%d的位置,然后将a=10这句话输出到标准输出缓冲区中。
例子2:
   int a = 10;
   fprintf(stderr,"a = %d\n",a);  //将a的值存放到%d的位置,然后将a=10这句话输出到标准出错中。
例子3:
   int a = 10;
   char buf[100] = {0};
   sprintf(buf,"a = %d\n",a);     //将a的值存放在%d的位置,然后将a=10这句话保存到buf这个数组中。
说明:
 sprintf 函数可以作为字符串拼接函数

练习1:
char buf1[] = "guoqing"
char buf2[] = "shuangwaiwai"
char buf3[1024];
使用sprintf函数将buf1和buf2拼接到buf3中

#include <stdio.h>

int main(int argc,char **argv)
{
/* 	char buf1[] = "guoqing";
	char buf2[] = "shuangwaiwai"; */
	char buf1[] = "国庆";
	char buf2[] = "爽歪歪";	
	char buf3[1024] = {0};	
	
	sprintf(buf3,"%s%s",buf1,buf2);

	printf("buf3:%s\n",buf3);
	
	return 0;
}

2.getchar()     --->  从标准输入缓冲区中获取一个字符。 作用:清空标准输入的缓冲区。(重点)
#include <stdio.h>
int getchar(void);
参数:无
返回值:
    成功:获取的字符
    失败:-1
注意:
每次scanf()之前,都最好先清空缓冲区。
while(getchar()!='\n');  //清空缓冲区
scanf();  //一定可以保证缓冲区是空的。

3.getc()   --->  从某一个文件指针中获取一个字符
#include <stdio.h>
int getc(FILE *stream);
参数:
   stream: 文件指针
返回值:
    成功:获取的字符
    失败:-1
 
说明:
1)getchar()   --> 固定从标准输入缓冲区获取,不能从别的地方获取。
2)getc(stdin)  等价于 getchar()  --> 指定从标准输入缓冲区中获取一个字符
FILE *fp = fopen("xxx","r");
getc(fp);                      --> 指定从xxx这个文件中获取一个字符。
------------------------------
#include <stdio.h>
int main()
{
    FILE *fp = fopen("1.txt","r");  //hello
    
    int c = getc(fp);
    printf("c = %d\n",c);
    printf("c = %c\n",c);
    
    c = getc(fp);
    printf("c = %d\n",c);
    printf("c = %c\n",c);
    
    fclose(fp);
    
    return 0;
}
---------------------------------
总结:
getc和getchar两个功能有重叠部分 getc() > getchar()
getc重复使用的时候,光标也在移动

4.fgetc()   等价于  getc()
两个参数一样
#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);

5.putchar()   -->  把某一个字符存放在标准输出的缓冲区中
#include <stdio.h>
int putchar(int c);
参数:
    c: 需要输出的字符
返回值:
    成功:写入的字符
    失败:-1
-------------------------
#include <stdio.h>

int main(int argc,char *argv[])
{
    int c = putchar('x');
    printf("c = %d\n",c);
    printf("c = %c\n",c);
    
    return 0;
}
--------------------------

6.putc()  ---> 将字符存放在文件指针中。
#include <stdio.h>
int putc(int c, FILE *stream);
参数:
    c: 需要输出的字符
    stream: 文件指针
返回值:
    成功:写入的字符
    失败:-1
----------------------------
#include <stdio.h>
int main(int argc,char *argv[])
{
    //putc('x',stdout);
    
    FILE *fp = fopen("2.txt","w");
    putc('x',fp);
    
    putc('k',fp);
    
    fclose(fp);
    
    return 0;
}
-----------------------------
总结:
putc和putchar两个功能有重叠部分 putc() > putchar() 
连续使用putc(),光标也会移动

7.fputc() 等价于 putc()
两个函数参数一样,返回值也一样
#include <stdio.h>
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);

8.gets()   -->  从标准输入缓冲区中获取一个字符串(不要用、危险)
#include <stdio.h>
char *gets(char *s);
参数:
        s: 缓冲区
返回值:
    成功:s的值
    失败:NULL

------------------------------
#include <stdio.h>
int main(int argc,char *argv[])
{
    char s[10] = {0};
    gets(s);    ---> 如果获取的字符超过10个,就会有问题。
    printf("s = %s\n",s);
    
    return 0;
}
说明:
gets()函数很危险,不要用。
/tmp/ccQKjzYm.o: In function `main':
gets.c:(.text+0x39): warning: the `gets' function is dangerous and should not be used.
-----------------------------

9.fgets()   --> 获取一个字符串
#include <stdio.h>
char *fgets(char *s, int size, FILE *stream);
参数:
    s: 缓冲区的地址
    size: 最多获取的字节数
    stream: 文件指针
返回值:
    成功:s的值
    失败:NULL
注意如下:
int main(int argc,char *argv[])
{
    FILE *fp = fopen("1.txt","r+");

    char buf[10] = {0};
    fgets(buf,6,fp);
    printf("buf:%s\n",buf);
    /*        
    buf:abcde
    说明:如果你想从文件里面拿出5个字节,你至少要拿6个;因为最后
    一个会自动补'\0'结束符。
    */
    return 0;
}
练习2:
用代码来验证fgets的功能

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

int main(int argc,char *argv[])
{
/* 	char buf[10] = {0};
	//等价于scanf,但是不同之处是fgets将‘\n’也会拿到buf中
	fgets(buf,sizeof(buf),stdin);
	printf("buf:%s strlen(buf)=%ld\n",buf,strlen(buf)); */
	
	FILE *fp = fopen("1.txt","r+");

	char buf[10] = {0};
	fgets(buf,6,fp);
	printf("buf:%s\n",buf);
			
/* 	buf:abcde
	说明:如果你想从文件里面拿出5个字节,你至少要拿6个;因为最后
	一个会自动补'\0'结束符。 */
	
	return 0;
}

10.puts()   ---> 输出一个字符串到标准输出中。
#include <stdio.h>
int puts(const char *s);
参数:
    s: 输出的字符串
返回值:
    成功:输出字符串的字符个数
    失败:-1

-------------------------
#include <stdio.h>
int main()
{
    char *s = "helloworld";
    puts(s);
    return 0;
}
-------------------------

11.fputs()  --->输出一个字符串到指定的文件指针中
#include <stdio.h>
int fputs(const char *s, FILE *stream);
参数:
    s: 缓冲区的地址
    stream: 文件指针
返回值:
    成功:非负数
    失败:负数

12.scanf() --->从标准输入里面按照指定格式获取数据
#include <stdio.h>
int scanf(const char *format, ...);
案例
int num;
scanf("%d",&num);

13.fscanf() --->从文件指针里面按照指定格式获取数据(重点:拆分字符串)
#include <stdio.h>
int fscanf(FILE *stream, const char *format, ...);
案例
FILE *fp = fopen("1.txt","r+");
char buf[1024];
fscanf(fp,“%s",buf)

练习3:
用fscanf将1.txt里面的字符串拆分 “aaa,bbb,ccc”
char buf1[]
char buf2[]
char buf3[]
//可以切割以逗号隔开的字符串
fscanf(fp,"%[^','],%[^','],%s",buf1,buf2,buf3); //OK

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

int main()
{
	FILE *fp = fopen("1.txt","r+");
	
/* 	char buf[1024] = {0};
	
	fscanf(fp,"%s",buf);
	
	printf("buf:%s\n",buf);
	 */
	
/* 	int num = 0;
	fscanf(fp,"%d",&num);
	printf("num:%d\n",num); */
	
	char buf1[1024] = {0};
	char buf2[1024] = {0};
	char buf3[1024] = {0};
	//fscanf(fp,"%s,%s,%s",buf1,buf2,buf3); //错误
	
	//可以切割以逗号隔开的字符串
	fscanf(fp,"%[^','],%[^','],%s",buf1,buf2,buf3); //OK
	
	//fscanf(fp,"%3s,%3s,%3s",buf1,buf2,buf3);//有局限性
	
	printf("buf1:%s buf2:%s buf3:%s\n",buf1,buf2,buf3);
	
	return 0;
}

14.sscanf --->从字符串里面按照指定格式获取数据(重点:拆分字符串)
#include <stdio.h>
int sscanf(const char *str, const char *format, ...);
案例1
char *str = "bling"
char name[20]={0};
sscanf(str,"%s",name);
案例2
char *str1 = "bling,zhangsan,lisi";
char buf1[1024] = {0};
char buf2[1024] = {0};
char buf3[1024] = {0};
sscanf(str1,"%[^','],%[^','],%s",buf1,buf2,buf3);//拆分字符串
printf("buf1:%s buf2:%s buf3:%s\n",buf1,buf2,buf3);

三、目录IO
1.为什么要学习目录IO接口?
目录可以存放一些文件/目录,如果学习目录IO操作,那么我们就可以通过目录的名字来将目录下的全部名字读取出来,方便后续的操作。
例如:usr_data/
bling.txt aaa.txt bbb.txt  --> 通过目录IO操作函数,就可以求出这些文件的名字。

2.访问文件与访问目录有什么区别?
访问文件  --> 得到文件里面的内容。
访问目录  --> 得到目录项的名字、属性、类型..

四、目录IO函数接口?
1.如何打开目录?  -->  opendir()  --> man 3 opendir
#include <sys/types.h>
#include <dirent.h>   //目录的专属头文件
DIR *opendir(const char *name);
参数:
    name: 需要打开的那个目录的路径
返回值:
    成功:目录流指针
    失败:NULL

问题:打开一个目录是不是意味着已经切换进去了?
答案:没有切换进去。

2.如何切换到目录中?  --> chdir()   --> man 3 chdir
问题:一定要切换到目录下,才能读取目录的东西吗?
答案:不一定,但是切换进去之后,该目录下所有的文件都是当前目录下的文件,访问这些文件就很方便。
#include <unistd.h>
 int chdir(const char *path);
参数:
  path:  需要切换的那个目录的路径。

返回值:
    成功:0
    失败:-1

3.如何读取目录下的内容?  -->  readdir()  --> man 3 readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
参数:
    dirp: 目录流指针
返回值:    
    成功:结构体指针
    失败:NULL    ---> 当读取目录完毕,就会返回NULL

说明:
每读取一个目录项,都会返回一个结构体指针,来代表这一个项的属性。
struct dirent{
               ino_t          d_ino;       //索引号
               off_t          d_off;       //偏移量
               unsigned short d_reclen;    //记录文件名长度
               unsigned char  d_type;      //文件类型
               char           d_name[256]; //文件名(重点掌握)
};

文件类型:
DT_BLK      This is a block device.      ---> 块设备文件     //6
DT_CHR      This is a character device.  ---> 字符设备文件   //2
DT_DIR      This is a directory.         ---> 目录文件       //4
DT_FIFO     This is a named pipe (FIFO). ---> 管道文件       //1
DT_LNK      This is a symbolic link.     ---> 链接文件       //10
DT_REG      This is a regular file.      ---> 普通文件       //8
DT_SOCK     This is a UNIX domain socket.---> 套接字文件     //12

文件名:最多可以设置256个字符。
练习:
读一次和循环读打印它的文件名

4.关闭文件。  --> closedir()  --> man 3 closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
参数:
    dirp:  目录流指针
返回值:
    成功:0
    失败:-1

5.重置目录指针。   ---> rewinddir()  --> man 3 rewinddir
#include <sys/types.h>
#include <dirent.h>
void rewinddir(DIR *dirp);
参数:
     dirp:  目录流指针
返回值:无

例子: 写代码,读取一个目录下的全部文件名出来。
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main()
{
    //1. 打开目录。
    DIR *dp = opendir("./bling_dir");
    if(dp == NULL)
        printf("opendir error!\n");
    
    //2. 切换到目录下。
    chdir("./bling_dir");
    
    //3. 不断去读取该目录下的文件名。
    struct dirent *ep = NULL;
    
    while(1)
    {
        ep = readdir(dp);
        if(ep == NULL)  //说明已经读取到最后一项了
        {
            break;
        }
        
        if(ep->d_name[0] == '.')  //如果文件名的第一个字符是.
        {
            continue;
        }
        
        printf("%s\n",ep->d_name);
    }
    
    //4. 关闭该目录。
    closedir(dp);
    
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值