C++文件的读写和对多行多个字符串的处理

本文介绍了C++中处理文件读写,特别是读取和处理含有多个字符串的行的方法,强调了使用stringstream进行逐行读取和分割字符串的便捷性。同时,文章还提及了在读写过程中遇到的常见问题,如行首尾的处理和文件结束的判断。此外,作者还简要提及了自己实现的快速排序算法。

C++读写文件中的字符串

今天帮人做了个简单的作业,没想到花时间最多的不是算法而是文件的读写,还有对读入字符串的分割处理。晚上写作业的时候又用到了对字符串的处理,这里记录一下。
小白第一次写博客,做的不好的请多多指正。

题目如下:

Retail.dat文件中包含了某零售商店M的8万多条真实(16,470种)商品的销售记录(每行对应一条销售记录),现M店装修,需要把这些商品摆放在一个单行长柜中,如下:
… k K+1 K+2 …
其中每个格子仅放一种商品,且商店左右两侧各有一个门,顾客从左门进入挑选商品,并在把所有商品都加入购物篮后可以马上结帐从右门离去。注意顾客每次可能需要买多种商品,我们把顾客从进门选货到选完所有货物所经过的格子总数作为他的“购物不便程度”(以下简称“不便度”)度量,如:设顾客从左侧(格子编号从1开始)进入商店,他所需的货物分别摆放在101, 103, 210三个格子上,则该顾客的不便度为210。
请根据商品的历史销售记录,为装修后的M店设计一个合适的商品布局顺序,使得Retail.dat中所有顾客的总的不便度尽可能的小,并请编码实现和验证你的模型。程序的输入/输出要求描述如下:
输入:Retail.dat 文件
输出:Layout.dat 文件。该文件总共有16,470行,第2行至最后一行每行包含如下内容:
商品编号, 格子编号
如 “123,1”表示第123号商品应该摆放在第一个格子里面。
Layout.dat 文件的第一行是Retail.dat中所有购买记录在你的模型下的不便度的总和。


读入:从硬盘读入内存ifstream

首先将文件流对象与文件建立连接

  • 注意这里判别是否打开失败很重要
    我第一次做的时候文件根本没有读取到,但是我完全不知道。
    把作业给朋友朋友也没有把文件放到同一位置,做一个简单的检验是有必要的。
string fileName = "retail.dat";
in.open(fileName.data(), ios::in);   //将文件流对象与文件连接起来
assert(in.is_open()); //如果打开失败,这里会终止运行

  • 要求读入文件中的全部数字,文件中数字的存储方式为:在这里插入图片描述
    因为文件的输入输出都是以字符串的形式,我面对的问题是:如何读取文件中的每一个字符串并将他们转换成数字
    这里可以提一下我踩过的坑(首先我没有试过二进制读取和定义指针的读取):

    1. 行末和行初会无法读入
       string filename;  
      string line;  
         while (getline (in, line)) // line中不包括每行的换行符  
          {
         
            
              cout << line << endl;  
          }  
      }  
    
    2. 直接用EOF判定文件末尾的,问题都是最后一行无法读入或无法停止循环
     ifstream FILE("test.txt");
      while (FILE.peek() != EOF)//修改
      {
         
         
          FILE.get(c);
          cout << c;
      }    
    
    3.试图直接逐个读取,但实际上行末或者行初会无法读入
    string buffer;
    fstream in;
    in.open("com.txt",ios::in);
    while(!in.eof())
    {
         
         
        in.getline(buffer,256,'\n');// 表示该行字符达到256个或遇到换行就结束
    }
    
    4.还有各种一边读入一边转换的骚操作,下次要一边尝试一边记录错误的经历

总而言之,最简单的做法应该是,逐行读取,在再提取空格,将单个字符串转换为数字。
注意这里用到了stringstream来再次读取从getline中读到的每一行,自动跳过空格。

stringstream ss(buffer);

这部分实现的代码如下:

	string fileName = "retail.dat";

	ifstream in;
	in.open(fileName.data(), ios::in)
处理大型 CSV 文件时,性能内存效率是关键因素。传统的逐行读取方式(如使用 `std::getline` `std::istringstream`)虽然简单,但在处理大规模数据时可能不够高效。为提高效率,可以采用以下方法: ### 使用内存映射文件进行读取 内存映射文件技术可将整个文件映射到进程的地址空间,从而避免频繁的系统调用开销。在 C++ 中,可以通过平台相关的 API(如 Linux 上的 `mmap` 或 Windows 上的 `CreateFileMapping`)实现该功能。这种方式特别适用于只读操作,能够显著提升大文件读取速度[^2]。 ### 缓冲区优化与批量处理读取或写入 CSV 数据时,应尽量减少 I/O 操作次数。可以通过设置较大的缓冲区来实现这一点。例如,使用 `std::ifstream` 时,可以通过 `rdbuf()->pubsetbuf()` 方法设置自定义缓冲区;在写入时,使用 `std::ofstream` 的 `rdbuf()->pubsetbuf()` 同样能提升性能。此外,对于解析逻辑,建议一次性读取多行并批量处理,以降低函数调用字符串操作的开销[^2]。 ### 使用高效的字符串分割算法 针对包含逗号的字段,CSV 文件通常使用双引号包裹字段内容。解析时需识别出被引号包围的部分,并跳过其中的逗号。一种高效的实现方式是通过状态机机制:逐字符读取,根据当前是否处于引号内部决定如何处理逗号。这种方式避免了多次创建临时字符串对象,提高了处理效率。 以下是一个基于状态机的 CSV 解析示例: ```cpp #include <vector> #include <string> #include <fstream> #include <sstream> std::vector<std::vector<std::string>> read_csv(const std::string& filename) { std::ifstream file(filename); std::vector<std::vector<std::string>> data; std::string line; while (std::getline(file, line)) { std::vector<std::string> row; std::string field; bool in_quotes = false; for (size_t i = 0; i < line.size(); ++i) { char c = line[i]; if (c == '"') { in_quotes = !in_quotes; } else if (c == ',' && !in_quotes) { row.push_back(field); field.clear(); } else { field += c; } } row.push_back(field); data.push_back(row); } return data; } ``` 该实现通过维护一个布尔变量 `in_quotes` 来判断当前是否处于引号包裹的字段中,从而正确处理字段内的逗号分隔符。 ### 并行化与异步 I/O 对于极大规模的 CSV 文件,可以考虑将文件划分为多个部分并行处理。例如,使用多线程分别解析不同的文件段落,或者利用异步 I/O 技术在后台执行读写操作,从而避免主线程阻塞。现代 C++ 提供了 `<thread>` `<future>` 等并发支持库,可用于构建高性能的数据处理流水线。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值