文件基础-----C语言经典题目(10)
一.标准 io 和文件 io 有什么区别,分别在什么场景下使用?
标准 io 和文件 io 是两种不同的输入输出处理方式。
标准 I/O
特点:
基于流(Stream)的操作,使用缓冲机制,提高读写效率。
有printf、scanf、fgets、fputs等接口。
自动处理文本和二进制模式的差异。
跨平台兼容性好。
使用场景:
用户交互。
处理文本文件。
需要缓冲提高性能的场景。
不需要底层文件控制的场景。
int main()
{// 打开文件"test.txt",使用写入模式("w")// 如果文件不存在则创建,如果存在则清空内容FILE *fp = fopen("test.txt", "w");// 检查文件是否成功打开if (fp != NULL) {// 使用fprintf向文件流写入格式化字符串// 相当于printf,但输出目标是文件而非控制台fprintf(fp, "Hello, World!\n");// 关闭文件流,释放资源// 重要:避免内存泄漏和数据丢失fclose(fp);}return 0;
}
文件 I/O 系统调用
特点:
基于文件描述符(整数)的操作,直接调用操作系统的系统调用(open、read、write、close)。
无缓冲,每次操作直接与文件系统交互。
提供底层控制,如文件定位、权限设置等。
使用场景:
对性能要求极高的场景。
底层文件操作。(设备驱动)
处理二进制文件(多媒体数据)。
int main()
{// 打开文件"test.txt",使用以下标志:// O_WRONLY: 只写模式// O_CREAT: 如果文件不存在则创建// 0644: 文件权限(用户可读可写,组和其他用户可读)int fd = open("test.txt", O_WRONLY | O_CREAT, 0644);// 检查文件是否成功打开(返回值为文件描述符,-1表示失败)if (fd != -1) {const char *msg = "Hello, World!\n";// 写入数据到文件// 参数:文件描述符、数据指针、数据长度// 返回值:实际写入的字节数,-1表示错误write(fd, msg, strlen(msg));// 关闭文件描述符,释放资源// 重要:避免文件描述符泄漏close(fd);}return 0;
}
二.标准io 是否带有缓存机制,系统提供标准 io 的缓存机制有哪些,以及各自的特性?
标准 io库是带有缓存机制的,目的是减少系统调用的次数,提高程序的运行效率。
全缓冲:
当缓存区被填满或者执行刷新操作(调用fflush)时,才会进行实际的 io 操作,适用于对磁盘文件的操作。
特点:当缓冲区满或者调用 fflush、程序正常终止时,才会进行实际的读写操作。
默认情况:标准库通常会为磁盘文件设置大约 8kb 的缓冲区。
行缓冲:
当遇到换行符 \n 或者缓冲区被填满、执行刷新操作时,才会进行实际的 io 操作。
特点:标准io 默认采用行缓冲。
无缓冲:
所有的 io 操作都会立即执行,不会进行缓存。标准错误输出(stderr)通常使用这种缓冲机制,能保证错误详细能够及时显示出来。
缓冲类型设置方法:
可以使用 setvbuf 函数来设置流的缓冲类型,函数原型为:
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
其中,mode 的取值有:
_IOFBF:全缓冲。
_IOLBF:行缓冲。
_IONBF:无缓冲。
缓存刷新的触发条件:
1.缓冲区满,自动刷新缓存。
2.调用 fflush 函数可以强制刷新缓存。
3.程序正常终止时,会刷新所有缓存。
4.对于行缓冲,遇到换行符 \n 时会刷新缓存。
int main()
{// 将stdout设置为全缓冲setvbuf(stdout, NULL, _IOFBF, 1024);printf("This is fully buffered output."); // 不会立即显示// 将stdout设置为行缓冲setvbuf(stdout, NULL, _IOLBF, 1024);printf("This is line buffered output.\n"); // 遇到\n会显示// 将stdout设置为无缓冲setvbuf(stdout, NULL, _IONBF, 0);printf("This is unbuffered output."); // 立即显示return 0;
}
三.linux 中,文件的类型有哪些?
文件类型借助文件属性来划分,可以通过 stat 结构体以及相关宏定义对这些类型进行判断。
普通文件:
用于存储数据的文件,涵盖文本文件、二进制文件等。
可以通过 S_ISREG(mode)宏来判断。
目录文件:
用于存储文件系统的结构,包含其他文件和目录的相关信息。
用 S_ISDIR(mode)来判断。
字符设备文件:
代表着字符设备,比如终端、串口之类的。
用 S_ISCHR(mode)宏来判断。
块设备文件:
代表着块设备,比如硬盘、U 盘等
用 S_ISBLK(mode)来判断。
套接字文件:
用于进程间的网络通信
用 S_ISSOCK(mode)来判断。
符号链接文件:
是指向其他文件或目录的一种特殊文件
用 S_ISLNK(mode)来判断。
命名管道文件:
用于进程间的通信,
用 S_ISFIFO(mode)来判断。
判断文件类型:
int main(int argc, char *argv[])
{struct stat fileStat;// 检查命令行参数,确保用户提供了文件名if (argc != 2) {printf("Usage: %s <filename>\n", argv[0]);return 1;}// 获取文件状态信息// stat函数通过文件名获取文件的详细信息,存储在fileStat结构体中if (stat(argv[1], &fileStat) < 0) {perror("stat"); // 打印错误信息return 1;}// 输出文件的基本信息printf("文件类型信息:\n");printf("设备ID: %ld\n", (long)fileStat.st_dev); // 包含文件的设备IDprintf("inode: %ld\n", (long)fileStat.st_ino); // 文件的inode号// 使用宏判断文件类型并输出结果if (S_ISREG(fileStat.st_mode))printf("类型:普通文件\n");if (S_ISDIR(fileStat.st_mode))printf("类型:目录\n");if (S_ISCHR(fileStat.st_mode))printf("类型:字符设备文件\n");if (S_ISBLK(fileStat.st_mode))printf("类型:块设备文件\n");if (S_ISFIFO(fileStat.st_mode))printf("类型:命名管道文件\n");if (S_ISLNK(fileStat.st_mode))printf("类型:符号链接文件\n");if (S_ISSOCK(fileStat.st_mode))printf("类型:套接字文件\n");return 0;
}
四.linux 程序开发过程中,使用的 stdio.h 这个头文件在系统的哪个目录下可以找到?
stdio.h 头文件一般存于标准 C 库的头文件目录。
/usr/include :是系统默认的头文件搜索路径,在编译程序是,编译器会自动搜索该目录。
可以用以下命令来搜索:
find /usr/include -name "stdio.h"
# 或者使用 locate 命令(需要先执行 updatedb)
locate stdio.h
# 还可以通过 gcc 命令查看搜索路径
gcc -print-file-name=stdio.h
五.系统编程过程怎么查询手册?
一般就是使用 linux 系统的 man 命令。
基本用法:
man [章节号] 函数名/系统调用名
查询 open 函数:
man open
查询 read 函数的第 2 章节(系统调用):
man 2 read
手册章节说明:
1.用户命令(ls、grep)
2.系统调用(open、read)
3.库函数(printf、malloc)
4.设备文件和驱动
5.文件格式(/etc/passwd格式)
6.游戏和娱乐
7.杂项(宏、协议)
8.系统管理命令(mount、ifconfig)
六.标准 io 中 文件操作的操作方法有哪些?
1.文件打开与关闭
FILE *fopen(const char *filename,const char *mode):打开文件并返回文件指针,mode 参数指定打开模式(“r” 读,“w”写,“a”追加)。
int fclose(FILE *stream):关闭文件流,释放资源。
2.按字符读写
int fgetc(FILE *stream):从文件读取一个字符,返回 EOF 表示文件结束。
int fputc(int c,FILE *stream):向文件写入一个字符。
3.按行读写
char *fgets(char *s,int size,FILE *stream):读取一行(最多 size - 1字符)到字符串 s,自动添加 \0。
int fputs(const char *s,FILE *stream):向文件写入字符串(不自动添加换行符)。
4.格式化读写
int fprintf(FILE *stream,const char *format,......):格式化输出到文件,类似 printf。
int fscanf(FILE *stream,const char *format,......):从文件格式化输入,类似scanf。
int main()
{FILE *fp; // 定义文件指针,用于操作文件char buffer[100]; // 缓冲区,用于存储从文件读取的数据// 打开文件(写模式)// "w" 表示写入模式,如果文件不存在则创建,存在则清空内容fp = fopen("test.txt", "w");// 检查文件是否成功打开if (fp == NULL) {perror("无法打开文件"); // perror 输出系统错误信息return 1; // 返回非零值表示程序异常退出}// 写入数据到文件fprintf(fp, "Hello, World!\n"); // 格式化输出,类似 printffputs("This is a test file.\n", fp); // 写入字符串(不带换行符)fclose(fp); // 关闭文件,释放资源// 打开文件(读模式)// "r" 表示只读模式,文件必须存在fp = fopen("test.txt", "r");// 再次检查文件是否成功打开if (fp == NULL) {perror("无法打开文件");return 1;}// 读取文件内容并打印到控制台// fgets 返回 NULL 表示已到达文件末尾或发生错误while (fgets(buffer, sizeof(buffer), fp) != NULL) {printf("%s", buffer); // 打印读取的一行数据}fclose(fp); // 关闭文件return 0; // 返回 0 表示程序正常退出
}
七.文件 io 中文件操作的操作方法有哪些?
文件 io 操作主要依靠标准库(stdio.h)来实现。
1.文件打开与关闭
fopen():打开文件,返回一个 FILE 指针。
FILE *fopen(const char *filename, const char *mode);
// 示例
FILE *fp = fopen("example.txt", "r"); // 以只读模式打开文件
fclose():关闭文件,释放资源。
int fclose(FILE *stream);
// 示例
fclose(fp);
2.字符读写
fgetc() / getc():从文件中读取单个字符。
int fgetc(FILE *stream);
// 示例
int c = fgetc(fp);
fputc() / putc():从文件中写入单个字符。
int fputc(int c, FILE *stream);
// 示例
fputc('A', fp);
3.字符串读写
fgets():从文件读取一行字符串。
char *fgets(char *str, int n, FILE *stream);
// 示例
char buffer[100];
fgets(buffer, 100, fp);
fputs():向文件写入字符串。
int fputs(const char *str, FILE *stream);
// 示例
fputs("Hello, World!", fp);
4.格式化读写
fscanf():按格式从文件读取数据。
int fscanf(FILE *stream, const char *format, ...);
// 示例
int num;
fscanf(fp, "%d", &num);
fprintf():按格式向文件写入数据。
int fprintf(FILE *stream, const char *format, ...);
// 示例
fprintf(fp, "%d", 42);
5.二进制读写
fread():从文件读取二进制数据。
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
// 示例
int arr[10];
fread(arr, sizeof(int), 10, fp);
fwrite():向文件写入二进制数据。
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
// 示例
fwrite(arr, sizeof(int), 10, fp);
6.文件模式
“r”:只读,文件必须存在。
“w”:写入,若文件存在则清空,不存在则创建。
“a”:追加,在文件末尾添加内容。
“r+”:读写,文件必须存在。
“w+”:读写,若文件存在则清空,不存在则创建。
“a+”:读写,在文件末尾添加内容,可读取整个文件。
八.文件读写操作过程中,文本文件和二进制文件有什么区别?
存储形式:
文本文件:以 ASCII 码的形式来存储字符,每个字节代表一个字符,比如数字 1 2 3,就会被存成 3 个字节,分别对应字符 “1” (49)、 "2" (50) 、 "3"(51)。
二进制文件:数据按照在内存中的存储形式直接写入文件。比如一个 int 类型的数字 123在内存中占 4 个字节,就会原封不动地将这 4 个字节写入文件,而不会进行字符转换。
读写函数:
文本文件:一般使用 fprintf()、fscanf()、fgets()、fputs()等函数进行读写操作。这些函数在处理数据时会自动进行格式转换。
二进制文件:主要用 fread()和 fwrite()函数来读写。这两个函数是按块对数据进行操作的,不会对数据格式进行转换。
换行符处理
文本文件:换行符 \n。使用文本模式进行读写时,系统会自动完成换行符的转换。
二进制文件:会原样保留所有数据,不会对换行符进行转换。
文件打开模式
文本文件:使用 'r' 、‘w’、‘a’等。
二进制文件:要在模式后加 ‘b’,例如 ‘rb’、‘wb’、‘ab’,来明确指定使用二进制模式。
数据完整性
文本文件:由于存在格式转换,在存储一些特殊数据,如浮点数、二进制数据时,有可能造成精度丢失。
二进制文件:能够完整保留数据的原始格式,适合用来存储图像、音频、结构体等数据。
int main()
{int n = 123;// === 文本文件操作 ===// 以文本写入模式打开文件("w")// 若文件不存在则创建,存在则清空内容FILE *txt_file = fopen("text.txt", "w");// 使用fprintf以文本格式写入数据// 将整数123转换为字符串"123"存储// 占用3个字节,分别对应字符'1'、'2'、'3'fprintf(txt_file, "%d", n);// 关闭文件,释放资源fclose(txt_file);// === 二进制文件操作 ===// 以二进制写入模式打开文件("wb")// 同样若文件不存在则创建,存在则清空FILE *bin_file = fopen("binary.bin", "wb");// 使用fwrite直接写入内存中的二进制数据// &n:获取变量n的内存地址// sizeof(int):每个数据项的大小(4字节)// 1:写入1个数据项// 直接存储整数123的二进制表示(如0x0000007B)fwrite(&n, sizeof(int), 1, bin_file);// 关闭文件fclose(bin_file);// === 验证区别 ===// text.txt文件内容(文本查看):123// binary.bin文件内容(二进制查看):7B 00 00 00(取决于系统字节序)return 0;
}