阅读文本文件和使用2D矢量

时间:2016-02-08 21:16:16

标签: c++

我使用下面的方法来读取大空格分隔的txt文件(大约900 Mb)。我花了879s将数据加载到内存中。我想知道是否有更有效的方法来读取txt文件?

另一个相关问题是:使用2D矢量存储这么大的数据集是个好主意吗?

这是我的代码

void Grid::loadGrid(const char* filePathGrid)
{
        // 2D vector to contain the matrix
        vector<vector<float>> data;

        unsigned nrows, ncols;
        double xllcorner, yllcorner;
        int cellsize, nodataValue;
        const int nRowHeader = 6;
    string line, strtmp;

    ifstream DEMFile;
    DEMFile.open(filePathGrid);
    if (DEMFile.is_open())
    {           
        // read the header (6 lines)
        for (int index = 0; index < nRowHeader; index++)
        {
            getline(DEMFile, line); 
            istringstream  ss(line);
            switch (index)
            {
                case 0: 
                    while (ss >> strtmp)
                    {                       
                        istringstream(strtmp) >> ncols;                     
                    }
                    break;
                case 1:
                    while (ss >> strtmp)
                    {
                        istringstream(strtmp) >> nrows;                     
                    }
                    break;
                case 2: 
                    while (ss >> strtmp)
                    {
                        istringstream(strtmp) >> xllcorner;                     
                    }
                    break;                  
                case 3:
                    while (ss >> strtmp)
                    {
                        istringstream(strtmp) >> yllcorner;                     
                    }
                    break;                      
                case 4:
                    while (ss >> strtmp)
                    {
                        istringstream(strtmp) >> cellsize;                      
                    }
                    break;                      
                case 5:
                    while (ss >> strtmp)
                    {
                        istringstream(strtmp) >> nodataValue;                       
                    }
                    break;                  
            }           
        }

        // Read in the elevation values
        if (ncols * nrows > 0)
        {       
            // Set up sizes. (rows x cols)
            data.resize(nrows);
            for (unsigned row = 0; row < nrows; ++row)
            {
                data[row].resize(ncols);
            }

            // Load values in   
            unsigned row = 0;
            while (row < nrows)
            {                           
                getline(DEMFile, line);
                istringstream ss(line);
                for (unsigned col =0; col < ncols; col++)
                {
                    ss >> data[row][col];
                }
                row ++;
            }
            DEMFile.close();            
        }       
    }
    else cout << "Unable to open file"; 
}

3 个答案:

答案 0 :(得分:3)

关于你的第二个问题:

我会选择使用一维向量,然后将其索引(row * ncols + col)。

这至少会减少内存消耗,但也可能对速度产生重大影响。

我不记得“矢量向量”是否是标准所认可的成语,但如果没有对“向量”的特殊处理,则存在过多的复制和内存重新分配的风险。矢量案例。

答案 1 :(得分:3)

与其他问题相比,答案并不多(这些问题不适合评论)。

观察:我认为如果不了解更多有关优化潜力的内容,很难回答矢量或其他更好的内存存储问题......一些与数据相关的问题就在那里。

关于时间的问题:

您是否可以修改时序逻辑以读取标题值,然后计算以下方案:

1) Read-only, just pull each line into memory.   Disable the the grid
      parsing & assignment part.  Goal to benchmark raw reads on file.
      Also no "resize" operations on your "data" member.
2) Memory allocation (just read the headers and "resize" the "data" member;
   don't loop through remainder of file).
3) Everything (code as-posted).

对我来说,读取1gb以下大小的文件将被操作系统缓存。
所以...
我鼓励你运行5次以上,看看后续运行是否一致。 (如果你没有检查它,看起来你可能会从一个小的改动到代码获得一个很大的加速,但实际上只是因为数据文件是由操作系统缓存而你的&#34;收益&# 34;随着下次重启而蒸发。

有关数据文件的问题......

换句话说,数据文件看起来像是网格中每个值的完整转储。

示例:除了6&#34;标题&#34;线条,100 x 200&#34;网格&#34;文件中将有100行,每行有200行。所以6 + 100 * 200 = 20,006行。

你提到了一个900 MB的数据文件。
我会做一些假设,只是为了它的乐趣。
如果您的值格式一致(例如&#34; 0.000000&#34; thru&#34; 1.000000&#34;),则表示每个值有8个字符。


假设简单的编码(每个字符1个字节),那么你就可以在900 MB中使用10,000 ^ 2网格。

忽略标题&#34; line&#34;和行尾delims(只会出现舍入错误):
1kb有1,024个字符
1mb有1,048,576个字符(1024 ^ 2) ▲900mb有943,718,400个字符(1024 ^ 2 * 900)
8个char元素值产生117,964,800个元素(1024 ^ 2 * 900/8)
大约是10,000 ^ 2网格(10,861来自sqrt(1024 ^ 2 * 900/8))。
这是否是中等接近,尺寸方面的?

您想要支持的最大数字网格元素是多少?百万?十亿?更多?

看起来像任何这样的&#34;限制&#34;将由产生数据文件的任何东西驱动。

有关数据值的问题

你在你的价值观中看到了什么样的分布?

你在价值观中看到了什么样的范围?

值是否始终为0.0000 - 1.0000?或者C ++浮点数的任何有效值?
你能产生价值的频率分布吗? 例如
计算下次构建Grid时Grid中有多少个不同的值?

这可能有助于找到您可以尝试优化的任何值?

也许许多网格元素是零,或1,或......?

如果是这样的话,你可能会考虑一种带有接口的稀疏矩阵方法,这种接口会给呼叫者带来错觉 完全实例化的网格(例如,不需要分配空间)。
我不知道&#34;稀疏矩阵&#34;的收支平衡点是什么?开始付清的方法。
(除非我对至少30%的网格元素有一个共同的值,否则我不会考虑。)

如果你正在操纵&#34; raw&#34;风格的图像,价值可能会到处都是。
如果你的价值观有一个模式,也许你可以利用它。 我想这将是一种数据压缩。

你能计算一个中点值并只存储偏移吗?
可以从网格坐标计算出值吗? (我猜不会)。

另一条评论(@MaruisBancila)提到二进制格式与字符格式。
很有道理。

从8个字符到4个字节的浮点数会将文件大小减半。

关于人们将如何处理网格的问题

填充网格后,&#34;用户&#34;做到了吗?
他们是在运营整个电网吗?
只是它的一部分? 你可以&#34;窗口&#34;在您的数据上使消费者满意并且只将一部分网格值加载到内存中?
(我猜不会,但从来没有伤害过要求)。

好的,这就是我能想到的所有问题。

答案 2 :(得分:2)

很棒的答案。使用二进制格式而不是纯文本会给我带来很好的性能提升。

我也有人发给我这个代码。我会玩更多的东西,拿出一个V2。

#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>

#include <deque>
#include <vector>

using namespace std;

/* ////////////////////////////////////////////////////////////////////////////
  timer stuff
//////////////////////////////////////////////////////////////////////////// */

//----------------------------------------------------------------------------
typedef double epoch_time_t;

//----------------------------------------------------------------------------
#ifdef __WIN32__

  #include <windows.h>

  epoch_time_t get_epoch_time()  // Since 1601 Jan 1
    {
    FILETIME f;
    GetSystemTimeAsFileTime( &f );
    LARGE_INTEGER t =
      { {
      f.dwLowDateTime,
      f.dwHighDateTime
      } };
    return t.QuadPart / 10000000.0;  // 100 nano-second intervals
    }

  void waitforkeypress()
    {
    WaitForSingleObject(
      GetStdHandle( STD_INPUT_HANDLE ),
      INFINITE
      );
    }

//----------------------------------------------------------------------------
#else // POSIX

  #include <sys/time.h>

  epoch_time_t get_epoch_time()  // Since 1970 Jan 1
    {
    struct timeval tv;
    if (gettimeofday( &tv, NULL )) return 0.0;
    return tv.tv_sec + tv.tv_usec / 1000000.0;
    }

  #include <unistd.h>
  #include <termios.h>
  #include <poll.h>

  #define INFINITE (-1)

  void waitforkeypress()
    {
    struct termios initial_settings;
    tcgetattr( STDIN_FILENO, &initial_settings );

    struct termios settings = initial_settings;
    settings.c_lflag &= ~(ICANON);
    tcsetattr( STDIN_FILENO, TCSANOW, &settings );

    struct pollfd pls[ 1 ];
    pls[ 0 ].fd     = STDIN_FILENO;
    pls[ 0 ].events = POLLIN | POLLPRI;
    poll( pls, 1, INFINITE );

    tcsetattr( STDIN_FILENO, TCSANOW, &initial_settings );
    }

#endif

//----------------------------------------------------------------------------
ostream& print_epoch_time( ostream& outs, epoch_time_t elapsed_time )
  {
  unsigned minutes    = (unsigned) elapsed_time        / 60;
  unsigned seconds    = (unsigned) elapsed_time        % 60;
  unsigned hundredths = (unsigned)(elapsed_time * 100) % 100;

  outs << "It took you "
       << setfill( '0' ) << minutes    << ":"
       << setw( 2 )      << seconds    << "."
       << setw( 2 )      << hundredths << endl;

  return outs;
  }

/* ////////////////////////////////////////////////////////////////////////////
  loading stuff
//////////////////////////////////////////////////////////////////////////// */

typedef vector <float>     container;
typedef deque  <container> container2;

//----------------------------------------------------------------------------
void load_at_once( const char* filename, string& result )
  {
  ifstream f( filename, ios::binary );
  result.assign( istream_iterator <char> ( f ), istream_iterator <char> () );
  }

//----------------------------------------------------------------------------
struct data_t
  {
  unsigned nrows;
  unsigned ncols;
  double   xllcorner;
  double   yllcorner;
  int      cellsize;
  double   nodatavalue;

  container2 data;
  };

void load_in_pieces( istream& f, data_t& data )
  {
  string s;
  f >> s >> data.ncols
    >> s >> data.nrows
    >> s >> data.xllcorner
    >> s >> data.yllcorner
    >> s >> data.cellsize
    >> s >> data.nodatavalue;
  data.data.resize( data.nrows );
  for (container2::iterator row = data.data.begin(); row != data.data.end(); ++row)
    {
    row->resize( data.ncols );
    for (container::iterator col = row->begin(); col != row->end(); ++col)
      {
      f >> *col;
      }
    }
  }

//----------------------------------------------------------------------------
int main()
  {
  epoch_time_t start, stop;
  string       raw_data;
  data_t       data;

  cout << "Please wait while loading...\n";
  start = get_epoch_time();
  load_at_once( "data.txt", raw_data );
  istringstream iss( raw_data );
  load_in_pieces( iss, data );
  stop = get_epoch_time();
  print_epoch_time( cout, stop - start );

  return 0;
  }