问题描述
|
我四处张望,没有找到关于如何从C ++文件中读取特定文本行的明确答案。我有一个文本文件,其中包含超过100,000个英语单词,每个单词单独一行。我不能使用数组,因为它们显然不会保存那么多数据,并且向量花费太长时间来存储每个单词。我该如何实现?
附言我没有发现与C ++有关的这个问题的重复项
while (getline(words_file,word))
{
my_vect.push_back(word);
}
编辑:
下面的评论者帮助我意识到,将文件加载到向量中的时间如此之长是因为我正在调试。正常运行.exe几乎立即会加载文件。谢谢大家的帮助。
解决方法
如果您的单词没有空格(我想他们没有),您可以使用更复杂的非Getline解决方案,使用
deque
!
using namespace std;
int main() {
deque<string> dictionary;
cout << \"Loading file...\" << endl;
ifstream myfile (\"dict.txt\");
if ( myfile.is_open() ) {
copy(istream_iterator<string>(myFile),istream_iterator<string>(),back_inserter<deque<string>>(dictionary));
myfile.close();
} else {
cout << \"Unable to open file.\" << endl;
}
return 0;
}
上面的代码将整个文件读入一个字符串,然后根据默认值std::stream
(任何空格-这对我来说是一个很大的假设)对字符串进行标记化,从而使其速度稍快。大约2-3秒完成100,000个单词。我还使用了deque
,它是此特定情况下的最佳数据结构(imo)。当我使用向量时,它需要大约20秒的时间(甚至不接近您的分钟标记-您必须做其他会增加复杂性的事情)。
要访问第1行的单词:
cout << dictionary[0] << endl;
希望这是有用的。
, 您有几种选择,但是没有一种会自动让您转到特定的行。文件系统不跟踪文件中的行号。
一种方法是在文件中使用固定宽度的行。然后根据所需的行号和每行的字节数读取适当的数据量。
另一种方法是循环,一次读取一行,直到到达所需的行。
第三种方法是在文件的开头创建一种索引来引用每一行的位置。当然,这将需要您控制文件格式。
, 我已经在评论中提到了这一点,但我想让遇到此问题的其他人更加了解...
我认为下面的代码需要很长时间才能从文件中读取,因为ѭ6可能必须多次重新分配其内部存储器才能解决您添加的所有这些元素。这是一个实现细节,但是如果我理解正确的话,ѭ6通常会很小,并根据需要增加其内存以容纳新元素。一次添加少量元素时,这种方法效果很好,但是一次添加一千个元素时,效率却很低。
while (getline(words_file,word)) {
my_vect.append(word); }
因此,在运行以上循环之前,请尝试使用my_vect(100000)
(带有指定元素数的构造函数)初始化向量。这迫使std::vector
提前分配足够的内存,这样以后就不必再洗了。
,这个问题非常不清楚。您如何确定具体
线?如果是第n行,最简单的解决方案就是调用
getline
n次,扔掉除最后一个结果以外的所有结果;呼唤
ignore
n-1次可能会快一点,但我怀疑如果
您总是读入相同的字符串(而不是构造一个
每次都更新一次),时间上的差异不会很大。如果你
还有其他条件,文件确实很大(从您的
描述(不是)并进行排序,则可以尝试使用二进制搜索,
寻求文件的中间,请提前阅读以找到
下一行的开始,然后根据其决定下一步
值。 (我已使用它在日志文件中查找相关条目。但是
我们正在谈论的文件大小为几千兆字节。)
如果您愿意使用系统相关代码,则可能会有所帮助
内存映射文件,然后搜索\'\\ n \'的第n个出现位置
(std::find
n次)。
添加:只是一些快速基准测试。在我的Linux机器上,获取
/usr/share/dict/words
起的第100000个字(479623个字,每行一个,
在我的机器上),大约需要
272毫秒,读取所有单词
变成std::vector
,然后索引,
256毫秒执行相同操作,但是
加上std::deque
30毫秒,使用getline
,但是
只是忽略结果,直到
我感兴趣的一个
20毫秒使用
istream::ignore
,以及
使用mmap
和6毫秒
在std::find
上循环播放。
FWIW,每种情况下的代码是:
对于std ::容器:
template<typename Container>
void Using<Container>::operator()()
{
std::ifstream input( m_filename.c_str() );
if ( !input )
Gabi::ProgramManagement::fatal() << \"Could not open \" << m_filename;
Container().swap( m_words );
std::copy( std::istream_iterator<Line>( input ),std::istream_iterator<Line>(),std::back_inserter( m_words ) );
if ( static_cast<int>( m_words.size() ) < m_target )
Gabi::ProgramManagement::fatal()
<< \"Not enough words,had \" << m_words.size()
<< \",wanted at least \" << m_target;
m_result = m_words[ m_target ];
}
对于不保存的getline
:
void UsingReadAndIgnore::operator()()
{
std::ifstream input( m_filename.c_str() );
if ( !input )
Gabi::ProgramManagement::fatal() << \"Could not open \" << m_filename;
std::string dummy;
for ( int count = m_target; count > 0; -- count )
std::getline( input,dummy );
std::getline( input,m_result );
}
对于ignore
:
void UsingIgnore::operator()()
{
std::ifstream input( m_filename.c_str() );
if ( !input )
Gabi::ProgramManagement::fatal() << \"Could not open \" << m_filename;
for ( int count = m_target; count > 0; -- count )
input.ignore( INT_MAX,\'\\n\' );
std::getline( input,m_result );
}
而对于mmap
:
void UsingMMap::operator()()
{
int input = ::open( m_filename.c_str(),O_RDONLY );
if ( input < 0 )
Gabi::ProgramManagement::fatal() << \"Could not open \" << m_filename;
struct ::stat infos;
if ( ::fstat( input,&infos ) != 0 )
Gabi::ProgramManagement::fatal() << \"Could not stat \" << m_filename;
char* base = (char*)::mmap( NULL,infos.st_size,PROT_READ,MAP_PRIVATE,input,0 );
if ( base == MAP_FAILED )
Gabi::ProgramManagement::fatal() << \"Could not mmap \" << m_filename;
char const* end = base + infos.st_size;
char const* curr = base;
char const* next = std::find( curr,end,\'\\n\' );
for ( int count = m_target; count > 0 && curr != end; -- count ) {
curr = next + 1;
next = std::find( curr,\'\\n\' );
}
m_result = std::string( curr,next );
::munmap( base,infos.st_size );
}
在每种情况下,代码都将运行
, 您可以寻找一个特定的位置,但这要求您知道生产线的起点。 100,000个单词的“不到一分钟”听起来对我来说确实很慢。
, 读取一些数据,计算换行符,丢弃这些数据,再阅读更多内容,再次计数换行符...然后重复直到您已阅读足够的换行符以达到目标。
同样,正如其他人所建议的那样,这也不是访问数据的特别有效的方法。索引会为您服务。