想法来源
由于在很多时候, 我们针对文件的操作都是针对于行进行的,尤其是只想根据某个文件的某一行或多行内容进行修改,这个时候就需要一个以行为单位进行文件管理的工具了,本文就是介绍了其中的某种实现
行操作需要考虑的问题
- 从文件加载所有行(load)
- 尾部追加行(append)
- 中间插入一行或多行(insert)
- 移除某一行或多行(remove)
- 读取某一行
- 修改某一行
- 遍历所有行(for)
- 获取总行数
- 保存更新后的行到文件
使用例程
/**
* usage example
*/
int main(int argc, char **argv)
{
FileLines lines("./test.txt");
std::cout << lines.tostring() << std::endl;
lines.append("4: 0987654321");
lines.save();
lines.refresh();
std::cout << lines.tostring() << std::endl;
return 0;
}
实现源码:
接口定义
/**
* filelines.h
*/
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
class FileLines
{
public:
FileLines();
explicit FileLines(const std::string& path);
/**
* @brief refresh
* @return
*/
bool refresh();
/**
* @brief refresh
* @param path
* @return
*/
bool refresh(const std::string& path);
/**
* @brief save
* @return
*/
bool save();
/**
* @brief save
* @param path
* @return
*/
bool save(const std::string& path);
int total() const;
/**
* @brief append add a new line to the end
* @param line
* @return
*/
int append(const std::string& line);
/**
* @brief clear all lines
*/
void clear();
/**
* @brief insertBefore insert a new line before the line at linenumber
* @param linenumber the linenumber
* @param text the text will be inserted
* @return
*/
bool insertBefore(int linenumber, const std::string& text);
/**
* @brief insertAfter
* @param linenumber
* @param text
* @return
*/
bool insertAfter(int linenumber, const std::string& text);
/**
* @brief remove remove a line at linenumber
* @param linenumber
* @return text of the removed line
*/
std::string remove(int linenumber);
/**
* @brief remove remove 'number' lines from 'start' line;
* @param start
* @param number
* @return the removed lines
*/
FileLines remove(int start, int number);
void assign(std::initializer_list<std::string> list);
template<class Iterator>
void assign(Iterator first, Iterator last) {
_lines.assign(first, last);
}
std::string tostring() const;
/**
* @brief operator []
* @param linenumer
* @return
*/
std::string& operator[](int linenumer);
const std::string& operator [](int linenumber) const;
/**save
* for using like std::xxx
*/
using iterator = std::vector<std::string>::iterator;
iterator begin();
iterator end();
using const_iterator = std::vector<std::string>::const_iterator;
const_iterator begin() const;
const_iterator end() const;
const_iterator cbegin() const;
const_iterator cend() const;
using reverse_iterator = std::vector<std::string>::reverse_iterator;
reverse_iterator rbegin();
reverse_iterator rend();
using const_reverse_iterator = std::vector<std::string>::const_reverse_iterator;
const_reverse_iterator rbegin() const;
const_reverse_iterator rend() const;
const_reverse_iterator crbegin() const;
const_reverse_iterator crend() const;
private:
std::string _rpath; //read from file
std::string _wpath; //write to file
std::vector<std::string> _lines;
};
接口实现
/**
* filelines.cpp
* #include "filelines.h"
*/
FileLines::FileLines() {}
FileLines::FileLines(const std::string &path): _rpath(path) {
refresh();
}
bool FileLines::refresh()
{
std::string line;
if(_rpath.empty()) return false;
std::ifstream in(_rpath);
if(in.is_open()) {
_lines.clear();
while(std::getline(in, line)) {
_lines.emplace_back(line);
}
in.close();
return true;
}
return false;
}
bool FileLines::refresh(const std::string &path)
{
_rpath.assign(path);
return refresh();
}
int FileLines::total() const
{
return _lines.size();
}
std::string& FileLines::operator [](int linenumber)
{
return _lines[linenumber];
}
const std::string& FileLines::operator [](int linenumber) const
{
return _lines[linenumber];
}
int FileLines::append(const std::string &line)
{
_lines.emplace_back(line);
return total();
}
bool FileLines::save()
{
if(_wpath.empty()) {
if(_rpath.empty()) return false;
_wpath = _rpath;
}
std::ofstream out(_wpath);
if(out.is_open()) {
for(auto& line: _lines) {
out << line << std::endl;
}
out.close();
return true;
}
return false;
}
bool FileLines::save(const std::string &path)
{
_wpath.assign(path);
return save();
}
void FileLines::clear()
{
_lines.clear();
}
bool FileLines::insertBefore(int linenumber, const std::string &text)
{
if(total() <= linenumber) return false;
_lines.insert(begin() + linenumber, text);
return true;
}
bool FileLines::insertAfter(int linenumber, const std::string &text)
{
if(total() <= linenumber) return false;
if(linenumber == total() - 1) return append(text);
_lines.insert(begin() + linenumber + 1, text);
}
void FileLines::assign(std::initializer_list<std::string> list)
{
_lines.assign(list);
}
std::string FileLines::tostring() const
{
std::ostringstream oss;
int last = total() - 1;
oss << "[";
for(int i = 0; i < last; ++i) {
oss << '"' << _lines.at(i) << '"' << ',';
}
oss << '"' << _lines.at(last) << '"' << ']';
return oss.str();
}
std::string FileLines::remove(int linenumber)
{
std::string rtn;
if(linenumber < total()) {
rtn = _lines.at(linenumber);
_lines.erase(begin() + linenumber);
}
return rtn;
}
FileLines FileLines::remove(int start, int number)
{
FileLines newlines;
if(total() <= start + number) {
number = total() - start;
}
newlines.assign(begin() + start, begin() + start + number);
_lines.erase(begin() + start, begin() + start + number);
return newlines;
}
FileLines::iterator FileLines::begin()
{
return _lines.begin();
}
FileLines::iterator FileLines::end()
{
return _lines.end();
}
FileLines::const_iterator FileLines::begin() const
{
return _lines.begin();
}
FileLines::const_iterator FileLines::end() const
{
return _lines.end();
}
FileLines::const_iterator FileLines::cbegin() const
{
return _lines.cbegin();
}
FileLines::const_iterator FileLines::cend() const
{
return _lines.cend();
}
FileLines::reverse_iterator FileLines::rbegin()
{
return _lines.rbegin();
}
FileLines::reverse_iterator FileLines::rend()
{
return _lines.rend();
}
FileLines::const_reverse_iterator FileLines::rbegin() const
{
return _lines.rbegin();
}
FileLines::const_reverse_iterator FileLines::rend()const
{
return _lines.rend();
}
FileLines::const_reverse_iterator FileLines::crbegin() const
{
return _lines.crbegin();
}
FileLines::const_reverse_iterator FileLines::crend() const
{
return _lines.crend();
}