我一直在寻找这个问题的答案,但我没有找到。我目前正在使用fstream
在标识为std::ios_base::in | std::ios_base::out | std::ios_base::binary
的硬盘上打开文件以进行随机访问。
文件中存在的数据是记录,每条记录的大小为16 bytes
。大约0.479604 seconds
将336.357 kb
个记录并行写入文件(两个线程)。我没有使用任何特定的策略来最佳地执行读写操作。没有线程,相同的操作花了0.352716 seconds
(时间差是预期的)。
这些是我用于执行读写操作的方法:
void FileBascIO::createFile(const std::string& fName) {
std::fstream fcreate(fName.c_str(), std::ios_base::out | std::ios_base::binary);
}
FileBascIO::returnTypeRead FileBascIO::readFromFile(const std::string& fName, int64_t pos,
FileFlagType relativeInitial, char* data, uint64_t size) {
std::fstream fio (fName.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
fio.seekg(pos, relativeInitial);
return fio.read(data, size);
}
FileBascIO::returnTypeWrite FileBascIO::writeToFile(const std::string& fName, int64_t pos,
FileFlagType relativeInitial, char* data, uint64_t size) {
std::fstream fio (fName.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
if (!fio) {
fio.close();
fio.clear();
createFile (fName);
fio.open(fName.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
}
fio.seekp(pos, relativeInitial);
return fio.write(data, size);
}
以上代码效率不高,我不知道如何提高效率。我做了一些搜索,我开始明白在执行操作之前,应该预先读取整个文件或文件的大块,并将其存储在RAM中。这是因为硬盘中数据的物理位置很重要。一旦字段更新,整个文件必须以大块写回硬盘。
在顺序写入16个字节的例子中,首先将数据首先存储在RAM存储器中并将其写入大块的文件中是不是更好?如果我手动执行此操作,我应该选择哪种块大小?什么是更有效地实现随机读/写访问的最佳替代方法?
修改
从以下评论中,解决此问题的最佳方法是使用文件的内存映射,并让操作系统处理所有优化内容,如@Sami Kuhmonen所指出的那样。我还没试过这个。另一个建议是不要像@ Jean-BaptisteYunès所指出的那样多次关闭和打开文件。应用该解决方案后,即使使用线程,代码也会在0.166191秒内运行。
更新后的来源:
标题
struct FstreamPtrContainer {
std::map <std::string, std::fstream*> fileStreamMap;
~FstreamPtrContainer();
};
struct FileBascIO{
static FstreamPtrContainer fileStreamContainer;
typedef decltype( ((std::fstream*) nullptr)->read((char*) nullptr, uint64_t() )) returnTypeRead;
typedef decltype( ((std::fstream*) nullptr)->write((char*) nullptr, uint64_t() )) returnTypeWrite;
typedef decltype( std::ios_base::beg ) FileFlagType;
static returnTypeRead readFromFile (const std::string& fName, int64_t pos,
FileFlagType relativeInitial, char* data, uint64_t size);
static returnTypeWrite writeToFile (const std::string& fName, int64_t pos,
FileFlagType relativeInitial, char* data, uint64_t size);
static void createFile (const std::string& fName);
static void flushAll();
};
在cpp文件中
FstreamPtrContainer::~FstreamPtrContainer() {
for (auto it : fileStreamMap){
it.second->close();
delete it.second;
}
}
FstreamPtrContainer FileBascIO::fileStreamContainer;
void FileBascIO::createFile(const std::string& fName) {
std::fstream fcreate(fName.c_str(), std::ios_base::out | std::ios_base::binary);
}
void FileBascIO::flushAll() {
for (auto it : fileStreamContainer.fileStreamMap) {
it.second->flush();
}
}
FileBascIO::returnTypeRead FileBascIO::readFromFile(const std::string& fName, int64_t pos,
FileFlagType relativeInitial, char* data, uint64_t size) {
auto it = fileStreamContainer.fileStreamMap.find(fName);
std::fstream* fio;
if (it == fileStreamContainer.fileStreamMap.end()) {
fio = new std::fstream (fName.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
fileStreamContainer.fileStreamMap [fName] = fio;
}
else {
fio = it->second;
fio->flush();
}
fio->seekg(pos, relativeInitial);
return fio->read(data, size);
}
FileBascIO::returnTypeWrite FileBascIO::writeToFile(const std::string& fName, int64_t pos,
FileFlagType relativeInitial, char* data, uint64_t size) {
auto it = fileStreamContainer.fileStreamMap.find(fName);
std::fstream* fio;
if (it == fileStreamContainer.fileStreamMap.end()) {
fio = new std::fstream(fName.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
if (!(*fio)) {
fio->close();
fio->clear();
createFile (fName);
fio->open(fName.c_str(), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
}
fileStreamContainer.fileStreamMap [fName] = fio;
} else{
fio = it->second;
fio->flush();
}
fio->seekp(pos, relativeInitial);
return fio->write(data, size);
}
现在执行时间几乎减半。