05、解剖CEL文件各版本格式和读取方法(非R语言)

  相比DAT文件,网络上更支持CEL级别的文件。CEL已经把DAT图像转换成数据了,而且CEL比DAT所占空间小得多。介绍一下CEL文件的格式,CEL文件有文本文件(TextCelFile,版本3)、BinaryCelFile(二进制文件,版本4)、GenericCelFile(普通文件,版本1)三种。

1)版本3

早期的CEL文件是版本3的,因为是文本文件,所以直接用记事本打开就可以看到里面的内容了,如下是GSM2899.CEL:

[CEL]

Version=3

[HEADER]

Cols=640

Rows=640

……

DatHeader=[5..46118]  AFRGV01031201:CLS=4733 RWS=4733 XIN=3  YIN=3  VE=17        2.0 03/12/ 1 17:16:25     GridVerify=None  HG_U95Av2.1sq                  6

……

CellHeader=X Y MEAN STDV NPIXELS

0   0 278.0 95.3  25

1   0 22909.3 5244.4  20

2   0 390.0 121.0  25

3   0 22530.0 5102.5  25

……

638 639 20835.5 3531.1  20

639 639 292.0 85.2  25

可以看到Version=3,列数Cols和行数Rows都是640。可以发现DatHeader里有很多的  ,它起到了分割字符串的作用(这是我第一次在C语言源码里看到  这样的乱码),把“DatHeader=”后面的部分分割成若*分,然后找出以“.1sq”结尾的那部分,即“HG_U95Av2.1sq”,再把“.1sq”去掉,就成功读取出芯片型号HG_U95Av2了。CellHeader=X Y MEAN STDV NPIXELS中的X和Y指的就是探针(特征)的X坐标和Y坐标,MEAN指探针的强度,STDV是方差,NPIXELS指用多少个像素来计算MEAN和STDV。每一行是一个探针(特征)的数据,这是一个640*640的阵列,所以X会从0变化到(640-1),以此循环640次,Y也从0变化到(640-1),不过每个数要重复640次。这样,就刚好有640*640行了。我们所要用到的数据只是MEAN那一列而已,不需要STDV和NPIXELS,而X和Y可以经过推算得出。这样,我们就可以理解为:坐标为(0,0)的探针强度为278.0,坐标为(1,0)的探针强度为22909.3,坐标为(2,0)的探针强度为390.0……

2)版本4

后来出现了版本4的CEL文件,它们是二进制文件,直接用记事本打开会看到很多的乱码。可以用CellFileConversionTool.exe工具进行版本3和版本4的格式转换。把版本3转换成版本4后,文件就小多了,因为已经去掉了X和Y这两列的数据。该版本采用了小端字节序,下面列举了不同数据类型的不同读取方法:

Integer:

若用Java读取整型数据:

如:FileInputStream fin=new FileInputStream("CEL文件的路径");

DataInputStream din=new DataInputStream(fin);

……

/*先读取出4个字节*/

int[] byteDataInt=new int[4];

for (int i=0;i<4;i++)

byteDataInt[i]=din.read();

/*移位,第(i-1)个字节右移i*8个字节*/

for (int i=0;i<4;i++)

byteDataInt[i]=byteDataInt[i]<<8*i;

/*再进行 | 运算*/

int result=byteDataInt[0]|byteDataInt[1]|byteDataInt[2]|byteDataInt[3];

……

若用C把完成以上的工作,就方便多了:

如:FILE *infile = fopen("CEL文件的路径", "rb")) ;

……

int result;

fread_int32(&result,1,infile);

……

这样,一个整型数据就被读取出来存放在result中了。

Short:

若用Java读取短整型数据:

int[] byteDataInt=new int[2];

for (int i=0;i<2;i++)

byteDataInt[i]=din.read();

for (int i=0;i<2;i++)

byteDataInt[i]=byteDataInt[i]<<8*i;

int result=byteDataInt[0] | byteDataInt[1];

用C语言:

fread_int16(&(result,1,infile);

Float:

若用Java读取浮点型数据:

int[] byteDataInt=new int[4];

for (int i=0;i<4;i++)

byteDataInt[i]=din.read();

int symbol=byteDataInt[3] & 8;    //get the symbol

int power=(byteDataInt[3]<<1 | byteDataInt[2]>>7)-127;  //get the power

int temp= byteDataInt[2] & 127;   // let the 8th bit to be 0

int a=temp<<16 | byteDataInt[1]<<8 | byteDataInt[0];

float result=1;

for (int i=1;i<=23;i++)

{

int x=a&(int)(Math.pow(2, i-1)); //keep value of the i bite and make others bites to be 0

int xx=x>>(i-1);              // move the i bite to the right end;

double addCount=xx*(Math.pow(2,-(23-(i-1))));  // computing the increment

result=result+addCount;

}

result=result*(int)(Math.pow(2, power));

if (symbol==1)

result=-result;

用C语言:

fread_float32(&(result,1,infile);

以上的3个例子可以看出,Java和C语言可以实现同样的功能,但是Java却麻烦得多,而且实验证明,Java花的时间会多得多。如版本4的探针强度是float型的,假如一张芯片的640*640个探针强度都用Java来读取,将会花费很长的时间,而用C语言不足1秒就可以完成。

3)版本1

版本1在版本3的基础上又去掉了STDV和NPIXELS这两列,并且出现了fread_be_int32、fread_be_uint16、fread_be_float32等C语言读取方法,这些方法都有着等效的Java实现方法,但是用Java来读取CEL文件总是很慢的。

上一篇:jqPlot图表插件学习之柱形图和旋转分类名称


下一篇:iOS: Xcode7安装KSImageNamed插件,自动读取图片名称