[英]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
。
現在,唯一的障礙是ostream
或basic_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::map
或std::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::vector
或std::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.