C语言-文件IO

news/2024/10/21 10:02:52/

文件IO

I :input 输入,从文件中读取数据到内存

O:output 输出,把数据写入到文件

Linux系统IO 和 c语言标准IO

1、linux系统IO

1.1 简介

linux操作系统把对文件的操作封装成了多个函数,统称为linux系统IO。

文件描述符(File descirptor) 是一个用来访问文件的抽象化概念

文件描述符是一个正整数(进程文件表项下标),一个被打开的文件对应着一个文件描述符

linux中,每个进程(暂时理解程序)都会自动打开3个文件:

功能                                                                            文件描述符           对应的宏

标准输入文件 从输入设备(鼠标,键盘等)中获取数据     0                      STDIN_FILENO

标准输出文件 输出数据到输出设备(屏幕等)                   1                      STDOUT_FILENO

标准出错文件 输出错误信息到输出设备(屏幕等)            2                      STDERR_FILENO

这个宏定义在头文件 /usr/include/unistd.h

/* Standard file descriptors. /

#define STDIN_FILENO 0 / Standard input. /

#define STDOUT_FILENO 1 / Standard output. /

#define STDERR_FILENO 2 / Standard error output. */

1.2 如何学习系统函数

ubuntu中,把所有系统函数都做了说明手册,我们需要学会去查询这个手册

man -f 标识符 //查询该标识符在手册中的所有功能简介

以 strcpy,printf为例

man 数字 标识符 //进入到对应手册

比如:

man printf //如果该标识符有多页,不加数字默认进入最前面那页

man 1 printf //进入printf手册第一页

man 3 printf //进入printf手册第三页

man strcpy

man 3 strcpy

可以安装中文手册

sudo apt install manpages-zh //安装

sudo apt remove manpages-zh //卸载

直接百度

1.3 具体函数

1.3.1 打开文件

   #include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>//使用open函数,需要包含这三个头文件int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);//为什么有两个open函数,不会重复定义吗?//一个是用宏函数实现的,一个是普通函数pathname :文件的路径名(包含路径的文件名)flags:打开该文件的方式,有很多种O_RDONLY, O_WRONLY 或 O_RDWR  必选项,三选一(只读 read only   只写write only  读写 read write)以下是可选项,0项或多项,和上面的标识用 | 连接O_CREAT:如果文件不存在,则先创建,如果文件存在则直接打开O_EXCL:该标识一般和 O_CREAT配合使用,如果文件存在,则报错O_TRUNC:如果文件存在且是普通文件,并且有可写权限,那么打开文件时会把文件的内容清空O_APPEND:追加方式打开。如果没有该标志,打开文件后,读写指针(光标)在文件开头;如果有该标志读写指针(光标)在文件末尾。O_NONBLOCK 或 O_NDELAY :以非阻塞的方式打开阻塞(默认方式)打开的话,该文件中如果没有内容,你去read,read函数会阻塞/等待,直到文件中有内容非阻塞打开的话,该文件中如果没有内容,你去read,直接返回0,不会等待注意:  普通文件没有阻塞效果,只有特殊文件(如:设备文件,管道文件...)才有mode:该参数只有在第二个参数有 O_CREAT 标志时才有效用来指定创建文件后文件的权限,有两种指定方式:(1)用宏指定S_IRWXU00700 允许 文件 的 属主 读 , 写 和 执行 文件S_IRUSR (S_IREAD)00400 允许 文件 的 属主 读 文件.....(2)用八进制数字指定0777    // 111 111 1110764    // 111 110 100....返回值:失败了返回-1,同时errno被设置成功返回文件描述符(可以打开目录,因为目录也是文件,只是只能以只读的方式打开目录)errno是系统中定义的一个全局变量,是一个整数,不同的值表示不同的系统错误,一般叫做错误码,当发生某个系统错误时,系统自动把errno设置为对应的错误码,并且提供了相关函数来解析这个错误码:perror  strerrorprintf("打开%s失败:%s\n","3.txt",strerror(errno));perror("打开失败");

1.3.2 关闭文件

#include <unistd.h>
int close(int fd);fd:要关闭的那个文件描述符
返回值:失败返回-1,同时errno被设置成功返回0任何一个文件打开,操作完之后,必须要关闭。

1.3.3 读取文件内容

   #include <unistd.h>ssize_t read(int fd, void *buf, size_t count);从文件描述符 fd 中读取 count 字节的数据并放入从 buf 开始的缓冲区中.fd:文件描述符buf:用来保存读取到的数据的内存首地址count:要读取的字节数返回值:失败返回-1,同时errno被设置成功返回实际读取到的字节数(返回0表示没有内容可读,一般是表示到了文件末尾了)

​ read函数进行读取,是从文件当前光标所在位置开始读的, ​ 读取成功之后,光标自动往后偏移。 ​ ​ 示例代码: ​

         01测试代码.c 中的 test1函数和test2函数

1.3.4 往文件写入数据

   #include <unistd.h>ssize_t write(int fd, const void *buf, size_t count);fd:文件描述符buf:要写入的数据的首地址count:要写入的字节数返回值:失败返回-1,同时errno被设置成功返回实际写入的字节数write函数进行写入,从光标位置开始写入,写入成功后,光标自动往后偏移示例代码:01测试代码.c 中的 test3函数
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
void test1()
{int fd ;fd = open("/mnt/hgfs/CS2415F/2阶段/1.txt",O_RDWR );if(fd == -1){//printf("打开失败\n");printf("打开%s失败:%s\n","1.txt",strerror(errno));perror("打开失败");return;}char buf[100];//因为是文本文件,文件中的内容是字符串,所以读到的内容需要用字符数组来保存int r = read(fd,buf,20);//从打开的文件中读取20字节保存到buf数组中if(r == -1){printf("读取失败:%s\n",strerror(errno));close(fd);return ;}buf[r] = '\0';printf("%s\n",buf);close(fd);
}void test2()
{int fd;fd = open("/mnt/hgfs/CS2415F/交叉开发/1_gcc和gdb/code/main.o",O_RDONLY);if(fd == -1){//printf("打开失败\n");printf("打开%s失败:%s\n","main.o",strerror(errno));return;}short data;//因为main.o是二进制文件,每2个字节为一个单位(整数),所以定义短整型变量来保存读取到的数据int r = read(fd,&data,2);if(r == -1){printf("读取失败:%s\n",strerror(errno));close(fd);return ;}printf("0x%hx\n",data);r = read(fd,&data,2);printf("0x%hx\n",data);close(fd);
}void test3()
{int fd ;fd = open("/mnt/hgfs/CS2415F/2阶段/1.txt",O_RDWR | O_APPEND);//if(fd == -1)if(-1 == fd){//printf("打开失败\n");printf("打开%s失败:%s\n","1.txt",strerror(errno));perror("打开失败");return;}char buf[100];scanf("%s",buf);//从键盘输入数据//把从键盘输入的数据保存/写入到文件中int r = write(fd,buf,strlen(buf));//if(r == -1)if(-1 == r){printf("写入失败:%s\n",strerror(errno));}close(fd);
}int main()
{//test1();//test2();test3();return 0;
}

1.3.5 定位光标

   #include <sys/types.h>#include <unistd.h>off_t lseek(int fd, off_t offset, int whence);fd:文件描述符offset:偏移量,以字节为单位,正数往后偏移,负数往前偏移whence:偏移方式SEEK_SET    以文件开头位置为基准  SEEK_CUR    以当前光标位置为基准  SEEK_END    以文件末尾位置为基准  如:lseek(fd,10,SEEK_SET);//把光标定位到据文件开头10字节处lseek(fd,0,SEEK_SET);//把光标定位到文件开头处lseek(fd,0,SEEK_END);//把光标定位到文件末尾处lseek(fd,5,SEEK_CUR);//把光标从当前位置往后移5字节返回值:失败返回-1,同时errno被设置成功返回新光标距离文件开头的字节数

1.3.6 获取文件属性

这个结构体用来描述文件的属性/状态struct stat {dev_t     st_dev;         /* ID of device containing file */文件的设备号ino_t     st_ino;         /* Inode number */Inode 号mode_t    st_mode;        /* File type and mode */   文件的类型及权限,详细介绍在下面nlink_t   st_nlink;       /* Number of hard links */硬链接的数目uid_t     st_uid;         /* User ID of owner */用户IDgid_t     st_gid;         /* Group ID of owner */组用户IDdev_t     st_rdev;        /* Device ID (if special file) */设备号off_t     st_size;        /* Total size, in bytes */文件大小blksize_t st_blksize;     /* Block size for filesystem I/O */块大小,一般来说一块是512字节blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */有多少块struct timespec st_atim;  /* Time of last access */最后访问文件的时间struct timespec st_mtim;  /* Time of last modification */最后修改文件内容的时间struct timespec st_ctim;  /* Time of last status change */最后修改文件状态的时间#define st_atime st_atim.tv_sec      /* Backward compatibility */#define st_mtime st_mtim.tv_sec#define st_ctime st_ctim.tv_sec};st_mode成员详细介绍该成员用来描述文件的类型及文件的权限strucr stat sb;//假设sb已经保存了某个文件的属性,那么下面代码就是用来判断该文件是什么类型的文件switch (sb.st_mode & S_IFMT) {case S_IFBLK:  printf("block device\n");            break;//块设备case S_IFCHR:  printf("character device\n");        break;//字符设备case S_IFDIR:  printf("directory\n");               break;//目录case S_IFIFO:  printf("FIFO/pipe\n");               break;//管道文件case S_IFLNK:  printf("symlink\n");                 break;//符号链接/软链接文件case S_IFREG:  printf("regular file\n");            break;//普通文件case S_IFSOCK: printf("socket\n");                  break;//套接字文件default:       printf("unknown?\n");                break;}
​下面的代码就是判断该文件的权限:if(sb.st_mode & S_IRUSR){//条件成立,说明该文件用用户可读权限}if(sb.st_mode & S_IWUSR){//条件成立,说明该文件用用户可写权限}......详细代码可以参考 man 2 stat #include <sys/types.h>#include <sys/stat.h>#include <unistd.h>
​int stat(const char *pathname, struct stat *statbuf);pathname:文件路径名statbuf:一个结构体变量的地址,stat函数执行成功后,该结构体就保存了文件的属性信息返回值:失败返回-1,同时errno被设置成功返回0int fstat(int fd, struct stat *statbuf);和 stat函数功能完全一样,区别在于第一个参数是文件描述符int lstat(const char *pathname, struct stat *statbuf);和 stat函数功能基本一样,区别在于如果 pathname 文件为软链接文件时,lstat获取的是软链接文件本身的属性信息stat获取的是软链接指向的源文件的属性信息
​示例代码:02测试代码.c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
int main()
{//先定义 struct stat 结构体变量,用来保存文件的属性信息struct stat st;//调用 stat函数获取文件属性信息,并保存在 st中int r = stat("/home/china/1",&st);if(r == 0){printf("文件大小:%ld\n",st.st_size);switch (st.st_mode & S_IFMT) {case S_IFBLK:  printf("block device\n");            break;//块设备case S_IFCHR:  printf("character device\n");        break;//字符设备case S_IFDIR:  printf("directory\n");               break;//目录case S_IFIFO:  printf("FIFO/pipe\n");               break;//管道文件case S_IFLNK:  printf("symlink\n");                 break;//符号链接/软链接文件case S_IFREG:  printf("regular file\n");            break;//普通文件case S_IFSOCK: printf("socket\n");                  break;//套接字文件default:       printf("unknown?\n");                break;}printf("最后修改文件内容的时间:%s\n",ctime(&(st.st_mtime)));}return 0;
}

1.3.7 目录操作

   (1)打开目录#include <sys/types.h>#include <dirent.h>DIR *opendir(const char *name);name:目录的路径DIR *fdopendir(int fd);fd:目录的文件描述符(先用 open 打开,返回文件描述符,再用 opendir打开)返回值:失败返回 NULL成功返回 DIR指针( 不需要关心DIR具体是什么,只需要知道后续对目录的操作要用到它)(2)读取目录#include <dirent.h>struct dirent *readdir(DIR *dirp);dirp:opendir的返回值目录中的内容(包括文件和子目录)有多少项是不固定的,readdir每次只读一项,需要循环调用readdir进行读取,直到返回NULL(表示读取完毕)返回值:成功返回 struct dirent 结构体指针struct dirent {ino_t          d_ino;       /* Inode number */off_t          d_off;       /* Not an offset; see below */unsigned short d_reclen;    /* Length of this record */unsigned char  d_type;      /* Type of file; not supportedby all filesystem types */char           d_name[256]; /* Null-terminated filename */};其中最重要的就是 d_name,就是读取到的 子目录名字或者文件名The  only  fields  in the dirent structure that are mandated by POSIX.1are d_name and d_ino.  The other fields  are  unstandardized,  and  notpresent on all systems; see NOTES below for some further details.只有 d_name 和 d_ino 是所有linux系统中都支持的成员,其他成员并不是所有系统中都存在。为了代码有更好的兼容性,建议尽量不要使用其他成员。(3)关闭目录#include <sys/types.h>#include <dirent.h>int closedir(DIR *dirp);(4)创建目录int mkdir(const char *pathname, mode_t mode);示例代码:04目录操作.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
//name:目录的路径名
int get_dir_num(const char *name)
{DIR * pdir = opendir(name);if(NULL == pdir){printf("打开%s目录失败,%s\n",name,strerror(errno));return -1;}int count = 0;struct dirent * p;struct stat st;int r;char pathname[100];while(1){p = readdir(pdir);if(NULL == p)//读取完毕,跳出循环{break;}//printf("%s\n",p->d_name);//可以发现,包含两个特殊目录:  .  ..if(strcmp(p->d_name,".")==0 || strcmp(p->d_name,"..")==0)continue;//if(p->d_type == DT_REG)//count++;strcpy(pathname,name);strcat(pathname,"/");strcat(pathname,p->d_name);//printf("%s\n",pathname);r = stat(pathname,&st);if(-1 == r){perror("");}if((st.st_mode & S_IFMT) == S_IFREG){count++;}else if((st.st_mode & S_IFMT) == S_IFDIR)//是子目录{count += get_dir_num(pathname);}}closedir(pdir);return count;
}int main(int argc,char *argv[])
{if(argc != 2){printf("输入有误,需要一个参数,指定目录\n");return -1;}int n = get_dir_num(argv[1]);//...//send(......);//write(......);printf("有%d个普通文件\n",n);return 0;
}

1.3.8 其他函数

	truncateint truncate(const char *path, off_t length);缩短/扩大 path文件 至 指定 length 长度unlinkint unlink(const char *pathname);删除指定文件mkdir 创建目录rmdir 删除空目录remove	删除普通文件或者目录chdir	改变工作路径,工作路径默认是运行程序的那个路径,程序中的相对路径都是相对工作路径而言的int chdir(const char *path);

2、c语言标准IO

2.1 简介

系统IO是操作系统提供的函数,不同的操作系统提供的函数不一样。

而C语言标准IO是c语言标准库提供的,只要你用c语言进行开发,不管在什么系统中都可以使用。

c语言标准IO,用struct FILE类型来表示一个被打开的文件

三个特殊的 FILE 指针

/* Standard streams.  */
extern struct FILE  *stdin;		/* Standard input stream.  */
extern struct FILE  *stdout;		/* Standard output stream.  */
extern struct FILE  *stderr;		/* Standard error output stream.  */stream 流
IO流  文件流		有缓冲区

参考 05测试代码.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
void test1()
{int fd = open("../1.txt",O_WRONLY);if(-1 == fd){perror("");return ;}int i;for(i=0;i<5;i++){write(fd,"1\n",2);sleep(2);}close(fd);
}void test2()
{FILE * fp = fopen("../1.txt","w");//...if(NULL == fp){perror("");return ;}int i;for(i=0;i<5;i++){fwrite("1\n",1,2,fp);sleep(2);}fclose(fp);
}int main()
{//test1();test2();return 0;
}

标准IO中在合适的时机把缓冲区中的数据写入到文件中,合适的时机??

全缓冲:当缓冲区满了之后或者程序正常结束或者关闭文件才会写入到文件中。比如 fwrite

行缓冲:遇到‘\n’或者程序正常结束才会写入到文件中 ,比如 printf

注意,用 printf调试段错误时一定要换行

无缓冲:没有缓存直接输出,比如 stderr文件流, perror函数

2.2 文件操作相关函数

2.2.1 打开文件

   #include <stdio.h>FILE *fopen(const char *path, const char *mode);path :要打开的文件的路径名mode :打开方式,字符串r      打开文本文件,用于读。流被定位于文件的开始。r+     打开文本文件,用于读写。流被定位于文件的开始。w      将文件长度截短为零(清空),或者创建文本文件,用于写。流被定位于文件的开始。w+     打开文件,用于读写。如果文件不存在就创建它,否则将清空它。流被定位于文件的开始。a      打开文件,用于追加 (在文件尾写)。如果文件不存在就创建它。流被定位于文件的末尾。a+     打开文件,用于追加 (在文件尾写)。如果文件不存在就创建它。读文件的初始位置是文件的开始,但是写入总是被追加到文件的末尾。	返回值:失败返回NULL,同时errno被设置成功返回被打开文件的 FILE指针FILE *fdopen(int fd, const char *mode);fd:文件描述符。先open,再fopenmode:和fopen一样返回值:和fopen一样

2.2.2 关闭文件

   #include <stdio.h>int fclose(FILE *stream);stream :fopen的返回值返回值:失败返回-1,同时errno被设置成功返回0

2.2.3 读取文件内容

   #include <stdio.h>size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);读取文本文本和二进制文件,并且想读多个字节都可以ptr:用来保存读取到的数据的内存首地址size:要读取的内容中单个元素的大小nmemb:要读取的内容中元素的个数读取的总字节数是 size*nmembstream:指定从哪个文件中读取返回值:失败返回-1,同时errno被设置成功返回实际读到的元素个数

  读取文本文件中的一个字符 	getc/getchar/fgetcint getchar(void);从标准输入文件流(stdin)中读取一个字符返回值:失败返回-1成功返回该字符的 ascii码int fgetc(FILE *stream);int getc(FILE *stream);从stream指定的文件中读取一个字符返回值:失败返回-1成功返回该字符的 ascii码
	读取文本文件中的一行字符char *gets(char *s);//容易越界,不建议使用char *fgets(char *s, int size, FILE *stream);s:用来保存字符串的那块内存的首地址size:表示最多读 size-1个字节(最后一个字节给'\0')。一般来说,传入s指向的那块内存的大小,可以防止越界如果在size-1个字节前遇到换行符,也会结束stream:指定从哪个文件中读取返回值:失败返回-1,同时errno被设置成功返回字符串首地址(其实就是s)

2.2.4 往文件中写入数据

   size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);ptr: 要写入的数据的首地址size:要写入的内容中单个元素的大小nmemb:要写入的内容中元素的个数stream:指定写入到哪个文件中返回值:失败返回-1,同时errno被设置成功返回实际写入的元素个数
	往文件中写入一个字符int putchar(int c);//把字符c写入标准输出流 stdout ,效果就是输出字符cc:要写入的字符失败返回-1成功返回cint putc(int c, FILE *stream);int fputc(int c, FILE *stream);c:要写入的字符stream:指定写入到哪个文件流失败返回-1成功返回c
    往文件中写入一行字符int puts(const char *s);//写入到stdout,自动加一个 '\n'int fputs(const char *s, FILE *stream);//输出到指定文件,不会加'\n'

2.2.5 定位光标

   #include <stdio.h>int fseek(FILE *stream, long offset, int whence);stream:指定文件流offset:偏移量,以字节为单位,正数往后偏移,负数往前偏移whence:偏移方式SEEK_SET	以文件开头位置为基准	SEEK_CUR	以当前光标位置为基准	SEEK_END	以文件末尾位置为基准	返回值:失败返回-1,同时errno被设置成功返回0long ftell(FILE *stream);返回 stream文件中光标距离文件的位置
练习:
(1)实现复制目录的函数把 src目录里面的所有文件都复制到 dest目录中,并且要保持文件的层次关系不变void copy_dir(const char *src,const char *dest){}//需要用到 mkdir函数
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
int copy_file(const char *src,const char *dest)
{// 打开两个文件int src_fd = open(src,O_RDONLY);if(-1 == src_fd){printf("打开源文件%s失败,%s\n",src,strerror(errno));return -1;}int dest_fd = open(dest,O_WRONLY | O_CREAT | O_TRUNC,0664);if(-1 == dest_fd){printf("打开目标文件%s失败,%s\n",dest,strerror(errno));close(src_fd);return -1;}//进行文件内容复制char buf[100];int r ;while(1){r = read(src_fd,buf,100);if(0 == r)break;//读取完毕write(dest_fd,buf,r);}//关闭文件close(src_fd);close(dest_fd);return 0;
}/*功能:复制目录,把 src目录里面的所有文件(包括子目录)全部复制到 dest目录中失败返回-1,成功返回0
*/
int copy_dir(const char *src,const char *dest)
{int r = mkdir(dest,0777);//创建目的目录,如果目录已经存在, mkdir会失败//但是这种情况并不影响我们后续的操作,所有不需要结束函数//如果是其他原因导致的创建失败,那就需要结束函数if(-1 == r && errno != EEXIST){printf("创建%s目录失败:%s\n",dest,strerror(errno));return -1;}DIR * psrc = opendir(src);if(NULL == psrc){printf("打开%s文件失败:%s\n",src,strerror(errno));return -1;}DIR * pdest = opendir(dest);if(NULL == pdest){printf("打开%s文件失败:%s\n",dest,strerror(errno));closedir(psrc);return -1;}struct dirent * p;//char srcpathname[100]; //可能会越界,最好是动态分配//char destpathname[100]; int srclen;int destlen;char * srcpathname;char * destpathname;struct stat st;//用来保存获取到的文件属性信息while(1)//一项一项读取目录{p = readdir(psrc);if(NULL == p)//返回NULL,代表目录读取完毕break;//printf("%s\n",p->d_name);//可以发现,包含两个特殊目录:  .  ..if(strcmp(p->d_name,".")==0 || strcmp(p->d_name,"..")==0)continue;//连接原目录及该目录中的文件,组成一个完整的路径名srclen = strlen(src) + 1 + strlen(p->d_name) + 1;srcpathname = (char *)malloc(srclen);strcpy(srcpathname,src);strcat(srcpathname,"/");strcat(srcpathname,p->d_name);printf("%s\n",srcpathname);r = stat(srcpathname,&st);if(-1 == r){perror("");continue;}destlen = strlen(dest) + 1 + strlen(p->d_name) + 1;destpathname = (char *)malloc(destlen);strcpy(destpathname,dest);strcat(destpathname,"/");strcat(destpathname,p->d_name);printf("%s\n",destpathname);if((st.st_mode & S_IFMT) == S_IFREG)//srcpathname是普通文件,进行复制{r = copy_file(srcpathname,destpathname);if(-1 == r)//该文件复制失败{printf("%s文件复制失败\n",srcpathname);}}else if((st.st_mode & S_IFMT) == S_IFDIR)//是子目录{//递归调用自己copy_dir(srcpathname,destpathname);}free(srcpathname);free(destpathname);}//原目录  /mnt/hgfs/mnt/hgfs/CS2415F/2阶段// /mnt/hgfs/mnt/hgfs/CS2415F/2阶段/1文件IO
//目录目录  /home/china/test//  /home/china/test/1文件IOclosedir(psrc);closedir(pdest);return 0;
}int main(int argc,char *argv[])
{if(argc != 3){printf("输入有误,需要带两个参数,原目录路径和目的目录路径\n");return -1;}int r = copy_dir(argv[1],argv[2]);if(-1 == r){printf("复制失败\n");}else{printf("复制成功\n");}return 0;
}

2.2.6 格式化输出

按照指定的格式进行输出

   #include <stdio.h>int printf(const char *format, ...);format:用于指定输出格式这个参数是一个字符串,字符串的内容分为三类字符(1)普通字符,原样输出(2)以\开头的转义字符,如: \n  \0  \t \r .....  如果想输出 \ 字符本身,  \\(3)以%开头的特色字符,如: %d %ld %x %hd %f %lf %s ... 会用后面的参数的值来替换它... :表示后面的参数个数集和类型是不确定的,根据你的实际情况写,后面的参数个数要和第一个参数中 % 开头的特色字符个数相同,类型要匹配返回值:失败返回-1,成功返回实际输出的字符个数例如:int a = 10;float b = 1.5;char c = 'X';printf("a=%d,b=%f,c=%c\n",a,b,c);输出 a=10,b=1.5,c=Xa=  ,  b= , c= 这些都是普通字符,原样输出, %d %f %c 由后面的参数的值替换输出\n 有换行的效果int fprintf(FILE *stream, const char *format, ...);该函数比 printf多了一个参数 stream,指定文件流printf固定向 STDOUT_FILENO文件流中输出而 fprintf可以指定向某个文件流中输出后面的参数和 printf完全一样如:FILE * fp = fopen("./1.txt","w+");fprintf(fp,"a=%d,b=%f,c=%c\n",a,b,c);//输出a=10,b=1.5,c=X\n到 1.txt文件中int dprintf(int fd, const char *format, ...);和 fprintf功能一样,输出到指定文件中,只不过是用 文件描述符来指定int sprintf(char *str, const char *format, ...);该函数比 printf多了一个参数 str,它是一块内存的首地址,该函数的功能不是输出到文件流中,而是保存到内存中。示例代码:之前有这3行代码,用来连接字符串,保存到 pathname数组中strcpy(pathname,name);strcat(pathname,"/");strcat(pathname,p->d_name);->sprintf(pathname,"%s/%s",name,p->d_name);int snprintf(char *str, size_t size, const char *format, ...);在 sprintf函数的基础上,增加了一个参数 size,用来指定 str内存的大小,防止越界

2.2.7 格式化输入

按照指定的格式进行输入

   #include <stdio.h>int scanf(const char *format, ...);format:指定输入格式,是一个字符串,字符串中有3类字符串(1)普通字符,原样输入int data;scanf("请输入:%d",&data);//单纯从语句的角度,没有错//输入:100   错误//输入:请输入:100    正确    因为 "请输入:" 这些字符就是普通字符,需要原样输入int a,b;scanf("%d%d",&a,&b);//输入:10 20  错误//输入:10,20  正确因为","是普通字符,需要原样输入(2) 空白符空格 tab  \n 等也要输入空白符(3) 以%开头的特色字符如: %d %ld %x %hd %f %lf %s ...  分别对应要输入不同类型的数据... 后面的参数个数及类型根据第一个参数中 %开头的特色字符决定的类型都是地址/指针返回值:返回正确匹配的变量数目(%开头的特色字符数目)int fscanf(FILE *stream, const char *format, ...);fscanf相比 scanf多了一个参数 stream, scanf只能从标准输入文件流中获取数据,而 fscanf可以从指定的文件流中获取数据int sscanf(const char *str, const char *format, ...);sscanf相比 scanf多了一个参数 str, scanf只能从标准输入文件流中获取数据,而 sscanf可以从指定的内存中获取数据char buf[] = "18 2.4 x dkljldk";r = sscanf(buf,"%d %f %c",&a,&b,&c);printf("r=%d,a=%d,b=%f,c=%c\n",r,a,b,c);

http://www.ppmy.cn/news/1538675.html

相关文章

ResNet模型

使用pytoch实现 1.卷积神经网络 conv2d的参数很简单 conv2d(input_channels, output_channels,kernel_size, stride, padding) 参数分别是输入通道&#xff0c;输出通道&#xff0c;卷积核大小&#xff0c;移动步长&#xff0c;填充数量。 输入通道是特征图的深度&#xff0c…

【详细教程】如何使用YOLOv11进行图像与视频的目标检测

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

MySQL 8.4修改初始化后的默认密码

MySQL 8.4修改初始化后的默认密码 &#xff08;1&#xff09;初始化mysql&#xff1a; mysqld --initialize --console &#xff08;2&#xff09;之后,mysql会生成一个默认复杂的密码&#xff0c;如果打算修改这个密码&#xff0c;可以先用旧密码登录&#xff1a; mysql -u…

vite 打包前请求接口和打包后的不一致

在使用 Vite 进行项目打包时&#xff0c;如果发现打包前请求接口和打包后的行为不一致&#xff0c;这可能是由于多种原因导致的。以下是一些可能的原因和相应的解决方案&#xff1a; 1. 代理配置问题 开发环境&#xff1a;在开发环境中&#xff0c;Vite 通常使用 vite.config…

处理Java内存溢出问题(java.lang.OutOfMemoryError):增加JVM堆内存与调优

处理Java内存溢出问题&#xff08;java.lang.OutOfMemoryError&#xff09;&#xff1a;增加JVM堆内存与调优 在进行压力测试时&#xff0c;遇到java.lang.OutOfMemoryError: Java heap space错误或者nginx报错no live upstreams while connecting to upstream通常意味着应用的…

JAVA学习-练习试用Java实现“Excel表列序号”

问题&#xff1a; 给定一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回该列名称对应的列序号。 例如&#xff0c; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 示例 1: 输入: columnTitle "A" 输出: 1 示例…

Guitar Pro怎么制作伴奏谱,吉他谱制作软件guitar pro教程

在诸多教学吉他谱制作软件中Guitar Pro是一款非常优秀的软件&#xff0c;它是专为吉他和其他弦乐器设计&#xff0c;且能提供乐谱编辑、音轨录制和播放、和弦与音阶库等功能的强大软件。Guitar Pro不仅具有强大的乐谱编辑功能&#xff0c;其用户界面也易于上手&#xff0c;更支…

web1.0,web2.0,web3.0 有什么区别 详解

Web 的发展经历了多个阶段&#xff0c;每个阶段都有其独特的特点和技术进步。下面是 Web 1.0、Web 2.0 和 Web 3.0 之间的主要区别和详细解释&#xff1a; Web 1.0 时间范围&#xff1a;大约在 1991 年至 1995 年。 Web 1.0 是互联网的最初形态&#xff0c;也被称为静态 Web…