流成向量
Streaming into vector?
我偶然发现了这段代码,用于将文件的内容插入到vector中。似乎是一个有用的东西来学习如何做:
#include <iostream>
#include <fstream>
#include <vector>
int main() {
typedef std::vector<char> fileContainer;
std::ifstream testFile("testfile.txt");
fileContainer container;
container.assign(
(std::istreambuf_iterator<char>(testFile)),
std::istreambuf_iterator<char>());
return 0;
}
它工作,但我想问的是,这是最好的方式做这样的事情吗?也就是说,获取任意文件类型的内容并将其插入到适当的STL容器中。有没有比上面更有效的方法?据我所知,它创建了ifstream的testFile实例,并用testFile .txt的内容填充它,然后该副本再次通过分配复制到容器中。看起来抄袭很多?
至于速度/效率,我不确定如何估计文件大小并使用保留函数,如果我使用保留,它似乎会减慢这段代码的速度。目前,换出vector并使用deque似乎更有效一些。
我不确定是否有最好的方法,但是使用两个迭代器构造函数应该更习惯:
FileContainer container( (std::istreambuf_iterator<char>( testFile )),
(std::istreambuf_iterator<char>()) );
(我注意到您的assign
中有额外的括号。他们在这里不是必需的,但在使用构造函数时是必需的。)
考虑到性能,预分配会更有效数据,类似于:
FileContainer container( actualSizeOfFile );
std::copy( std::istreambuf_iterator<char>( testFile ),
std::istreambuf_iterator<char>(),
container.begin() );
这有点危险;如果你的估计太小,你就会遇到未定义的行为。为了避免这种情况,您还可以这样做:
FileContainer container;
container.reserve( estimatedSizeOfFile );
container.insert( container.begin(),
std::istreambuf_iterator<char>( testFile ),
std::istreambuf_iterator<char>() );
哪一个更快取决于实现;最后一个我测量的时间(用g++),第一个稍微快一点,但是如果你实际上从文件中读取,差异可能是不可测量的。
这两种方法的问题是,尽管有其他的答案,有找到文件大小的便携方法除了实际吗读取文件。对于某些系统(fstat
)存在不可移植的方法在Unix下),但在其他系统(如Windows)上,没有表示找到char
的确切数量,你可以从一个文本文件中读取。当然,也不能保证tellg()
的结果会甚至转换成整型,如果转换成整型,它们也不会做一个神奇的饼干,没有数字意义。
话虽如此,在实践中,tellg()
的使用建议其他海报通常是"可移植的"(Windows和大多数Unix)最少),结果往往会"足够接近";它们通常是在Windows下有点高(因为结果将计算)回车符(不会被读取),但在很多情况下,这不是什么大问题。最后,是由你来决定做什么你的要求是关于便携性和精度大小。
它创建一个ifstream的testFile实例,并用testFile .txt
的内容填充它。
不,它打开testfile.txt
并调用句柄testFile
。从磁盘到内存有一个拷贝。(除了I/O通常是通过内核空间的另一份拷贝来完成,但您不会以可移植的方式避免这种情况。)
至于速度/效率,我不知道如何估计文件大小和使用保留函数
如果文件是普通文件:
std::ifstream testFile("testfile.txt");
testFile.seekg(0, std::ios::end);
std::ios::streampos size = testFile.tellg();
testFile.seekg(0, std::ios::beg);
std::vector<char> container;
container.reserve(size);
然后像以前一样填充container
。或者将其构造为std::vector<char> container(size)
并用
testFile.read(&container.front, size);
哪一个更快应该通过分析来确定。
std::ifstream
不包含文件的内容,内容按需读取。这涉及到某种缓冲,因此文件将以k
字节的块读取。由于流迭代器是InputIterators
,因此首先在vector
上调用reserve
应该更有效;但前提是您已经有了这些信息,或者可以猜测出一个很好的近似值,否则您必须遍历文件内容两次。
人们更希望从文件中读取到字符串而不是vector。如果你能用这个,你可能想看看我对上一个问题的回答。
对第四个测试进行一个小的编辑,会得到这样的结果:
std::vector<char> s4;
file.seekg(0, std::ios::end);
s4.resize(file.tellg());
file.seekg(0, std::ios::beg);
file.read(&s4[0], s4.size());
我的猜测是,这应该使性能基本上与使用字符串的代码没有区别。根据您的编译器/标准库,这可能比您当前的代码要快得多(同样,请参阅计时结果,了解您可能看到的差异)。
还要注意,这提供了一点额外的能力来检测和诊断错误。例如,您可以通过比较s4.size()
和file.gcount()
(和/或检查file.eof()
)来检查是否成功读取了整个文件。这也使得通过限制您读取的数量来防止问题变得更容易一些,以防有人想看看当他们试图使用您的程序读取一个6tb的文件时会发生什么。
如果你想让它更有效率,肯定有更好的方法。您可以检查文件大小,预先分配向量和直接读取到向量的内存。一个简单的例子:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <iostream>
using namespace std;
int main ()
{
int fd = open ("test.data", O_RDONLY);
if (fd == -1)
{
perror ("open");
return EXIT_FAILURE;
}
struct stat info;
int res = fstat (fd, &info);
if (res != 0)
{
perror ("fstat");
return EXIT_FAILURE;
}
std::vector<char> data;
if (info.st_size > 0)
{
data.resize (info.st_size);
ssize_t x = read (fd, &data[0], data.size ());
if (x != info.st_size)
{
perror ("read");
return EXIT_FAILURE;
}
cout << "Data (" << info.st_size << "):n";
cout.write (&data[0], data.size ());
}
}
对于某些任务还有其他更有效的方法。例如,要复制文件而不向用户空间传输数据,您可以使用sendfile
等
它确实有效,而且很方便,但在许多情况下,这是一个坏主意。
例如,用户编辑文件中的错误处理。如果用户手工编辑了一个数据文件,或者它是从具有松散字段定义的电子表格甚至数据库中导入的,那么这种填充向量的方法将导致一个没有细节的简单错误。
为了处理文件并报告发生错误的,您需要逐行读取它,并尝试在每行上转换为数字。然后可以报告转换失败的行号和文本。这非常有用。如果没有这个特性,用户就会怀疑是哪一行引起了问题,而不是能够立即修复它。- 写入向量<向量<bool>>
- 函数向量_指针有不同的原型,我可以构建一个吗
- std::向量与传递值的动态数组
- 将值指定给向量(2D)的向量中的某个位置
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 如何使用向量的template_back函数
- 尝试通过多个向量访问变量时,向量下标超出范围
- 如何通过派生类函数更改基类中的向量
- C++从另一个类访问公共静态向量的正确方法是什么
- 如何将ampl中的集合表示为c++中的向量
- 变量没有改变?通过向量的函数调用
- 迭代时从向量和内存中删除对象
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 计算排序向量的向量中唯一值的计数
- 矩阵向量乘法(cublasDgemv)返回零
- 一对向量构造函数:初始值设定项列表与显式构造
- 将结构向量排序为子组
- 在C++中调整向量中的索引
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么