C语言文件I/O相关函数操作
fopen/fcolse
fopen 函数用于打开一个文件,并根据指定的模式(如只读、只写、读写等)返回一个指向该文件的 FILE 类型的指针。如果文件打开失败,fopen 将返回 NULL。
函数原型:
FILE *fopen(const char *filename, const char *mode);
filename:要打开文件的名称(包括路径,如果需要的话)。
mode:指定文件打开的模式。常见的模式有 “r”(只读)、“w”(只写,文件存在则长度被截断为零,即该文件内容会消失;文件不存在则创建新文件)、“a”(追加,写入的数据会被追加到文件尾,如果文件不存在则创建新文件)、“r+”(读写,文件必须存在)、“w+”(读写,同上,但文件内容会被清空)、“a+”(读写,写入的数据会被追加到文件尾)等。
man fopen查看相关信息:
fclose 函数用于关闭一个先前用 fopen 或 fdopen 打开的文件。关闭文件是一个好习惯,可以释放文件相关的资源并确保所有的输出都被正确地写入文件。
函数原型如下:
int fclose(FILE *stream);
stream:指向 FILE 对象的指针,该 FILE 对象标识了要关闭的文件。
fclose 函数在成功时返回 0,在失败时返回 EOF。然而,在大多数实现中,fclose 仅在极少数情况下会失败(如写入文件时磁盘空间不足),并且通常它总是能成功关闭文件。
写文件:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp = fopen("myfile", "w");
if(!fp){
printf("fopen error!\n");
}
const char *msg = "hello bit!\n";
int count = 5;
while(count--){
fwrite(msg, strlen(msg), 1, fp);
}
fclose(fp);
return 0;
}
fwrite
fwrite 函数用于向文件写入数据块。它从一个数组中获取数据,并将数据写入到文件中。与 fprintf 不同的是,fwrite 不对数据进行格式化,而是直接按照数据块的原始形式写入。
函数原型如下:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr:指向要写入的数据块的指针。
size:每个数据块的大小(以字节为单位)。
nmemb:数据块的个数。
stream:指向 FILE 对象的指针,该 FILE 对象标识了要写入数据的文件。
fwrite 返回成功写入的数据块的数量,通常这等于 nmemb 的值,除非发生了错误或达到了文件末尾。
我们用fwrite向myfile中写入:
#include<stdio.h>
#include<string.h>
int main()
{
FILE* fp = fopen("myfile","w");
if(fp==NULL)
{
perror("fopen");
}
//进行文件操作
const char *s1 = "hello Linux\n";
fwrite(s1, strlen(s1), 1, fp);
fclose(fp);
return 0;
}
fseek
fseek 函数用于设置文件内部的位置指针,即文件读/写的下一个位置。通过调用 fseek,程序可以在文件中前后移动,进行非顺序访问。
函数原型如下:
int fseek(FILE *stream, long offset, int whence);
stream:指向 FILE 对象的指针,该 FILE 对象标识了要移动位置的文件。
offset:相对于 whence 指定的位置的偏移量,以字节为单位。
whence:指定从哪个位置开始计算偏移量。它可以是 SEEK_SET(文件开头)、SEEK_CUR(当前位置)、或 SEEK_END(文件末尾)。
fseek 成功时返回 0,失败时返回非零值。
用fseek修改myfile中特定位置:
#include <stdio.h>
int main() {
FILE *fp = fopen("myfile", "r+"); // 以读写模式打开文件
if (fp == NULL) {
perror("Error opening file");
return -1;
}
// 假设我们要修改文件中的某些内容
fseek(fp, 5, SEEK_SET); // 将文件位置指针移动到文件开头后的第5个字节
fputc('X', fp); // 在当前位置写入字符'X'
fclose(fp);
return 0;
}
fprintf/fscanf
fprintf函数用于向文件或标准输出流(如stdout)写入格式化的数据。它的工作方式类似于printf,但fprintf允许你指定一个输出流(FILE* 类型的指针),而不仅仅是标准输出。
函数原型:
int fprintf(FILE *stream, const char *format, ...);
stream:指向FILE对象的指针,指定了输出目标。
format:格式化字符串,指定了后续参数如何被格式化和插入到输出流中。
…:可变数量的参数,根据format字符串中的格式说明符进行格式化。
返回值: 成功时返回写入的字符数(不包括末尾的空字符),失败时返回负值。
fprintf示例:
#include <stdio.h>
int main() {
FILE *fp = fopen("output.txt", "w"); // 打开文件用于写入
if (fp == NULL) {
perror("Error opening file");
return -1;
}
// 使用 fprintf 写入格式化的数据
fprintf(fp, "Name: %s\nAge: %d\n", "Alice", 30);
fclose(fp); // 关闭文件
return 0;
}
fscanf函数用于从文件或标准输入流(如stdin)读取格式化的输入。它类似于scanf,但允许你指定一个输入流(FILE* 类型的指针)。
函数原型:
int fscanf(FILE *stream, const char *format, ...);
stream:指向FILE对象的指针,指定了输入源。
format:格式化字符串,指定了如何解析输入流中的数据。
…:可变数量的参数,用于存储解析出的数据。
返回值: 成功匹配并赋值的输入项的数量,如果到达文件末尾或发生读取错误,则可能返回EOF。
fgets/fputs
fgets函数用于从指定的文件流中读取一行数据,直到遇到换行符(‘\n’)、文件结束符(EOF)或已读取了n-1个字符为止(其中n是fgets函数的第三个参数指定的最大字符数)。读取的字符串会在末尾自动添加一个空字符(‘\0’)以标记字符串的结束。
函数原型:
char *fgets(char *str, int n, FILE *stream);
str:指向用于存储读取数据的字符数组的指针。
n:指定了最多读取的字符数(包括末尾的空字符)。
stream:指向FILE对象的指针,指定了输入源。
返回值: 成功时返回指向str的指针,失败时或到达文件末尾时返回NULL。
示例:
#include <stdio.h>
int main() {
FILE *fp = fopen("myfile", "r"); // 打开文件用于读取
if (fp == NULL) {
perror("Error opening file");
return -1;
}
char line[100];
// 使用 fgets 逐行读取文件
while (fgets(line, sizeof(line), fp) != NULL) {
printf("%s", line); // 打印读取的行
}
fclose(fp); // 关闭文件
return 0;
}
这个示例将逐行读取lines.txt文件的内容,并打印到标准输出上。
fputs函数用于将一个字符串写入到指定的文件流中,但不包括末尾的空字符(‘\0’)。与fputs相对的是fputs_s(在某些安全敏感的环境中可用),它要求明确指定目标缓冲区的大小,以防止缓冲区溢出。
函数原型:
int fputs(const char *str, FILE *stream);
str:指向要写入文件的字符串的指针。
stream:指向FILE对象的指针,指定了输出目标。
返回值: 成功时返回非负值,失败时返回EOF。
示例:
#include <stdio.h>
int main() {
FILE *fp = fopen("copy.txt", "w"); // 打开文件用于写入
if (fp == NULL) {
perror("Error opening file");
return -1;
}
// 使用 fputs 写入字符串到文件
fputs("Hello, World!\n", fp);
fputs("This is another line.\n", fp);
fclose(fp); // 关闭文件
return 0;
}
系统调用相关接口
系统调用是操作系统提供给用户程序与操作系统内核进行交互的接口。在C语言中,这些系统调用通常通过库函数封装后提供给用户使用,这些库函数定义在如<unistd.h>(POSIX标准)、<fcntl.h>等头文件中。下面将介绍open、close、write、read这四个系统调用
open/close
open系统调用用于打开或创建一个文件。它返回一个文件描述符(一个非负整数),用于后续的read、write等系统调用。如果打开失败,则返回-1。
函数原型(POSIX标准):
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
pathname:要打开或创建的文件的名称。
flags:用于指定文件如何被打开或创建,例如O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)、O_CREAT(如果文件不存在则创建)、O_TRUNC(如果文件已存在且为只写或读写模式,则长度截断为0)等。
mode(可选):如果文件被创建,这个参数指定了文件的权限。
man open查看详细信息
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("example.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
perror("open failed");
return -1;
}
// 后续可以使用fd进行write等操作
close(fd); // 不要忘记关闭文件
return 0;
}
close系统调用用于关闭一个打开的文件描述符。关闭文件描述符会释放文件或设备相关的资源,并确保所有的输出都被正确地写入。
函数原型:
#include <unistd.h>
int close(int fd);
fd:要关闭的文件描述符。
write/read
write系统调用用于将数据写入到打开的文件描述符中。
函数原型:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
fd:要写入的文件描述符。
buf:指向要写入数据的缓冲区的指针。
count:要写入的字节数。
返回值:
成功:返回实际写入的字节数。
失败:返回-1,并设置errno来指示错误。
read系统调用用于从打开的文件描述符中读取数据。
函数原型:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd:要从中读取数据的文件描述符。
buf:指向存储读取数据的缓冲区的指针。
count:要读取的最大字节数。
返回值:
成功:返回实际读取的字节数。
失败:返回-1,并设置errno来指示错误。