C语言怎么读写文件

一、C语言创建文件

1. 使用C语言创建一个文本文件log.txt并写入hello,world

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>

int main() {
FILE *file;

// 以写入模式打开文件,如果文件不存在则创建
file = fopen("log.txt", "w");

if (file == NULL) {
printf("无法创建文件。\n");
return 1;
}

// 向文件中写入内容
fprintf(file, "hello,world\n");

// 关闭文件
fclose(file);

printf("文件创建并写入成功!\n");
return 0;
}

2. 使用C语言打开log.txt并在下一行添加字符串”你好,世界”

将打开模式修改为 "a"(追加模式):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>

int main() {
FILE *file;

// 以读取模式打开文件,如果文件不存在则创建
file = fopen("log.txt", "a");

if (file == NULL) {
printf("无法创建文件。\n");
return 1;
}

// 向文件中写入内容
fprintf(file, "hello,world\n");

// 关闭文件
fclose(file);
return 0;
}

二、C语言读取文件

1. 用C语言读取第一行的字符串并打印。

要用 C 语言读取文本文件的第一行字符串并打印出来,可以按照以下步骤进行:

  1. 打开文件:使用 fopen 函数以读取模式打开目标文件。
  2. 读取第一行:使用 fgets 函数从文件中读取一行字符串。
  3. 打印字符串:将读取的字符串输出到控制台。
  4. 关闭文件:使用 fclose 函数关闭文件,释放资源。

下面是完整的代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>

int main() {
FILE *file;
char buffer[1024]; // 定义缓冲区来存储读取的字符串

// 1. 打开文件
file = fopen("log.txt", "r"); // 请确保文件名和路径正确
if (file == NULL) {
printf("无法打开文件。\n");
return 1;
}

// 2. 读取第一行
if (fgets(buffer, sizeof(buffer), file) != NULL) {
// 3. 打印字符串
printf("文件的第一行内容是:%s", buffer);
} else {
printf("文件是空的或读取错误。\n");
}

// 4. 关闭文件
fclose(file);
return 0;
}

2. 用C语言读取每一行的字符串并打印。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

int main() {
FILE *file;
char buffer[256];

file = fopen("log.txt", "r");

if (file == NULL) {
printf("无法打开文件。\n");
return 1;
}

// 逐行读取文件内容
while (fgets(buffer, sizeof(buffer), file) != NULL) {
printf("%s", buffer);
}

fclose(file);
return 0;
}

3. C语言以二进制的方式读取第一行字符串并以16进制打印。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdlib.h>

int main() {
FILE *file;
unsigned char buffer[1024]; // 用于存储读取的字节数据
size_t bytesRead = 0;
int ch;

// 1. 以二进制模式打开文件
file = fopen("log.txt", "rb");
if (file == NULL) {
printf("无法打开文件。\n");
return 1;
}

// 2. 读取第一行数据
while (bytesRead < sizeof(buffer)) {
ch = fgetc(file);
if (ch == EOF) {
break; // 到达文件末尾
}
buffer[bytesRead++] = (unsigned char)ch;
if (ch == '\n' || ch == '\r') {
// 遇到换行符或回车符,判断是否为 Windows 的 \r\n
if (ch == '\r') {
int next_ch = fgetc(file);
if (next_ch == '\n') {
buffer[bytesRead++] = (unsigned char)next_ch;
} else if (next_ch != EOF) {
ungetc(next_ch, file); // 将读取的字符退回流中
}
}
break; // 读取完第一行
}
}

fclose(file);

// 3. 以十六进制格式打印第一行的数据
if (bytesRead > 0) {
printf("第一行的十六进制内容是:\n");
for (size_t i = 0; i < bytesRead; i++) {
printf("%02X ", buffer[i]);
}
printf("\n");
} else {
printf("文件是空的或读取错误。\n");
}

return 0;
}

4. C语言以二进制的方式读取log.txt,并将结果以16进制写入到文本中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <stdlib.h>

int main() {
FILE *inputFile, *outputFile;
unsigned char buffer[1024]; // 用于存储读取的字节数据
size_t bytesRead;

// 1. 以二进制模式打开 log.txt 文件进行读取
inputFile = fopen("log.txt", "rb");
if (inputFile == NULL) {
printf("无法打开输入文件。\n");
return 1;
}

// 2. 以文本模式打开 output.txt 文件进行写入
outputFile = fopen("output.txt", "w");
if (outputFile == NULL) {
printf("无法创建输出文件。\n");
fclose(inputFile);
return 1;
}

// 3. 逐字节读取 log.txt 文件内容,并以十六进制格式写入 output.txt 文件
while ((bytesRead = fread(buffer, 1, sizeof(buffer), inputFile)) > 0) {
for (size_t i = 0; i < bytesRead; i++) {
fprintf(outputFile, "%02X ", buffer[i]);
}
fprintf(outputFile, "\n"); // 每读取一块数据后换行
}

// 4. 关闭文件
fclose(inputFile);
fclose(outputFile);

printf("文件内容已成功以十六进制格式写入到 output.txt。\n");
return 0;
}

三、C语言删除文件

  • **使用C语言删除log.txt **

要使用 C 语言删除一个文件(例如 log.txt),可以使用标准库函数 remove。这个函数用于删除指定路径的文件,如果删除成功,返回 0,否则返回一个非零值。

以下是一个完整的代码示例,展示了如何删除文件 log.txt

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main() {
// 尝试删除文件 log.txt
if (remove("log.txt") == 0) {
printf("文件 log.txt 已成功删除。\n");
} else {
perror("删除文件 log.txt 失败");
}

return 0;
}

注意事项

  • 文件路径:确保提供的文件路径正确,如果文件不在当前目录下,需要提供完整路径,例如 remove("/path/to/log.txt")
  • 文件权限:确保程序有权限删除指定的文件,否则 remove 函数会失败。
  • 检查文件是否存在:删除之前,可以检查文件是否存在,避免不必要的错误处理。

四、C语言复制文件

复制文件log.txt到其他路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>

int copyFile(const char *sourcePath, const char *destPath) {
FILE *sourceFile, *destFile;
unsigned char buffer[1024]; // 定义缓冲区
size_t bytesRead;

// 1. 打开源文件
sourceFile = fopen(sourcePath, "rb");
if (sourceFile == NULL) {
printf("无法打开源文件 %s。\n", sourcePath);
return 1;
}

// 2. 打开目标文件
destFile = fopen(destPath, "wb");
if (destFile == NULL) {
printf("无法创建目标文件 %s。\n", destPath);
fclose(sourceFile);
return 1;
}

// 3. 逐块读取并写入数据
while ((bytesRead = fread(buffer, 1, sizeof(buffer), sourceFile)) > 0) {
fwrite(buffer, 1, bytesRead, destFile);
}

// 4. 关闭文件
fclose(sourceFile);
fclose(destFile);

printf("文件已成功从 %s 复制到 %s。\n", sourcePath, destPath);
return 0;
}

int main() {
const char *sourcePath = "log.txt";
const char *destPath = "/home/kali/cc++/log.txt"; // 替换为实际目标路径

// 调用复制函数
int result = copyFile(sourcePath, destPath);

return result;
}

以二进制读取的任何文件都能复制。

五、C语言修改文件

1. 用C语言修改第一行的字符串为abcdefg

方法:使用临时文件,适合处理大文件

如果文件很大,读取整个文件到内存可能不太现实。可以采取以下方法:

  1. 同时打开原文件和临时文件:
    • 以读取模式打开原文件。
    • 以写入模式创建临时文件。
  2. 逐行读取原文件,写入临时文件:
    • 读取第一行,写入修改后的内容 abcdefg 到临时文件。
    • 从第二行开始,直接将读取的内容写入临时文件,不做修改。
  3. 替换原文件:
    • 关闭文件后,删除原文件。
    • 将临时文件重命名为原文件名。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE_LENGTH 1024

int main() {
FILE *file_in, *file_out;
char buffer[MAX_LINE_LENGTH];
int line_number = 0;

// 打开原文件读取
file_in = fopen("log.txt", "r");
if (file_in == NULL) {
printf("无法打开原文件。\n");
return 1;
}

// 打开临时文件写入
file_out = fopen("temp_log.txt", "w");
if (file_out == NULL) {
printf("无法创建临时文件。\n");
fclose(file_in);
return 1;
}

// 逐行读取原文件,处理并写入临时文件
while (fgets(buffer, MAX_LINE_LENGTH, file_in) != NULL) {
line_number++;
if (line_number == 1) {
// 修改第一行
fprintf(file_out, "abcdefg\n");
} else {
// 其余行直接写入
fputs(buffer, file_out);
}
}

// 如果文件为空,添加 "abcdefg" 作为第一行
if (line_number == 0) {
fprintf(file_out, "abcdefg\n");
}

fclose(file_in);
fclose(file_out);

// 删除原文件,重命名临时文件
if (remove("log.txt") != 0) {
printf("无法删除原文件。\n");
return 1;
}
if (rename("temp_log.txt", "log.txt") != 0) {
printf("无法重命名临时文件。\n");
return 1;
}

printf("文件的第一行已成功修改为 'abcdefg'。\n");
return 0;
}

方法详解:

  • 文件操作:
    • file_in:指向原始文件,用于读取。
    • file_out:指向临时文件,用于写入。
  • 流程说明:
    • 读取和写入:
      • 使用 fgets 从原文件读取每一行。
      • 使用 fprintffputs 将内容写入临时文件。
      • 对第一行进行特殊处理,替换为 abcdefg
    • 文件替换:
      • 关闭所有文件指针后,使用 remove 删除原文件。
      • 使用 rename 将临时文件重命名为原文件名,实现文件的替换。
  • 优点:
    • 高效性: 无需将整个文件内容加载到内存中,适合处理大型文件。
    • 简洁性: 代码逻辑清晰,易于理解和维护。
  • 注意事项:
    • 错误处理: 在删除和重命名文件时,必须检查返回值,确保文件操作成功。
    • 权限问题: 程序需要有删除和修改文件的权限。

2. 以二进制的方式将第二行中的’abcdefg’修改为’hijklmn’

要用 C 语言以二进制方式读取文件,并将第二行中的 ‘abcdefg’ 修改为 ‘hijklmn’,需要以下步骤:

  1. 打开文件:以二进制读写模式打开文件。
  2. 读取文件内容:逐行读取文件,找到第二行并进行修改。
  3. 写回修改后的内容:将修改后的内容重新写回文件。

以下是一个完整的代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 1024

int main() {
FILE *file;
char buffer[BUFFER_SIZE];
long secondLinePos = 0;
int currentLine = 0;

// 打开文件(读写模式)
file = fopen("log.txt", "rb+");
if (file == NULL) {
perror("无法打开文件");
return 1;
}

// 读取文件并寻找第二行的位置
while (fgets(buffer, sizeof(buffer), file) != NULL) {
currentLine++;
if (currentLine == 2) {
secondLinePos = ftell(file) - strlen(buffer);
break;
}
}

// 如果没有找到第二行,输出错误信息
if (currentLine < 2) {
printf("文件没有第二行。\n");
fclose(file);
return 1;
}

// 修改第二行中的 'abcdefg' 为 'hijklmn'
fseek(file, secondLinePos, SEEK_SET);
if (fgets(buffer, sizeof(buffer), file) != NULL) {
char *pos = strstr(buffer, "abcdefg");
if (pos != NULL) {
fseek(file, secondLinePos + (pos - buffer), SEEK_SET);
fwrite("hijklmn", sizeof(char), strlen("hijklmn"), file);
}
}

// 关闭文件
fclose(file);

printf("第二行中的 'abcdefg' 已修改为 'hijklmn'。\n");
return 0;
}

代码解析:

  1. 包含头文件:
    • #include <stdio.h>:标准输入输出库,提供文件操作。
    • #include <stdlib.h>:标准库。
    • #include <string.h>:字符串处理库。
  2. 宏定义:
    • #define BUFFER_SIZE 1024:定义缓冲区大小。
  3. 主程序:
    • FILE *file;:文件指针。
    • char buffer[BUFFER_SIZE];:缓冲区,用于存储读取的行。
    • long secondLinePos = 0;:用于存储第二行的文件位置。
    • int currentLine = 0;:用于记录当前行号。
  4. 打开文件:
    • 使用 fopen("log.txt", "rb+") 以二进制读写模式打开文件。
  5. 读取文件并寻找第二行的位置:
    • 使用 fgets 逐行读取文件内容。
    • 当前行号递增,如果达到第二行,记录当前文件位置。
  6. 修改第二行的内容:
    • 使用 fseek 移动文件指针到第二行的位置。
    • 使用 strstr 查找 ‘abcdefg’ 的位置。
    • 使用 fwrite 写入 ‘hijklmn’,覆盖原有内容。
  7. 关闭文件:
    • 使用 fclose 关闭文件。

注意事项:

  • 文件路径:确保文件路径正确,并且文件存在。
  • 文件权限:确保程序有权限读取和修改文件。
  • 字符串匹配:代码假设 ‘abcdefg’ 在第二行中出现,且长度相同。否则需要更复杂的处理。

3. 以二进制的方式将第二行中的’abcdefg’修改为’hijklmn’,逐个写入字符的 ASCII 码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFFER_SIZE 1024

int main() {
FILE *file;
char buffer[BUFFER_SIZE];
long secondLinePos = 0;
int currentLine = 0;

// 打开文件(读写模式)
file = fopen("log.txt", "rb+");
if (file == NULL) {
perror("无法打开文件");
return 1;
}

// 读取文件并寻找第二行的位置
while (fgets(buffer, sizeof(buffer), file) != NULL) {
currentLine++;
if (currentLine == 2) {
secondLinePos = ftell(file) - strlen(buffer);
break;
}
}

// 如果没有找到第二行,输出错误信息
if (currentLine < 2) {
printf("文件没有第二行。\n");
fclose(file);
return 1;
}

// 修改第二行中的 'abcdefg' 为 'hijklmn'
fseek(file, secondLinePos, SEEK_SET);
if (fgets(buffer, sizeof(buffer), file) != NULL) {
char *pos = strstr(buffer, "abcdefg");
if (pos != NULL) {
fseek(file, secondLinePos + (pos - buffer), SEEK_SET);
const char *newStr = "hijklmn";
for (size_t i = 0; i < strlen(newStr); i++) {
fputc(newStr[i], file);
}
}
}

// 关闭文件
fclose(file);

printf("第二行中的 'abcdefg' 已修改为 'hijklmn'。\n");
return 0;
}

六、C语言调用Linux系统函数复制文件夹

1. 复制文件夹的步骤:

  1. 打开源文件夹。
  2. 创建目标文件夹。
  3. 遍历源文件夹中的每个条目:
    • 如果是文件,复制文件。
    • 如果是子文件夹,递归复制子文件夹。
  4. 处理错误和边界情况(例如文件权限问题)。

2. 代码示例:

以下是一个实现上述步骤的代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

#define BUFFER_SIZE 1024

// 复制文件
int copyFile(const char *sourcePath, const char *destPath) {
FILE *sourceFile, *destFile;
char buffer[BUFFER_SIZE];
size_t bytesRead;

sourceFile = fopen(sourcePath, "rb");
if (sourceFile == NULL) {
perror("无法打开源文件");
return 1;
}

destFile = fopen(destPath, "wb");
if (destFile == NULL) {
perror("无法创建目标文件");
fclose(sourceFile);
return 1;
}

while ((bytesRead = fread(buffer, 1, sizeof(buffer), sourceFile)) > 0) {
fwrite(buffer, 1, bytesRead, destFile);
}

fclose(sourceFile);
fclose(destFile);
return 0;
}

// 递归复制文件夹
int copyDirectory(const char *sourceDir, const char *destDir) {
DIR *dir;
struct dirent *entry;
struct stat statBuffer;

// 创建目标文件夹
mkdir(destDir, 0755);

// 打开源文件夹
dir = opendir(sourceDir);
if (dir == NULL) {
perror("无法打开源文件夹");
return 1;
}

// 遍历源文件夹中的每个条目
while ((entry = readdir(dir)) != NULL) {
char sourcePath[PATH_MAX];
char destPath[PATH_MAX];

// 忽略 "." 和 ".."
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}

// 构建源路径和目标路径
snprintf(sourcePath, sizeof(sourcePath), "%s/%s", sourceDir, entry->d_name);
snprintf(destPath, sizeof(destPath), "%s/%s", destDir, entry->d_name);

// 获取文件/文件夹的属性
if (stat(sourcePath, &statBuffer) == -1) {
perror("无法获取文件属性");
continue;
}

// 如果是文件夹,递归复制
if (S_ISDIR(statBuffer.st_mode)) {
copyDirectory(sourcePath, destPath);
} else {
copyFile(sourcePath, destPath);
}
}

closedir(dir);
return 0;
}

int main() {
const char *sourceDir = "/home/kali/cc++/crawler"; // 源文件夹路径
const char *destDir = "/home/kali/cc++/crawler_copy"; // 目标文件夹路径

if (copyDirectory(sourceDir, destDir) == 0) {
printf("文件夹复制成功!\n");
} else {
printf("文件夹复制失败!\n");
}

return 0;
}

3. 代码解析:

  1. 包含头文件:
    • #include <stdio.h>:标准输入输出库。
    • #include <stdlib.h>:标准库。
    • #include <string.h>:字符串处理。
    • #include <sys/types.h>#include <sys/stat.h>:文件属性操作。
    • #include <dirent.h>:目录操作。
    • #include <unistd.h>:POSIX 标准库函数。
  2. copyFile 函数:用于复制单个文件。
    • 打开源文件和目标文件。
    • 逐块读取源文件并写入目标文件。
    • 关闭文件。
  3. copyDirectory 函数:用于递归复制文件夹。
    • 使用 mkdir 创建目标文件夹。
    • 打开源文件夹,使用 opendirreaddir 遍历文件夹内容。
    • 忽略 ... 条目。
    • 使用 stat 获取文件/文件夹属性。
    • 如果是文件夹,递归调用 copyDirectory
    • 如果是文件,调用 copyFile 复制文件。
    • 关闭目录。
  4. main 函数:定义源文件夹和目标文件夹路径,调用 copyDirectory 函数执行复制操作。

注意事项:

  • 路径处*:确保源文件夹和目标文件夹路径正确。
  • 文件权限:程序需要有权限访问源文件夹和写入目标文件夹。
  • 递归深度:确保递归深度不超过系统限制。

七、C语言调用Linux系统标准库删除文件夹

1. 删除空文件夹

以下是一个使用 rmdir 函数删除空文件夹的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <unistd.h>

int main() {
const char *folderPath = "path/to/empty/folder";

if (rmdir(folderPath) == 0) {
printf("文件夹已成功删除:%s\n", folderPath);
} else {
perror("删除文件夹失败");
}

return 0;
}

2. 递归删除非空文件夹

对于非空文件夹,可以使用 nftw 函数递归删除文件夹及其内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <stdlib.h>
#include <ftw.h>
#include <unistd.h>
#include <limits.h>

// 手动定义宏(如果未定义)
#ifndef FTW_DEPTH
#define FTW_DEPTH 8
#endif

#ifndef FTW_PHYS
#define FTW_PHYS 1
#endif

// 删除单个文件或目录
int removeEntry(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
int ret = remove(fpath);
if (ret) perror(fpath);
return ret;
}

// 递归删除目录
int removeDirectory(const char *path) {
return nftw(path, removeEntry, 64, FTW_DEPTH | FTW_PHYS);
}

int main() {
const char *folderPath = "/home/kali/cc++/crawler_copy";

if (removeDirectory(folderPath) == 0) {
printf("文件夹及其内容已成功删除:%s\n", folderPath);
} else {
perror("删除文件夹失败");
}

return 0;
}

代码解析:

  1. 删除空文件夹:
    • #include <unistd.h>:包含 Unix 标准库,用于系统调用。
    • rmdir(folderPath):尝试删除指定路径的空文件夹。
  2. 递归删除非空文件夹:
    • #include <ftw.h>:包含文件树遍历库。
    • nftw(path, removeEntry, 64, FTW_DEPTH | FTW_PHYS):递归遍历并删除目录及其内容。
      • removeEntry:删除单个文件或目录的回调函数。
      • FTW_DEPTH:深度优先遍历。
      • FTW_PHYS:不跟随符号链接。

注意事项:

  • 路径处*:确保提供正确的文件夹路径,并具有删除权限。
  • 删除非空目录:使用 rmdir 只能删除空目录,删除非空目录需要使用递归方法。
  • 谨慎操作:递归删除目录时要小心,以防误删除重要文件夹。