读写模板

在数据处理过程中,非常重要的一个环节就是文件的读入和输出。C++中可以通过fstream对文件进行读写,下面就是一个C++中文件读写的一个模板。

// basic file operation
#include <iostream>
#include <fstream> //文件操作模块
#include <string> //字符串模块
using namespace std;

int main(){
    string line;
    ifstream myfile ("a1.txt"); //定义读入文件对象,文件名
    ofstream myfile_out ("a2.txt"); //定义输出文件对象,及文件名
    if(myfile.is_open()){//打开文件
        while(getline (myfile, line)){ //按行读入文件
            do something;//对line进行操作,line是文件每一行的一个字符串
            myfile_out << line << endl;
        };
        myfile_out.close(); 
        myfile.close(); //关闭文件
    }else{
        cout << "Unable to open file" << endl; //如果没能打开文件,提示错误
    }
    return 0;
}

上述过程实现了对文件的读写,具体来说就是把a1.txt中的每一行都复制到了a2.txt中。

具体例子

我们有一个基因注释文件 consensus.maker.clean_up.gff(GFF格式),文件格式如下。

其中注释有基因区域,有外显子区域还有CDS区域等。那么我们只想要“基因”区域,则可以通过第3列筛选出“gene”的行。

我们首先通过C++来实现我们的目的,首先读入gff文件,然后把每一行字符串的分割成vector,判断其中第3个元素是否为”gene”,如果是则输出该行。

//test extract genes
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

int main(){
    ifstream inFile("consensus.maker.clean_up.gff");
    ofstream outFile("consensus.maker.clean_up.gene_CPP.gff");
    string line;
    while(getline(inFile, line)){
        istringstream iss(line);
        string buf;
        vector<string> tokens;
        while (iss >> buf){
            tokens.push_back(buf);
        };
        if(tokens[2] == "gene"){
            outFile << line << endl;
        }
    }
    inFile.close();
    outFile.close();
    return 0;
}

得到结果如下:

其他几种语言实现该目的并比较

如果我们使用Python完成上述目的

Python:

with open("consensus.maker.clean_up.gff","r") as ff:
    with open("consensus.maker.clean_up_Python.gff", "w") as gg:
        for line in ff.readlines():
            if (line.split("\t")[2] == "gene"):
                gg.writelines(line)

使用R到达上述目的,这里使用的data.table包,能够大大提升R的运行效率:

R:

library(data.table)
aa <- fread("consensus.maker.clean_up.gff", header = F, sep = "\t")
bb <- aa[V3 == "gene"]
fwrite(bb,"consensus.maker.clean_up.gene_R.gff", col.names = F, sep = "\t")

是不是觉得从C++,到Python,到R代码越来越少,越来越简单呢。其实最简单的是使用awk命令,只需要在终端中输入一行命令就可以完胜上面的目的。具体参考本公众号之前的awk教程。

awk:

awk '{if($3=="gene") {print $0}}' consensus.maker.clean_up.gff > consensus.maker.clean_up.gene_awk.gff

对四种方法的输出文件进行检验,如下

即4种方法输出的结果完全一样。

另外,比较一下四种方法的运行时间,依次为C++, Python, R 和AWK:

结果有点意外,R的运行速度竟然最快,估计和使用data.table包有关系!而C++的运行速度最慢,这儿竟然意外翻车了!猜测可能是数据量比较少(70M),同时本人C水平入门级别,没能对代码进行很好的优化。

总结,通过fstream可是在C++中实现对文件的读写。另外,程序运行速度不仅取决于编程语言本身,还和代码的优化有很大关系。

======= THE END ======