繁体   English   中英

如何在不关闭它们的情况下切换fstream文件(同时输出文件) - C ++

[英]How can I switch between fstream files without closing them (Simultaneous output files) - C++

我有一点C ++问题,我无法通过在线浏览解决。 这是我的代码(摘录):

if(File.is_open()) {
    while(!File.eof())  {
        i++;
        getline(File,Line);
        if(i>=2) {                //Skip Headers
            int CharCount=0;
            for(int CharPosition=0; CharPosition<Line.size(); CharPosition++)                       {
                if(Line[CharPosition]==',') {
                    Length=CharPosition;
                    break;
                }
            }
            NameText=Line.substr(0,Length);
            Path= Path_Folder + "\\" + NameText + ".csv";
            if(!CheckExistance(Path.c_str())) {
                fstream Text_File;
            }
            Text_File.open(Path, fstream::in | fstream::out | fstream::app);
            Text_File<<Line<<"\n";
            Text_File.close();
        }
    }
}

这段代码工作正常,但我想改变它每次进入while循环时关闭Text_File的事实。

基本上,这个程序在很多较小的文件中分割出一个大的输入文件。 随着我的小文件变得越来越大,执行越来越慢(正常)。 我的目标是让所有较小的文件( Text_File )在这个while循环中打开,然后将fstream指针(指针?)从一个切换到另一个。

我试图改变为:

...

NameText=Line.substr(0,Length);
Path= Path_Folder + "\\" + NameText + ".csv";

if(!CheckExistance(Path.c_str())) {
    fstream Text_File;
}

if(!Text_File.open()) {
    Text_File.open(Path, fstream::in |fstream::out | fstream::app);
}

Text_File<<Line<<"\n";
\\Text_File.close();

...

但无论NameText是什么,它都在使用相同的Text_File 所以我猜测fstream Text_File的指针不会改变。 那我需要做什么? 把指针放在一边? 怎么样?

谢谢你们!

不确定它是否相关,但我正在使用Microsoft Visual C ++ 2010 Express。 另外,我既不是教育也不是生活的程序员,所以如果你能用不太先进的词语来解释它,我会很感激。

看起来你想要在ostream对象上处理filebuf

现在,唯一的障碍是ostreambasic_filebuf<char>不是可复制类型,因此您不能直接将它们放入地图(通过文件名)。 通过创建一个小型Holder类型可以轻松解决这个问题:

struct Holder {
    Holder(std::string const& path) 
        : buf(std::make_shared<std::filebuf>())
    { 
        buf->open(path.c_str(), std::ios::out | std::ios::app);
    }
    std::shared_ptr<std::filebuf> buf;
};

std::map<std::string, Holder> buffers;

现在,完整的程序(已测试)将如下所示:

#include <fstream>
#include <sstream>
#include <iostream>
#include <map>
#include <memory>

const std::string Path_Folder = ".";

int main()
{
    std::istream& File     = std::cin; // just for example
    std::filebuf  dummy;
    std::ostream  TextFile(&dummy);

    struct Holder {
        Holder(std::string const& path) 
            : buf(std::make_shared<std::filebuf>())
        { 
            buf->open(path.c_str(), std::ios::out | std::ios::app);
        }
        std::shared_ptr<std::filebuf> buf;
    };

    std::map<std::string, Holder> buffers;
    int i = 0;

    std::string   Line;
    while(getline(File, Line))
    {
        if (i++<2)
            continue; //Skip Headers

        auto NameText = Line.substr(0, Line.find(','));
        auto Path = Path_Folder + '/' + NameText + ".csv";

        // open, only if not allready opened
        auto found = buffers.find(NameText);
        if (end(buffers) == found)
            found = buffers.insert({ NameText, Path }).first;

        TextFile.rdbuf(found->second.buf.get());

        TextFile << Line << std::endl; // notice implicit std::flush in std::endl
    }

    // all files are automatically closed here
}

还有三个笔记:

  • buffers映射超出范围时,文件会自动关闭。
  • 你可能需要在切换这样的rdbuf()时添加显式刷新,如果你不使用隐式std::flush结束你的行(就像使用std::endl )。
  • dummy只存在一个我们可以切换缓冲区的ostream对象

我用以下输入测试了这个:

Header Row #1
Header Row #2
Jack,1,some data
Jill,2,some more data
Jack,3,not reopening :)
Jill,4,jill still receiving output
Romeo,5,someone else reporting

现在,我得到了以下输出: 在Coliru看到它

/tmp$ rm *.csv
/tmp$ make && ./test < input.txt && tail *.csv

g++ -std=c++11 -Wall -g test.cpp -o test
==> Jack.csv <==
Jack,1,some data
Jack,3,not reopening :)

==> Jill.csv <==
Jill,2,some more data
Jill,4,jill still receiving output

==> Romeo.csv <==
Romeo,5,someone else reporting

注意:看起来你的Text_File超出了范围。 我猜你在代码中的其他地方声明了它。 所以,这条线是没用的:

if(!CheckExistance(Path.c_str())){fstream Text_File;}

要访问多个文件流,您可以使用这个使用std :: map数据结构的简单类:

#include <iostream>
#include <map>
#include <string>
#include <fstream>

class StreamWriter
{
    typedef std::map<std::string, std::fstream> StreamMap;
    static StreamMap Files;

public:
    static std::fstream& GetFile(const std::string& filename)
    {
        std::fstream& stream = Files[filename];
        if (!stream.is_open())
        {
            stream.open(filename, std::fstream::in
                   | std::fstream::out | std::fstream::app);
        }
        return stream;
    }
};

StreamWriter::StreamMap StreamWriter::Files = StreamWriter::StreamMap();

然后,访问文件就像下面这样简单:

StreamWriter::GetFile("C:/sample1.txt") << "test";

而已。

我要做的是使用std::mapstd::unordered_map将名称映射到fstream对象。

map<string, fstream> files;

...

while(getline(File,Line)) // don't use while(File.eof())
{
    ...

    if( files.count(NameText) == 0 ) // checks for the existence of the fstream object
    {            
        files[NameText].open(Path, fstream::in | fstream::out);
    }

    files[NameText] << Line << "\n";
}

请参阅此处了解为什么我更改了while循环的条件。


您的操作系统可能无法同时拥有多个打开的文件。 也许你可以尝试这样的事情。

在地图旁边,保留打开的文件名称列表。 每次需要写入文件时,首先在列表中搜索它,将其删除并将其添加到列表的前面。 如果不存在,只需将其添加到列表的前面即可。 检查以确保文件已打开。 如果不是,那么试着打开它。 如果打开它失败,则逐个删除列表后面的项目,关闭该项目的相应文件,并尝试再次打开当前文件。 重复,直到打开文件成功。

这样做可确保最常写入文件的文件保留在列表的前面并保持打开状态。 编写频率较低的文件会移到后面,最终会被关闭。 在列表中搜索文件不是最佳的(O(n)),但由于我们在这里处理文件写入,这是一个更昂贵的操作,你不应该注意到任何类型的性能。

您正在尝试重用 Text_File fstream。 为此,在完成写入csv文件后,必须执行close()来刷新流。 请看这个问题: C ++可以重用fstream来打开和写入多个文件吗?

另外:这是我在谷歌搜索这个问题: http//goo.gl/Oy5KKM

请注意, Text_File是一个变量,就像所有变量一样,您可以拥有多个具有相同类型的变量。 如果您需要管理多个不同的文件,甚至可以在任何标准容器中使用std::fstream ,例如std::vectorstd::map 此外,您应该考虑将代码分解为更小,更易于管理的部分。 例如,您可以创建一个以std::fstream&作为参数的函数。 这允许程序的其余部分控制在任何给定时间使用哪个std::fstream& 我强烈建议您查看不同的设计选项以帮助组织代码。

存在检查语句没有效果 - 如前所述。 也许你打算做这样的事情:

if(!CheckExistance(Path.c_str())) {
    fstream Text_File;

    Text_File.open(Path, fstream::in | fstream::out | fstream::app);
    Text_File<<Line<<"\n";
    Text_File.close();
}

if语句范围内的fstream将隐藏外部作用域中必须具有的那个。 此外,close是可选的 - 当流超出范围时,流将被关闭。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM