从文件中读取第n行的快速方法

2024-04-28

介绍

我有一个名为的 C++ 进程MyProcess我称之为nbLines时间、地点nbLines是一个名为的大文件的行数InputDataFile.txt在其中可以找到输入数据。例如调用

./MyProcess InputDataFile.txt 142

Inform MyProcess输入数据可以在该行找到142 of the InputDataFile.txt file.

Issue

问题是InputDataFile.txt如此之大(~ 150 GB)以至于搜索正确行的时间不可忽略。灵感形式这个帖子 https://stackoverflow.com/questions/7273326/getting-the-nth-line-of-a-text-file-in-c,这是我的(可能不是最佳的)代码

int line = 142;
int N = line - 1;
std::ifstream inputDataFile(filename.c_str());
std::string inputData;
for(int i = 0; i < N; ++i)
    std::getline(inputDataFile, inputData);

std::getline(inputDataFile,inputData);

Goal

我的目标是寻找inputData更快地MyProcess.

可能的解决方案

将每行第一个字符的索引与行号进行匹配会很方便bash。这样而不是给予142 to MyProcess,我可以直接给出感兴趣的第一个字符的索引。MyProcess然后可以直接跳转到这个位置,而不必搜索和计算 '\n' 字符。然后它会读取数据,直到遇到“\n”字符。这样的事情可行吗?如何实施?

当然,我欢迎任何其他可以减少导入这些输入数据的总体计算时间的解决方案。


正如其他答案中所建议的,构建文件映射可能是一个好主意。我这样做的方式(以伪代码)是:

let offset be a unsigned 64 bit int =0;

for each line in the file 
    read the line
    write offset to a binary file (as 8 bytes rather as chars)
    offset += length of line in bytes

现在您有一个“Map”文件,它是 64 位整数的列表(文件中的每一行一个)。要读取地图,您只需计算所需线路的条目在地图中的位置:

offset = desired_line_number * 8 // where line number starts at 0
offset2 = (desired_line_number+1) * 8

data_position1 = load bytes [offset through offset + 8] as a 64bit int from map
data_position2 = load bytes [offset2 through offset2 + 8] as a 64bit int from map

data = load bytes[data_position1 through data_position2-1] as a string from data.

这个想法是,您读取一次数据文件,并将字节偏移量记录在文件中每行开始的位置,然后使用固定大小的整数类型将偏移量顺序存储在二进制文件中。地图文件的大小应为number_of_lines * sizeof(integer_type_used)。然后,您只需通过计算存储行号偏移量的位置的偏移量来查找映射文件,并读取该偏移量以及下一行偏移量。从那里您可以得到数据应位于的数字范围(以字节为单位)。

Example:

Data:

hello\n 
world\n
(\n newline at end of file)

创建地图。

Map:每个分组[数字]将代表文件中的8字节长度

[0][7][14]
//or in binary
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000111
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00001110

现在假设我想要第 2 行:

line offset = 2-1 * 8 // offset is 8 

因为我们使用的是基于 0 的系统,所以它是文件中的第 9 个字节。因此,数字由字节 9 - 17 组成,它们是:

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000111
//or as decimal
7

现在我们知道 out 行应该从数据文件中的偏移量 7 开始(该偏移量以 1 为基数,如果我们从 0 开始计数,则为 6)。

然后我们执行相同的过程来获取下一行的起始偏移量,即 14。

最后我们查找字节范围 7-14(基数 1、6-13 基数 0)并将其存储为字符串并得到world\n.

C++实现:

#include <iostream>
#include <fstream>

int main(int argc, const char * argv[]) {
    std::string filename = "path/to/input.txt";

    std::ifstream inputFile(filename.c_str(),std::ios::binary);
    std::ofstream outfile("path/to/map/file.bin",std::ios::binary|std::ios::ate);

    if (!inputFile.is_open() || !outfile.is_open()) {
        //use better error handling than this
        throw std::runtime_error("Error opening files");
    }


    std::string inputData;
    std::size_t offset = 0;
    while(std::getline(inputFile, inputData)){
        //write the offset as binary
        outfile.write((const char*)&offset, sizeof(offset));
        //increment the counter
        offset+=inputData.length()+2;
        //add one becuase getline strips the \n and add one to make the index represent the next line
    }
    outfile.close();

    offset=0;

    //from here on we are reading the map
    std::ifstream inmap("/Users/alexanderzywicki/Documents/xcode/textsearch/textsearch/map",std::ios::binary);
    std::size_t line = 2;//your chosen line number
    std::size_t idx = (line-1) * sizeof(offset); //the calculated offset
    //seek into the map
    inmap.seekg(idx);
    //read the binary at that location
    inmap.read((char*)&offset, sizeof(offset));
    std::cout<<offset<<std::endl;

    //from here you just need to lookup from the data file in the same manor


    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从文件中读取第n行的快速方法 的相关文章

  • 如何使用 Entity Framework 和 Identity 解决对象处置异常 ASP.NET Core

    我正在尝试编写一个控制器 该控制器接收来自 AJAX 调用的请求并通过 DBContext 对数据库执行一些调用 但是 当我发出命令时var user await GetCurrentUserAsynch 在对 DBContext 的任何调
  • getline 之后返回到文件开头

    所以我已经从文件中读取了所有行 while getline ifile line logic 其中 ifile 是 ifstream line 是字符串 我的问题是我现在想再次使用 getline 并且似乎无法返回到文件的开头 因为运行 c
  • C# 中类似图的实现

    所以我有一个对象 我们称之为 Head 它有一个对象列表 C C1 C2 C3 T T1 T2 和 M M1 M2 并且所有这些都是相互关联的 例如 Head gt C1 C2 C3 T1 T2 M1 M2 T1 gt C1 C2 T2 g
  • 我可以将 char 或 DateTime 设置为 null 吗?

    我可以将 null 设置为char数据类型 并且DateTime在 C 中 多谢你们 这是不可能的 它是一个值类型 使用 char myChar null DateTime myDate null 这相当于 Nullable
  • 在 .NET Core 中从 HttpResponseMessage 转换为 IActionResult

    我正在将之前在 NET Framework 中编写的一些代码移植到 NET Core 我有这样的事情 HttpResponseMessage result await client SendAync request if result St
  • 如何使用 CUDA/Thrust 对两个数组/向量根据其中一个数组中的值进行排序

    这是一个关于编程的概念问题 总而言之 我有两个数组 向量 我需要对一个数组 向量进行排序 并将更改传播到另一个数组 向量中 这样 如果我对 arrayOne 进行排序 则对于排序中的每个交换 arrayTwo 也会发生同样的情况 现在 我知
  • 如何在 Visual Basic DLL 和 C++ DLL 之间创建隔离/免注册 COM?

    我必须在 C DLL 中使用 VB COM DLL 我弄清楚了如何从 C DLL 访问 VB COM DLL 并且它可以工作 现在我遇到了一个问题 我必须使用隔离的 COM 免注册 COM 因为我无法在必须使用它的每台 PC 上注册 DLL
  • C# 中的抽象类和接口类有什么不同?

    C 中的抽象类和接口类有什么不同 An 接口不是类 它只是一个contract定义了public一个类的成员must实施 抽象类只是一个类 您从中可以cannot创建一个实例 通常您会使用它来定义一个基类 该基类定义了一些virtual方法
  • 检测反射 DLL 注入

    在过去的几年中 恶意软件 以及一些渗透测试工具 如 Metasploit 的 meterpreter 负载 已经开始使用反射 DLL 注入 PDF http www harmonysecurity com files HS P005 Ref
  • 如何在 C++ 和 QML 应用程序中使用 qrc?

    我在 Windows7 上用 c qnd Qt Creator QML 编写了 Qt Quick Desktop 应用程序 现在 我必须部署它 并且我需要隐藏 qml 文件和图像 意味着 将它们放入资源等中 我读到有一个很好的方法可以使用
  • 检查两个函数或成员函数指针的签名是否相等

    我编写了一些代码来检查自由函数的签名是否等于成员函数的签名等 它比较提取的返回类型和函数参数 include
  • 列表到优先队列

    我有一个 C 大学编程项目 分为两个部分 在开始第二部分时应该使用priority queues hash tables and BST s 我 至少 在优先级队列方面遇到了麻烦 因为它迫使我自己重做第一部分中已经实现的许多代码 该项目是关
  • ASP.net WebForms - 在标记中使用 GetRouteUrl

    我一直在尝试弄清楚如何将路由功能与 ASP net 4 0 WebForms 一起使用 我将一条路线添加到我的路线集合中 void Application Start RegisterRoutes RouteTable Routes voi
  • Windows 上本机 C++ 应用程序中的自动死代码检测?

    背景 我有一个用原生 C 编写的应用程序 花了几年的时间 大约有 60 KLOC 有很多函数和类已经死了 可能有 10 15 就像下面提出的类似的基于 Unix 的问题 我们最近开始对所有新代码进行单元测试 并尽可能将其应用于修改后的代码
  • 在 C# .NET 中对非 ASCII 字符进行编码

    我想向我的应用程序发送的电子邮件添加自定义标头 标头名称只能包含 ASCII 字符 但对于值和用户可能会输入 UTF 8 字符 我必须对它们进行 Base64 编码 此外 我还必须将它们解码回 UTF 8 以便在 UI 中向用户显示它们 最
  • 从具有相同属性的另一个对象创建对象

    我有一个 C 对象 可以说有 20 个属性 它是数据契约的一部分 我还有另一个具有类似属性的业务实体 我想从响应对象中填充该实体 除了将一个对象的每个属性分配给另一个对象的相应属性之外 还有其他方法可以做到这一点吗 是的 看看自动映射器 h
  • 在 C# 命令行应用程序中包含并执行 EXE

    所以我找到了一个很棒的小 EXE 命令行应用程序 我们将其称为 program exe 它输出一些我想用 C 操作的数据 我想知道是否有一种方法可以将program exe 打包 到我的Visual Studio项目文件中 这样我就可以将编
  • 如何通过代理将套接字连接到http服务器?

    最近 我使用 C 语言编写了一个程序 用于连接到本地运行的 HTTP 服务器 从而向该服务器发出请求 这对我来说效果很好 之后 我尝试使用相同的代码连接到网络上的另一台服务器 例如 www google com 但我无法连接并从网络中的代理
  • 使用C标准数学库精确计算标准正态分布的CDF

    标准 C 数学库不提供计算标准正态分布 CDF 的函数 normcdf 然而 它确实提供了密切相关的函数 误差函数 erf 和互补误差函数 erfc 计算 CDF 的最快方法通常是通过误差函数 使用预定义常量 M SQRT1 2 来表示 d
  • 如何通过API退出Win32应用程序?

    我有一个使用 Win32 API 编写的 C Win32 应用程序 我希望强制它在其中一个函数中退出 有没有类似的东西Exit or Destroy or Abort 类似的东西会终止它吗 哎呀呀呀呀呀呀 不要做任何这些事情 exit 和

随机推荐