15. truncate - 截断文件 見出しへのリンク
函数介绍 見出しへのリンク
truncate
系统调用用于将文件截断到指定长度。如果指定长度小于文件当前长度,则文件末尾被截断;如果指定长度大于文件当前长度,则文件被扩展,扩展部分填充为零。
函数原型 見出しへのリンク
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
功能 見出しへのリンク
根据文件路径将文件截断或扩展到指定长度。
参数 見出しへのリンク
const char *path
: 文件路径名off_t length
: 目标文件长度(字节)
返回值 見出しへのリンク
- 成功时返回0
- 失败时返回-1,并设置errno:
EACCES
: 权限不足EFBIG
: 长度参数过大EIO
: I/O错误EISDIR
: 路径指向目录ELOOP
: 符号链接循环ENAMETOOLONG
: 路径名过长ENOENT
: 文件不存在ENOTDIR
: 路径前缀不是目录EPERM
: 操作不被允许EROFS
: 文件在只读文件系统上ETXTBSY
: 文件是正在执行的程序
相似函数 見出しへのリンク
ftruncate()
: 通过文件描述符截断文件open()
配合O_TRUNC
标志
示例代码 見出しへのリンク
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
int main() {
int fd;
struct stat stat_buf;
printf("=== Truncate函数示例 ===\n");
// 示例1: 基本的文件截断操作
printf("\n示例1: 基本的文件截断操作\n");
// 创建测试文件并写入数据
fd = open("test_truncate.txt", O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd == -1) {
perror("创建测试文件失败");
exit(EXIT_FAILURE);
}
// 写入较长的数据
const char *original_data =
"This is a long piece of text that will be used to demonstrate "
"the truncate function. It contains multiple sentences and is "
"quite lengthy to show how truncation works.";
if (write(fd, original_data, strlen(original_data)) == -1) {
perror("写入原始数据失败");
close(fd);
exit(EXIT_FAILURE);
}
printf("写入原始数据,长度: %ld 字节\n", (long)strlen(original_data));
close(fd);
// 获取原始文件状态
if (stat("test_truncate.txt", &stat_buf) == -1) {
perror("获取文件状态失败");
} else {
printf("原始文件大小: %ld 字节\n", stat_buf.st_size);
}
// 使用truncate截断文件到50字节
printf("\n使用truncate将文件截断到50字节...\n");
if (truncate("test_truncate.txt", 50) == -1) {
perror("截断文件失败");
} else {
printf("文件截断成功\n");
}
// 检查截断后的文件大小
if (stat("test_truncate.txt", &stat_buf) == -1) {
perror("获取截断后文件状态失败");
} else {
printf("截断后文件大小: %ld 字节\n", stat_buf.st_size);
}
// 读取截断后的数据验证
fd = open("test_truncate.txt", O_RDONLY);
if (fd != -1) {
char buffer[100];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf("截断后文件内容: %s\n", buffer);
}
close(fd);
}
// 示例2: 扩展文件
printf("\n示例2: 扩展文件\n");
// 使用truncate将文件扩展到100字节
printf("使用truncate将文件扩展到100字节...\n");
if (truncate("test_truncate.txt", 100) == -1) {
perror("扩展文件失败");
} else {
printf("文件扩展成功\n");
}
// 检查扩展后的文件大小
if (stat("test_truncate.txt", &stat_buf) == -1) {
perror("获取扩展后文件状态失败");
} else {
printf("扩展后文件大小: %ld 字节\n", stat_buf.st_size);
}
// 读取扩展后的数据
fd = open("test_truncate.txt", O_RDONLY);
if (fd != -1) {
char buffer[150];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
if (bytes_read > 0) {
printf("扩展后文件前%d字节内容:\n", (int)bytes_read);
// 打印可见字符
for (int i = 0; i < bytes_read && i < 60; i++) {
if (buffer[i] >= 32 && buffer[i] <= 126) {
putchar(buffer[i]);
} else {
printf("[%02x]", (unsigned char)buffer[i]);
}
}
printf("\n");
}
close(fd);
}
// 示例3: 截断到0字节(清空文件)
printf("\n示例3: 截断到0字节(清空文件)\n");
printf("将文件截断到0字节...\n");
if (truncate("test_truncate.txt", 0) == -1) {
perror("清空文件失败");
} else {
printf("文件清空成功\n");
}
if (stat("test_truncate.txt", &stat_buf) == -1) {
perror("获取清空后文件状态失败");
} else {
printf("清空后文件大小: %ld 字节\n", stat_buf.st_size);
}
// 示例4: 不同长度的截断演示
printf("\n示例4: 不同长度的截断演示\n");
// 重新创建文件并写入数据
fd = open("test_truncate.txt", O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd != -1) {
const char *test_data = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (write(fd, test_data, strlen(test_data)) != -1) {
printf("重新写入测试数据: %s\n", test_data);
}
close(fd);
}
// 演示不同长度的截断
off_t lengths[] = {5, 15, 30, 50};
for (int i = 0; i < 4; i++) {
printf("截断到%ld字节: ", lengths[i]);
if (truncate("test_truncate.txt", lengths[i]) == -1) {
printf("失败 - %s\n", strerror(errno));
} else {
if (stat("test_truncate.txt", &stat_buf) == -1) {
printf("获取状态失败\n");
} else {
printf("成功,新大小: %ld字节\n", stat_buf.st_size);
// 读取并显示内容
fd = open("test_truncate.txt", O_RDONLY);
if (fd != -1) {
char buffer[100];
ssize_t bytes_read = read(fd, buffer, stat_buf.st_size);
if (bytes_read > 0) {
buffer[bytes_read] = '\0';
printf(" 内容: %s\n", buffer);
}
close(fd);
}
}
}
}
// 示例5: 错误处理演示
printf("\n示例5: 错误处理演示\n");
// 尝试截断不存在的文件
if (truncate("nonexistent_file.txt", 100) == -1) {
printf("截断不存在的文件: %s\n", strerror(errno));
}
// 尝试对只读文件系统上的文件操作
// 这个测试可能需要特殊环境,我们只演示概念
printf("对只读文件系统操作会返回EROFS错误\n");
// 尝试使用负数长度
if (truncate("test_truncate.txt", -10) == -1) {
printf("使用负数长度: %s\n", strerror(errno));
}
// 尝试对目录操作
if (truncate(".", 100) == -1) {
printf("对目录截断: %s\n", strerror(errno));
}
// 示例6: 实际应用场景
printf("\n示例6: 实际应用场景\n");
// 场景1: 日志文件轮转
printf("场景1: 日志文件轮转\n");
int log_fd = open("application.log", O_CREAT | O_RDWR | O_APPEND, 0644);
if (log_fd != -1) {
// 模拟写入大量日志
for (int i = 0; i < 100; i++) {
char log_entry[100];
sprintf(log_entry, "Log entry %d: Application is running normally\n", i);
write(log_fd, log_entry, strlen(log_entry));
}
close(log_fd);
// 检查日志文件大小
if (stat("application.log", &stat_buf) == 0) {
printf("日志文件大小: %ld 字节\n", stat_buf.st_size);
// 如果文件太大,截断到1KB
if (stat_buf.st_size > 1024) {
printf("日志文件过大,截断到1KB...\n");
if (truncate("application.log", 1024) == -1) {
perror("日志文件截断失败");
} else {
printf("日志文件截断成功\n");
}
}
}
unlink("application.log");
}
// 场景2: 临时文件大小控制
printf("场景2: 临时文件大小控制\n");
int temp_fd = open("temp_file.dat", O_CREAT | O_RDWR, 0644);
if (temp_fd != -1) {
// 创建一个大文件
char large_data[1000];
memset(large_data, 'X', sizeof(large_data));
for (int i = 0; i < 10; i++) {
write(temp_fd, large_data, sizeof(large_data));
}
close(temp_fd);
if (stat("temp_file.dat", &stat_buf) == 0) {
printf("临时文件原始大小: %ld 字节\n", stat_buf.st_size);
// 将文件大小调整为5KB
printf("调整临时文件大小到5KB...\n");
if (truncate("temp_file.dat", 5120) == -1) {
perror("调整文件大小失败");
} else {
printf("文件大小调整成功\n");
if (stat("temp_file.dat", &stat_buf) == 0) {
printf("调整后文件大小: %ld 字节\n", stat_buf.st_size);
}
}
}
unlink("temp_file.dat");
}
// 清理资源
printf("\n清理资源...\n");
if (unlink("test_truncate.txt") == -1) {
perror("删除测试文件失败");
} else {
printf("成功删除测试文件\n");
}
return 0;
}