在 C 语言中,文件操作是一项基础且重要的技能。无论是简单的文本文件读写,还是复杂的二进制文件处理,掌握文件操作对于开发各种类型的应用程序都是必不可少的。本文将详细介绍 C 语言中文件操作的基本原理、常用函数及其使用方法,并通过示例代码加深理解。
在 C 语言中,文件操作主要通过两种方式进行:标准 I/O 函数族 (stdio.h
) 和低级 I/O 函数族 (fcntl.h
和 unistd.h
)。
标准 I/O 函数族提供了一套高级的、面向流的 API,如 fopen
, fclose
, fprintf
, fscanf
等。这些函数使用起来非常直观,适合大多数应用场景。
低级 I/O 函数族提供了更底层的操作接口,如 open
, close
, read
, write
等。这些函数允许开发者更精细地控制文件的读写过程,通常用于需要高度定制化的场景。
在 Unix/Linux 系统中,文件通过文件描述符来标识。文件描述符是一个非负整数,通常用于系统调用。每个进程都有一个文件描述符表,用于跟踪打开的文件和其他 I/O 资源。
STDIN_FILENO
(0): 标准输入。STDOUT_FILENO
(1): 标准输出。STDERR_FILENO
(2): 标准错误输出。在 C 语言中,文件通过结构体 FILE
来表示。FILE
结构体包含文件的状态信息、缓冲区、当前位置等。
struct _IO_FILE {
/* ... */
char *_M_buf_base;
char *_M_buf_end;
char *_M_ptr;
/* ... */
};
在 C 语言中,文件操作通过文件指针来进行。文件指针是一个指向结构体 FILE
的指针,该结构体包含了文件的相关信息。
#include
FILE *fp; // 文件指针声明
fopen
函数用于打开文件。它接受两个参数:文件名和模式字符串。常见的模式包括 "r"
(只读)、"w"
(只写,清空原有内容)、"a"
(追加模式)、"r+"
(读写)、"w+"
(读写,清空原有内容)等。
#include
FILE *fp = fopen("example.txt", "r"); // 以只读模式打开文件
if (fp == NULL) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
使用完毕后,应通过 fclose
函数关闭文件,释放相关资源。
#include
fclose(fp); // 关闭文件
fgetc
用于从文件中读取单个字符。int ch;
while ((ch = fgetc(fp)) != EOF) {
putchar(ch); // 输出到标准输出
}
fgets
用于从文件中读取一行字符串。char str[100];
fgets(str, sizeof(str), fp); // 读取一行
fscanf
类似于 scanf
,用于从文件中读取格式化的数据。int num;
fscanf(fp, "%d", &num); // 读取整数
fputc
用于向文件中写入单个字符。fputc('A', fp); // 写入字符 'A'
fputs
用于向文件中写入字符串。const char *str = "Hello, world!";
fputs(str, fp); // 写入字符串
fprintf
类似于 printf
,用于向文件中写入格式化的数据。int num = 42;
fprintf(fp, "Number: %d", num); // 写入整数
fseek
和 ftell
函数用于改变文件指针的位置。
long pos = ftell(fp); // 获取当前文件指针位置
fseek(fp, 0, SEEK_SET); // 将文件指针移动到文件开头
fflush
函数用于刷新输出缓冲区,确保所有数据都被写入文件。
fflush(fp); // 刷新文件输出缓冲区
在进行文件操作时,必须注意处理可能出现的错误。使用 ferror
和 clearerr
函数可以帮助诊断和清除错误状态。
if (ferror(fp)) {
perror("Error occurred");
} else {
clearerr(fp); // 清除错误状态
}
在低级 I/O 函数族中,文件通过文件描述符来标识。文件描述符是一个非负整数,通常用于系统调用。
#include
#include
int fd; // 文件描述符
open
函数用于打开文件。它接受三个参数:文件名、打开模式和权限掩码。
int fd = open("example.txt", O_RDONLY); // 以只读模式打开文件
if (fd == -1) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
使用 close
函数关闭文件。
close(fd); // 关闭文件
read
函数用于从文件中读取数据。char buffer[256];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read == -1) {
perror("Error reading file");
exit(EXIT_FAILURE);
}
write
函数用于向文件中写入数据。const char *str = "Hello, world!";
ssize_t bytes_written = write(fd, str, strlen(str));
if (bytes_written == -1) {
perror("Error writing file");
exit(EXIT_FAILURE);
}
#include
#include
#include
#include
int main() {
int fd;
char buffer[256];
ssize_t bytes_read;
fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
write(STDOUT_FILENO, buffer, bytes_read);
}
close(fd);
return 0;
}
#include
#include
#include
#include
int main() {
int fd;
const char *str = "Hello, world!";
fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
ssize_t bytes_written = write(fd, str, strlen(str));
if (bytes_written == -1) {
perror("Error writing file");
exit(EXIT_FAILURE);
}
close(fd);
return 0;
}
在 Unix/Linux 系统中,文件权限决定了用户对文件的访问权限。权限包括读 (r
), 写 (w
), 和执行 (x
)。
r
): 允许读取文件内容。w
): 允许修改文件内容。x
): 允许执行文件作为程序。在使用 open
函数时,可以通过不同的模式来指定文件的打开方式。
00000000
) : 只读模式。00000001
) : 只写模式。00000002
) : 读写模式。00000004
) : 追加模式,每次写入都会移动到文件末尾。00000100
) : 如果文件不存在,则创建文件。00000200
) : 如果文件存在,则截断文件长度至 0 字节。00000400
) : 如果文件已存在,O_CREAT
和 O_EXCL
同时设置时,打开失败。setbuf
或 setvbuf
来控制缓冲区行为。flock
函数来实现文件的独占访问,避免并发问题。realpath
函数来获取文件的绝对路径。stat
或 fstat
函数来获取文件属性,如大小、权限等。在处理大型文件时,需要注意内存使用情况。通常采用分块读写的方式来处理大文件,以避免一次性加载整个文件到内存中。
#include
#include
#define BUFFER_SIZE 1024
int main() {
FILE *fp;
char *buffer = malloc(BUFFER_SIZE);
size_t bytes_read;
fp = fopen("largefile.txt", "r");
if (fp == NULL) {
perror("Error opening file");
free(buffer);
exit(EXIT_FAILURE);
}
while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, fp)) > 0) {
fwrite(buffer, 1, bytes_read, stdout);
}
fclose(fp);
free(buffer);
return 0;
}
文件映射是一种高效的文件操作方式,它可以将文件的一部分映射到内存区域,从而实现对文件的快速随机访问。
#include
#include
#include
#include
#include
#include
int main() {
int fd;
struct stat sb;
char *mem;
size_t length;
fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
if (fstat(fd, &sb) == -1) {
perror("Error getting file status");
close(fd);
exit(EXIT_FAILURE);
}
length = sb.st_size;
mem = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
if (mem == MAP_FAILED) {
perror("Error mapping file to memory");
close(fd);
exit(EXIT_FAILURE);
}
// 使用 mem 访问文件内容
// ...
munmap(mem, length);
close(fd);
return 0;
}
在多线程或多进程环境中,文件操作需要保证同步以防止数据损坏。可以使用互斥锁或其他同步机制来保护共享资源。
#include
#include
#include
#include
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *writer_thread(void *arg) {
int fd = *(int *)arg;
pthread_mutex_lock(&lock);
write(fd, "Thread data", 12);
pthread_mutex_unlock(&lock);
return NULL;
}
int main() {
int fd;
pthread_t thread;
fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("Error opening file");
exit(EXIT_FAILURE);
}
pthread_create(&thread, NULL, writer_thread, &fd);
pthread_join(thread, NULL);
close(fd);
return 0;
}
本文详细介绍了 C 语言中的文件操作,包括标准 I/O 函数族和低级 I/O 函数族。通过这些函数,您可以轻松地进行文件的打开、读取、写入和关闭等操作。希望本文能够帮助您更好地理解和掌握 C 语言中的文件操作技巧。