今有文件 **test.txt** 文件内容如下: aBcDEfoKr# ,以 # 为结束,实现一个函数将其大小写转换输出到控制台修改保存源文件

  1. b12@PC:~/chapter13$ mkdir data
  2. b12@PC:~/chapter13$ echo 'aBcDEfoKr#' > ./data/test.txt
  3. b12@PC:~/chapter13$ cat ./data/test.txt
  4. aBcDEfoKr#

34、在打开文件时,指定的文件名找不到

错误示范文件名不对或该路径下没有该文件造成错误!

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main () {
  4. FILE *fp = fopen("./data/test", "r");
  5. if (NULL == fp) {
  6. printf("Error: can not open file\n");
  7. exit(0);
  8. }
  9. printf("Reading file successfully\n");
  10. // fclose(fp);
  11. return 0;
  12. }

编译运行: :::success b12@PC:~/chapter13$ gcc ./src/IO.c -o ./bin/IO
b12@PC:~/chapter13$ ./bin/IO
Error: can not open file ::: 拓展延申:在 Linux 下,有头文件 unistd.h 专门访问 Unix 平台的一系列函数,在 Windows 下不行!这里演示下获取工作目录。具体用法见官网, getcwd,getwd 两者都要申请内存用作函数填充路径问题。但是用 get_current_dir_name 比较方便。

  1. NAME
  2. getcwd, getwd, get_current_dir_name - get current working directory
  3. SYNOPSIS
  4. #include <unistd.h>
  5. char *getcwd(char *buf, size_t size);
  6. char *getwd(char *buf);
  7. char *get_current_dir_name(void);

当然我们也可以鸡贼调用 shell 命令 ls 帮我们打印当前目录信息。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main () {
  4. FILE *fp = fopen("./data/test.txt", "r"); // 注意路径
  5. if (NULL == fp) {
  6. printf("Error: can not open file\n");
  7. exit(0);
  8. }
  9. char ch = fgetc(fp);
  10. while ('#' != ch) {
  11. if ('A' <= ch && ch <= 'Z') {
  12. putchar(ch + 32);
  13. } else {
  14. putchar(ch - 32);
  15. }
  16. ch = fgetc(fp);
  17. }
  18. printf("\n");
  19. system("ls");
  20. fclose(fp);
  21. return 0;
  22. }

编译运行: :::success (base) b12@PC:~/chapter13$ gcc ./src/IO.c -o ./bin/IO
b12@PC:~/chapter13$ ./bin/IO
AbCdeFOkR
bin data src
(base) b12@PC:~/chapter13$ cat ./data/test.txt
aBcDEfoKr# ::: 但是上面的程序只是在控制台输出,然而源文件没有被修改过!修改见下面代码

33、使用文件时忘记打开,或打开方式与使用情况不匹配

错误示范r 打开又读又写

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main () {
  4. FILE *fp = fopen("./data/test.txt", "r");
  5. if (NULL == fp) {
  6. printf("Error: can not open file\n");
  7. exit(0);
  8. }
  9. char ch = fgetc(fp);
  10. while ('#' != ch) {
  11. if ('A' <= ch && ch <= 'Z') {
  12. putchar(ch + 32);
  13. fputc(ch + 32, fp);
  14. } else {
  15. putchar(ch - 32);
  16. fputc(ch - 32, fp);
  17. }
  18. ch = fgetc(fp);
  19. }
  20. printf("\n");
  21. fclose(fp);
  22. return 0;
  23. }

编译运行: :::success (base) b12@PC:~/chapter13$ gcc ./src/IO.c -o ./bin/IO
(base) b12@PC:~/chapter13$ ./bin/IO
AbCdeFOkR
(base) b12@PC:~/chapter13$ cat ./data/test.txt
aBcDEfoKr# ::: 可见没有报错,但是最终文件却没有被写入保存。
正确做法:重新创建临时文件 tmp.txt ,然后写入后,删除 test.txt 文件重命名临时文件 tmp.txttest.txt

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. char *originFile = "./data/test.txt";
  4. char *tmpFile = "./data/tmp.txt";
  5. int main () {
  6. FILE *fp1 = fopen(originFile, "r");
  7. if (NULL == fp1) {
  8. printf("Error: can not open %s file\n", originFile);
  9. exit(0);
  10. }
  11. FILE *fp2 = fopen(tmpFile, "w");
  12. if (NULL == fp2) {
  13. printf("Error: can not build %s file\n", tmpFile);
  14. exit(0);
  15. }
  16. char ch = fgetc(fp1);
  17. while ('#' != ch) {
  18. if ('A' <= ch && ch <= 'Z') {
  19. putchar(ch + 32);
  20. fputc(ch + 32, fp2);
  21. } else {
  22. putchar(ch - 32);
  23. fputc(ch - 32, fp2);
  24. }
  25. ch = fgetc(fp1);
  26. }
  27. printf("\n");
  28. fclose(fp1);
  29. // 1.删除原文件名
  30. if (0 != remove(originFile)) {
  31. printf("Error:can not remove %s!\n", originFile);
  32. exit(0);
  33. }
  34. // 2.将 tmp 文件重命名为 test.txt (偷天换日)
  35. if (0 != rename(tmpFile, originFile)) {
  36. printf("Error:can not rename %s!\n", tmpFile);
  37. exit(0);
  38. }
  39. fclose(fp2);
  40. return 0;
  41. }

编译运行: :::success (base) b12@PC:~/chapter13$ gcc ./src/IO.c -o ./bin/IO
(base) b12@PC:~/chapter13$ ./bin/IO
AbCdeFOkR
(base) b12@PC:~/chapter13$ cat ./data/test.txt
AbCdeFOkR :::

35、忘记关闭文件,虽然系统会自动关闭所用文件,但可能会丢失数据。因此必须在用完文件后关闭它

操作系统在进行 IO 时,有一个缓冲区,一般都是行缓冲(即为何你输入数据后要按下回车)可以设置超过多少后就进行处理。那么如果在缓冲区内含有数据尚未输出到磁盘之前就会关闭文件,那么就会造成数据丢失。