【文件操作:解锁高效读写与管理技巧】(中)

简介: 【文件操作:解锁高效读写与管理技巧】

【文件操作:解锁高效读写与管理技巧】(上):https://developer.aliyun.com/article/1424823


那么再来写练一下文本行输出函数


int fputs ( const char * str, FILE * stream );


  • 将由 str 指向的 C 字符串写入流中。
  • 该函数从指定地址(str)开始复制,直到遇到终止空字符('\0')为止。终止空字符不会被复制到流中。
  • 注意,fputs 与 puts 的区别不仅在于可以指定目标流,而且 fputs 不会写入额外的字符,而 puts 会自动在末尾追加换行字符。


#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt","w");
  if (!pf)
  {
    perror("fopen");
    return 1;
  }
  //写文件 - 写一行 - 输出
  //int fputs ( const char * str, FILE * stream );
  fputs("hello world\n",pf);
  fputs("big dream\n", pf);
  //这两句话在文件中是一行还是两行? 两行
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}


输出结果:



文本输入函数:


int fgetc ( FILE * stream );


  • 返回指定流的内部文件位置指示器当前指向的字符。然后,内部文件位置指示器会向下一个字符推进。
  • 如果在调用时流已经到达文件末尾,该函数返回 EOF 并为该流设置文件末尾指示器 (feof)。
  • 如果发生读取错误,该函数返回 EOF 并为该流设置错误指示器 (ferror)。
  • fgetc 和 getc 是等价的,但在某些库中 getc 可能被实现为宏。


#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt","r");
  if (!pf)
  {
    perror("fopen");
    return 1;
  }
  //读文件 - 读一行 - 输入
  //char * fgets ( char * str, int num, FILE * stream );
  char arr[10] = { 0 };
  fgets(arr, 10, pf);
  printf("%s\n", arr);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}


运行结果:



       上面的结果发现输出了两个换行,说明fgets在获取到num-1(留一个位置给'\n')个字符之后会自动换行。如果该字符没有读完,下次读取就会取消第一次读取的换行,将第二次的输出字符,直至这个字符串读完再换行。


格式输出函数:


int fprintf ( FILE * stream, const char * format, ... );


  • 将由 format 指向的 C 字符串写入流中。如果 format 包含格式说明符(以 % 开头的子序列),则会格式化并插入 format 后面的附加参数,替换相应的格式说明符。
  • 在 format 参数之后,该函数期望至少有与 format 指定的格式相同数量的附加参数。


#include<stdio.h>
int main()
{
  FILE* pf = fopen("data.txt","w");
  if (!pf)
  {
    perror("fopen");
    return 1;
  }
  //写文件  - 输出
  //int fprintf ( FILE * stream, const char * format, ... );
  fprintf(pf,"%d %lf",520,13.14);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}


结果:



格式输入函数


int fscanf ( FILE * stream, const char * format, ... );


  • 从流中读取数据,并根据参数 format 将它们存储到附加参数所指向的位置。
  • 附加参数应该指向已经分配的对象,其类型由 format 字符串中对应的格式说明符指定。


#include<stdio.h>
int main()
{
  int a;
  double d;
  FILE* pf = fopen("data.txt","r");
  if (!pf)
  {
    perror("fopen");
    return 1;
  }
  //读文件  - 输入
  //int fscanf ( FILE * stream, const char * format, ... );
  fscanf(pf, "%d %lf", &a, &d);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}


二进制输出:


size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );


  • 将由 ptr 指向的内存块中的 count 个元素写入流的当前位置。
  • 流的位置指示器会根据写入的总字节数向前推进。
  • 在内部,该函数将 ptr 指向的块解释为类型为 unsigned char 的 (size*count) 个元素的数组,并按顺序将它们写入流中,就像对每个字节调用了 fputc 一样。


#include<stdio.h>
struct S
{
  int a;
  double d;
};
int main()
{
  struct S s = { 520,13.14 };
  FILE* pf = fopen("data.txt", "wb");//二进制打开文件
  if (!pf)
  {
    perror("fopen");
    return 1;
  }
  //写文件 - 输出
  //size_t fwrite(const void* ptr, size_t size, size_t count, FILE * stream);
  fwrite(&s, sizeof(struct S), 1, pf);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}


输出:二级制文件



二进制输入:



size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );


  • 从流中读取 count 个元素,每个元素大小为 size 字节,并将它们存储在由 ptr 指定的内存块中。
  • 流的位置指示器会根据成功读取的总字节数向前推进。
  • 如果成功读取,总共读取的字节数为 (size*count)。
#include<stdio.h>
struct S
{
  int a;
  double d;
};
int main()
{
  struct S s = { 0 };
  FILE* pf = fopen("data.txt", "rb");//二进制读出文件
  if (!pf)
  {
    perror("fopen");
    return 1;
  }
  //读文件 - 输入
  //size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
  fread(&s, sizeof(struct S), 1, pf);
  printf("%d %lf", s.a, s.d);
  //关闭文件
  fclose(pf);
  pf = NULL;
  return 0;
}


运行结果:



4.2 对比一组函数:


int sscanf ( const char * s, const char * format, ...);


  • 从字符串 s 中读取数据,并根据参数 format 将其存储到附加参数所指向的位置,就像使用 scanf 一样,但是从字符串 s 而不是标准输入(stdin)读取。
  • 附加参数应该指向已经分配的对象,其类型由 format 字符串中对应的格式说明符指定。


int sprintf ( char * str, const char * format, ... );


  • 该函数将以与使用 printf 时相同的文本组成一个字符串,但不会将其打印,而是将内容存储为 C 字符串,存放在由 str 指向的缓冲区中。
  • 缓冲区的大小应足够大,以容纳整个结果字符串(请参阅更安全的版本 snprintf)。
  • 内容后会自动追加一个终止空字符。
  • 在 format 参数之后,该函数期望至少有足够的附加参数以满足 format 的需求。


#include<stdio.h>
struct S
{
  int a;
  double d;
  char arr[10];
};
int main()
{
  struct S s = { 12,3.14,"hello" };
  char str[100];
  struct S temp = { 0 };
  //int sprintf ( char * str, const char * format, ... );
  sprintf(str, "%d %lf %s", s.a, s.d, s.arr);
  printf(str);
  //int sscanf ( const char * s, const char * format, ...);
  sscanf(str, "%d %lf %s", &(temp.a), &(temp.d), &(temp.arr));
  printf("%d %lf %s\n", temp.a, temp.d, temp.arr);
  return 0;
}


  1. scanf, fscanf, sscanf:


scanf: 从标准输入(键盘)读取数据,并根据指定的格式进行解析,将数据存储到给定的变量中。

fscanf: 从指定的文件流中读取数据,并根据指定的格式进行解析,将数据存储到给定的变量中。

sscanf: 从指定的字符串中读取数据,并根据指定的格式进行解析,将数据存储到给定的变量中。


  1. printf, fprintf, sprintf:


printf: 将格式化的数据输出到标准输出(屏幕)。

fprintf: 将格式化的数据输出到指定的文件流。

sprintf: 将格式化的数据输出到指定的字符串缓冲区。


总结区别:


scanf, fscanf, sscanf 主要用于输入操作,从不同来源(标准输入、文件、字符串)读取数据。

printf, fprintf, sprintf 主要用于输出操作,将格式化的数据输出到不同的目标(标准输出、文件、字符串缓冲区)中。


5. 文件的随机读写


5.1 fseek - 根据文件指针的位置和偏移量来定位文件指针。


int fseek ( FILE * stream, long int offset, int origin );


stream:指向标识流的 FILE 对象的指针。


offset:


  • 二进制文件:从 origin 确定的位置偏移的字节数。
  • 文本文件:要么为零,要么为 ftell函数 返回的值。


origin:用作偏移参考的位置。


  • SEEK_SET 文件开头
  • SEEK_CUR 文件指针的当前位置
  • SEEK_END 文件末尾
#include <stdio.h>
int main()
{
  FILE* pFile;
  pFile = fopen("example.txt", "wb");
  fputs("This is an apple.", pFile);///写文件 - 输出
  fseek(pFile, 9, SEEK_SET);//从起始位置开始偏移
  //fseek(pFile, -8, SEEK_END);//从起始位置开始偏移
  //偏移量为9的字符串换为 sam
  fputs(" sam", pFile);///写文件 - 输出
  fclose(pFile);
  pFile = NULL;
  return 0;
}


运行结果:



【文件操作:解锁高效读写与管理技巧】(下):https://developer.aliyun.com/article/1424833

相关文章
|
7月前
|
监控 安全 Linux
Qt 文件类实战:解锁文件操作的无限可能
Qt 文件类实战:解锁文件操作的无限可能
320 1
|
7月前
|
存储 C语言
【文件操作:解锁高效读写与管理技巧】(下)
【文件操作:解锁高效读写与管理技巧】
|
4月前
|
存储 Java 数据库连接
BIO阻塞IO流与数据存储大揭秘:性能与资源消耗,一文让你彻底解锁!
【8月更文挑战第25天】本文探讨了Java中BIO阻塞IO流与数据存储的概念及其实现。BIO作为一种传统IO模型,在处理每个客户端请求时需创建新线程并等待响应,这在并发量大时会导致性能下降和高资源消耗。示例代码展示了如何利用`ServerSocket`实现基于BIO的简单服务器。此外,文章还介绍了数据存储的基本方法,例如通过`BufferedWriter`向文件写入数据。两者对比显示,BIO适合连接数稳定的场景,而数据存储则适用于需要持久化保存信息的情况。通过这些分析和实例,希望能帮助读者更好地掌握这两种技术的应用场景及其优缺点。
51 0
|
SQL 开发框架 .NET
一个超级大的文件如何更快读
# 一个超级大的文件如何更快读 问题起因 ![](https://img2023.cnblogs.com/blog/2415052/202306/2415052-20230608110517159-989018809.png) 一个有千万的数据的txt文件如何发挥IO的全部性能更快的读和写。 ## 方案一 使用ChatGPT4的方案 在C#中,我们可以使用多线程来处理大量的数据并将其写入数据库。在处理大数据时,我们需要将任务分解为多个子任务,这样我们可以在不同的线程中并行执行它们以提高性能。 这里是一种可能的解决方案,使用了`Task Parallel Library (TPL
94 0
一个超级大的文件如何更快读
|
7月前
|
存储 监控 API
【C/C++ 文件操作】深入浸润:C++多线程文件操作的艺术与策略
【C/C++ 文件操作】深入浸润:C++多线程文件操作的艺术与策略
384 0
|
7月前
|
存储 编译器 C语言
【文件操作:解锁高效读写与管理技巧】(上)
【文件操作:解锁高效读写与管理技巧】
|
自然语言处理 监控 C#
应用程序DDE读组态王的数据
应用程序DDE读组态王的数据
|
API C语言 C++
C++文件操作的5种方式
C++文件操作的5种方式
158 1
文件IO操作的一些练习小案例
文件IO操作的一些练习小案例
148 0
|
Windows
文件操作管理
文件操作管理
109 0
文件操作管理