在生物信息领域读取fasta文件是重要的序列信息储存载体,分为开头注释和序列信息两部分。在上一篇博客中,小编已经分享了Java读取fasta文件的方法。详情请见:Java逐行读取fasta文件
上面提到的方法是通过逐行读取源文件,因此可以有效区分标签和序列。但是实际使用的时候由于fasta文件的来源网站不同,其源文件中会出现序列带有换行符的情况(如下图,其实每一段序列中间的每一行末尾都有“\n”分隔),这样的情况下用刚刚的代码就不灵了(一段序列会被逐行读取成多段序列)。我们需要进行一些预处理。
方法1:利用Linux awk命令预处理fasta文件
我们待处理的目标序列信息存储在sequence.fasta文件中,经过awk处理会生成seq_withoutn.fa文件。而后者则去掉了序列信息中的所有换行符。
awk '!/^>/{printf $0;n ="\n"}/^>/{print n $0; n = ""}END{printf "%s",n}' sequence.fasta > seq_withoutn.fa
这里感谢Kirby_monster提供的思路和技术支持!上述linux命令运行起来非常迅速,awk也是linux系统最常用的文件处理工具之一。但是如果你的手头没有linux服务器,那就有些麻烦,因此小编更推荐第二种方法:改进fasta读取。
方法2:改进Java读取fasta文件的方法
我们重新思考之前的方法:Java逐行读取fasta文件会发现如果fasta开头注释部分的获取是没有任何问题的,问题就在于序列信息部分的\n。带有换行符的一条序列会被代码读取为多个序列,并分别存储到内存中。 如何去掉换行符,并且逐行连接左右的序列是解决折叠行问题的关键。最重要的是如果fasta文件里包含了多段序列,拼接的时候还不能和下一段序列搞混。
在这里,小编使用了StringBuilder.append命令,该命令可以逐行拼接序列并且无视掉中间的换行符。同时通过设置“断点”,一旦检测到开头标签信息(带有">"的开头)则会重新清空StringBuilder,从而重新开启下一个序列的逐行拼接。
具体代码如下:
public static ArrayList<String> BufferedReader2(String path,String choose) {//返回值类型是新建集合大类,此处是Set而非哈希。
BufferedReader reader;
ArrayList<String> tag = new java.util.ArrayList<String>();
ArrayList<String> fasta = new java.util.ArrayList<String>();
try {
reader = new BufferedReader(new FileReader(path));
String line = reader.readLine();
StringBuilder sb = new StringBuilder();
while (line != null) {//多次匹配带有“>”的行,\w代表0—9A—Z_a—z,需要转义。\W代表非0—9A—Z_a—z。
if (line.matches(">[\\w*|\\W*]*")){
tag.add(line);
//定义字符串变量seq保存删除换行符的序列信息
if (sb.length()!=0){
String seq = sb.toString();
fasta.add(seq);
sb.delete(0, sb.length());//清空StringBuilder中全部元素
}
}else{
sb.append(line);//重新向StringBuilder添加元素
}
// read next line
line = reader.readLine();
}
String seq = sb.toString();
fasta.add(seq);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
if (choose.equals("tag")){
return tag;
}
return fasta;
}
使用这段java代码读取fasta文件时就不用再担心序列信息中的换行符问题啦。而且fasta文件中的开头注释信息和序列信息能分别存储到集合“fasta”和集合“tag”之中。方便后继的读取和调用。