在IDL中读写数据Word下载.docx
《在IDL中读写数据Word下载.docx》由会员分享,可在线阅读,更多相关《在IDL中读写数据Word下载.docx(27页珍藏版)》请在冰豆网上搜索。
IDL被广泛使用的原因之一,是IDL可以在许多不同的计算机操作系统中运行。
但由于不同的操作系统有不同的文件命名习惯(而且,特别用确定子目录的不同方式),这在以独立于机器的方式指定文件名方面提出了挑战。
幸好,IDL提供了一些工具可让这项工作变得容易些。
选择文件名
也许获得机器独立文件名最容易的方法是用Pickfile对话框。
IDL命令允许用机器上自身的选择文件的图形对话框来交互式地从文件名列表中选择一个文件名。
例如,从本地目录.pro文件列表中选择一个文件名,可以键入如下命令:
IDL>
filename=Dialog_Pickfile(Filter=’*.pro’,/Read)
注意,这个命令在IDL5.0以前的版本中命名为Pickfile。
IDL5.2版通过关键字Multiple,赋予Dialog_Pickfile选择多个文件名(若它们存在于同一个目录下)的能力。
使用了正常的依赖于平台的选择文件方式。
例如,在用WinDOws操作系统的计算机上,通常先选择第一个文件,接着用Shift键和鼠标点击来选择在第一个文件和第二个文件之间的所有文件,或者用Control键和鼠标点击来选择一个额外的文件。
filename=Dialog_Pickfile(Filter=’*.pro’,/Read,/Muitiple)
如果要打开文件来写而不是去读,在对话框中,可用Write关键字代替Read关键字。
甚至可以推荐一个缺省的文件名,键入:
outfile=Dialog_Pickfile(File=’default.dat’,/Write)
从这个对话框中返回的是带绝对路径的文件名,其形式与运行IDL的机器有关。
也就是说,它使用机器自身的文件命名语法。
键入以下命令就可以看到:
Help,filename,outfile
注意,Dialog_Pickfile对话框中有一个“取消”按钮。
若选择“取消”按钮,对话框会返回一个空字符串。
所以在打开文件读写之前,总是希望检查返回的名字是否为空。
IFoutfileEQ‘’THENPrint,’Whoops!
’
选择目录名
在IDL5.2中,Dialog_pickfile得到改进,因而它也能用于选择目录名而不仅是一个文件名。
设置Directory关键字,在选择窗口内只列出目录而没有文件。
directory=Dialog_Pickfile(/Directory)
寻找文件
另一个有用的命令是FindFile命令。
此命令返回一个包含所有符合给定文件要求的文件名的字符串数组。
这在IDL程序中用于自动匹配并打开文件的任务中非常有用,或者是在任何时候不知道一个目录下有多少个文件的情况下,用于在该目录下创建一批文件的任务中也是非常有用的。
例如,要打印出当前目录下所有数据文件的长度(按字节计),可键入IDL代码:
Files=findfile(‘*.dat’,count=numfiles)
Ifnumfileseq0thenmessage,‘nodatafileshere!
FORj=0,numfiles-1DOBEGIN
Openr,10,files(j)
fileinfo=fstat(10)
print,fileinfo.size
Close,10
ENDFOR
需要重点指出的是:
FindFile命令中文件说明(’*.dat’)是以相对路径名给出,而不是绝对路径名。
因此,命令返回也是相对路径名,而不是绝对路径名。
这不同于Pickfile对话框,Pickfile总是返回绝对路径名。
构造文件名
获得机器独立文件名的第三个很有用的IDL命令是Filepath命令。
例如,假设要打开文件galaxy.dat,它在IDL主目录下的examples/data子目录中。
可以为此文件构造一个机器独立的绝对路径名,键入:
galaxy=filepath(‘galaxy.dat’,Subdirectory=[‘examples’,’data’]
如果想从其它的目录开始而不是IDL主目录,可以用Root_Dir关键字指定开始的目录名。
例如,要在当前目录的子目录coyote中构造此文件的一个路径名,可以键入:
cd,current=thisdir
galaxy=filepath(‘galaxy.dat’,root_dir=thisdir,$
Subdirectory=’coyote’)
注意:
Filepath命令并没有实际找到此文件,它只是构造了一个文件路径名。
构造的文件名甚至在机器中可以不存在。
获取逻辑设备号
在IDL中所有文件输出和输入都是在一个逻辑设备号上完成的。
一个Open命令的作用是将一个特定的文件(通过其文件名来指定)和一个逻辑设备号相关联。
有128个逻辑设备号可供使用。
它们被分成两类。
逻辑设备号
用途
1-99
这些号可以在Open命令中直接使用
100-128
这些号通过Get_Lun和Free_Lun命令获取和管理
表8:
128种逻辑设备号被分成两类。
一类可以直接使用,另一类用Get_Lun和Free_Lun命令获取和管理
直接使用逻辑设备号
要直接使用逻辑设备号,只能在1-99中选择一个号,并用Open命令使用它。
要做的是选择一个当前没有使用的号。
例如,可用逻辑设备号5来打开当前目录的子目录coyote中的galaxy.dat文件,键入:
CD,current=thiedir
filename=Filepath(Root_Dir=thisdir,$
Subdirectory=’coyote’,’galaxy.dat’)
Openr,5,filename
一旦1-99中的某个逻辑设备号分配给一个文件后,它就不能再分配了,直到该逻辑设备号被关闭或退出IDL(这将自动关闭所有打开的逻辑设备号)。
当完成了对逻辑设备号的操作(也就是说,不想再对文件进行读写),可用Close命令关闭它,并使其可以重新使用:
IDL>
Close,5
让IDL管理逻辑设备号
多数情况下(特别在IDL程序中),最好让IDL管理逻辑设备号。
可使用Get_Lun和Free_Lun命令完成此项功能。
有两种方法让IDL返回一个逻辑设备号。
可以直接使用Get_Lun命令。
如:
Get_Lun,lun
OpenR,lun,filename
或者,可以用带关键字Get_Lun的Open命令来间接完成:
OpenR,lun,filename,/Get_Lun
这个命令运用隐含的Get_Lun命令将作为结果的逻辑设备号存入变量Lun中。
这是逻辑设备号最常用的获取方法,特别是在IDL程序中。
(注意,变量名不一定是Lun。
可以给出喜欢的名字。
如果打开了几个文件,就需要几个不同的名字。
)
当完成了对逻辑设备号的操作(也就是说,不想再对文件进行读写),可用Free_Lun命令关闭它。
Free_Lun,Lun
使用Get_Lun和Free_Lun命令的好处在于不必记住哪个逻辑设备号是可用的或没被使用的。
Get_Lun程序保证返回一个有效的逻辑设备号(假设同时已经打开的文件少于28个)。
如果是在过程和函数中打开文件,一般最好使用Get_Lun命令。
因为如果直接选择某个特定的逻辑设备号,不能保证它是可用的或没有被使用的。
判断哪些文件和哪些逻辑设备号相连
使用带Files关键字的Help命令,可以很容易判断哪些文件和哪些逻辑设备号相连。
Help,/Files
读写格式化数据
IDL在读写格式化数据方面有两种格式化文件之区分:
自由文件格式和确定的文件格式。
格式化文件有时叫做ASCII文件或者纯文本文件。
自由文件格式自由格式文件用逗号或空白(tab键和空格键)分开文件中的每个元素,这没有确定的文件格式正规。
确定的文件格式确定的格式文件是用格式说明按照给定的规范进行编排的。
IDL格式说明和FORTRAN或C程序中的格式说明类似。
写自由格式文件
在IDL中,写一个自由格式文件极其容易。
只要用PrintF命令将变量写入文件即可。
这和在显示窗口上用Print命令打印变量的形式几乎相同。
IDL在写文件时自动在数据的元素间加入空格。
例如,键入下面这些命令,创建数据并写入文件:
array=FIndGin(25)
vector=[33.6,77.2]
scalar=5
text=[‘array’,’vector’,’scalar’]
header=’Testdatafile.’
created=’created:
’+SysTime()
接着,将一个逻辑设备号(让IDL自己选择一个并放到变量lun中)和特定文件相连来打开文件写入,键入:
OpenW,lun,’test.dat’,/Get_Lun
最后,将数据写入文件,并关闭数据文件,键入:
PrintF,lun,header
PrintF,lun,created
PrintF,lun,array,vector,scalar,text
Free_Lun,lun
用一个文本编辑器打开文件检查。
类似于如下所示:
Testdatafile.
created:
TueNov2815:
50:
582000
0.0000001.000002.000003.000004.000005.00000
6.000007.000008.000009.0000010.000011.0000
12.000013.000014.000015.000016.000017.0000
18.000019.000020.000021.000022.000023.0000
24.0000
33.600077.2000
5
arrayvectorscalar
注意:
IDL在数组变量的每个元素间设置空白区,并使每个新变量另起一行开头。
IDL在缺省情况下使用80列宽度。
如果需要不同的列宽度,可以用带Width关键字的OpenW命令设置。
读自由格式文件
许多ASCII文件是自由格式文件。
例如,从电子数字表程序中保存的文件大多是自由格式文件。
一种特殊的自由格式数据是从键盘或标准输入读取的数据。
在IDL中,有两种命令可以读取自由格式文件。
Read读取从标准输入或键盘上读入自由格式数据
ReadF从文件中读入自由格式数据
读取自由格式文件的规则
无论是从键盘上还是从文件中读取自由格式的数据,IDL遵循下列7种规则:
1.如果读入到字符串变量中,那么,在当前行剩下的所有字符都将读入该变量中。
观察上面数据文件的第一行,此行内有三个单词。
此项规则意味着,一旦IDL开始为字符串变量读入数据,那么IDL将一直读到行尾,否则不会停止。
其原因是在IDL的所有数据类型中,字符串变量可以是任意尺寸的,而且空格符也是ASCII字符。
打开该数据来读入,试着只读入一个单词,如下:
IDL>Open,lun,‘test.dat’,/Get_Lun
word=‘’
ReadF,lun,word
Print,word
所看到的是整个第一行都被读入到word变量中。
(如果想将第一行分解成单个的单词,可以用IDL的字符串处理程序来完成。
)这种可以读到行尾的能力是IDL一个好的特色。
为什么这样说呢?
首先,将文件指针重置到文件的开头。
可用Point_Lun命令实现此项功能。
键入:
Point_Lun,lun,0
现在可将数据文件的前二行读入到header变量中。
IDL>header=StArr
(2)
ReadF,lun,header
Print,header
这些命令将读出文件的前二行,并将文件指针定位到数组的起始处。
可以在同一行上同时输出了头两行的内容。
Testdatafile.created:
2.输入数据必须用逗号或空白分隔(空格键或tab键)。
在test.dat数据文件中所用到的就是这种格式的数据。
IDL在数组变量中的每个元素间插入5个空格。
3.输入通过数字变量完成。
数组和结构都可作为数字变量的集合。
这意味着,如果正在读入的变量含,比如说,10个元素,IDL将从数据文件中读入10个分开的数值。
它将采用以下的两条规则来确定这些数据存在于文件的何处。
4.如果当前读入行是空的,并且还有变量要求输入,则读取另一行。
5.如果当前读入行不是空的,但是没有变量要求输入,则忽略此行剩下的数。
为了解其含意,可键入:
IDL>data=FltArr(8)
ReadF,lun,data
Print,data
将看到:
0.000001.000002.000003.000004.000005.00000
6.000007.00000
在此例中,IDL从文件中读入8个分开的数据值。
当读取到第一行数据的末端时,它自动进入到第二行(规则4),因为还有更多的数据要求读入。
当数据读入到第二行的中部时,规则5起作用了。
如果现在还要读入更多的数据,那将从数据的第三行开始,因为第二行的其它部分被忽略了。
IDL>data=FltArr(3)
ReadF,lun,vector3
Print,vector3
12.000013.000014.0000
6.尽量将数据转换为变量所希望的数据类型。
要了解什么意思,将第四、第五行数据读入到一个字符串数组,以便让文件指针定位在文件中的第六数据行(即起始数值为33.6000的那行)。
IDL>dummy=StrArr
(2)
ReadF,lun,dummy
假设想读入两个整型值。
IDL尽量将数据(在此情况下,为浮点数)转换为整型。
IDL>ints=IntArr
(2)
ReadF,lun,ints
Print,ints
3377
注意,浮点数被简单的截取成整数。
在转换处理过程中并没有采用四舍五入的规则来保证最接近的整数值。
7.复数数据必须有实数和虚数两部分,用逗号分隔,并用括号括起来。
如果仅仅提供了单个数值,它将被认为是实数部分,而虚数设置为0。
例如,可通过键盘读入复数数据:
value=ComplexArr
(2)
Read,value
:
(3,4)
(4.4,25.5)
print,value
在结束这部分学习之前,确保关闭test.dat文件。
IDL>Free_Lun,lun
读写自由格式文件的实例
学会用IDL读写数据最容易的方法是看一些实例。
下面实例说明在读入文件头、处理以列排列的数据以及处理已读入IDL的数据这些方面的常用IDL技巧。
读一个简单数据文件
从读刚创建的test.dat文件中的数据开始。
首先,创建用于读文件中数据的变量。
header=strarr
(2);
twoheaderlines.
data=fltarr(5,5);
floatingpointarray.
vector=intarr
(2);
two-elementintegervector.
scalar=0.0;
floating-pointscalar.
string_var=’’;
astringvariable.
注意,此时数据变量将是5*5的数组。
而在文件中是以25个元素的矢量保存的。
用这种方法读入数据相当于读入25个元素的矢量,并将其重新格式化为5*5的数组。
记住IDL中的数据是按行存储的。
根据规则一,不能将文件末端的一行文本读到三元素的字符串数组中。
不得不将其读入单个字符串变量,然后用IDL的字符串处理命令将该文本字符串分解到后续的变量中。
可立即从文件中读出所有数据,键入:
openr,lun,’test.dat’,/Get_Lun
ReadF,lun,header,data,vector,scalar,string_var
free_Lun,lun
要将包含文件末行文本的字符串变量转换成三个元素的字符串数组,首先要将变量前后两头的空白字符除去。
thisstring=strtrim(string_var,2)
有时若将字符串转换成字节型数组,字符串的处理就会容易些。
可以先处理字节型数组,最后再将其转换成字符串。
当然也可使用其它方法,但是这种方法在这里更好一些。
thisarray=Byte(thisstring)
help,thisarray
这是19个元素的字节型数组。
要知道空格的ASCII码字符,可用IDL查出:
blank=Byte(“”)
print,blank
help,blank
注意,Byte命令处理一个字符串后的返回值总是一个数组。
在此例中,是一个元素的数组。
为了以后不至于混淆,将其转换成一个数值。
blank=Blank[0]
输出空白字符的ASCII码值是32。
可用Where命令显示字节型数组中的空白字符。
vals=Where(thisarrayEQblank)
最后,将字符串转换成三个元素的数组。
s=strarr(3)
s[0]=string(thisarray[0:
vals[0]-1])
s[1]=string(thisarray[vals[0]+1:
vals[1]-1]
s[2]=string(thisarray[vals[1]+1:
*]
写列格式数据文件
在文件中数据按列储存是不稀奇。
需要了解如何用IDL读写这种数据。
IDL将会给粗心的程序员一个惊奇。
要知道究竟是怎么回事,可以写一个列格式数据文件。
用下列命令将数据读入IDL:
data=LoadData(15)
这个数据是一个有三个字段的结构:
lat,lon和temp。
每个字段都是41个元素的浮点矢量。
可用如下命令从结构中提取矢量:
lat=data.lat
lon=data.lon
temp=data.temp
接着,打开一个写入数据文件,键入:
OpenW,lun,’column.dat’,/Get_Lun
需要将三列数据写入这个文件,通过自由格式输出。
这可以在一个循环中完成。
printf,lun,’columndata:
lat,lon,temp’
FORj=0,40DOprintf,lun,lat[j],lon[j],temp[j]
free_lun,lun
column.dat文件的前四行应如下:
Columndata:
lat,lon,temp
33.9840–86.940536.9465
26.2072–121.61520.1868
42.1539–103.733231.604
读列格式数据文件
到目前为止一切正常。
当试着将列格式数据读入IDL时问题就出来了。
可能会按如下做。
首先,创建要读入数据的变量。
header=’’
thislat=fltarr(41)
thislon=fltarr(41)
thistemp=fltarr(41)
打开column.dat文件读首行:
OpenR,lun,’column.dat’,/Get_Lun
由于是用一个循环将数据放进文件的,所以也可能会用一个循环从文件中将数据读出。
FORj=0,40DOReadF,lun,thislat[j],thislon[j],thistemp[j]
但这不奏效。
虽然上面的命令没有错误,但没有数据读入变量(如打印变量值,它们将是零)。
其原因是IDL中有一个严格的规则,即不能带下标的变量来读入内容。
原因是IDL将带下标的变量作为值而不是作为变量的引用传递给象ReadF这样的IDL程序。
以数值传递的数据不能在被调用的子程序中改变,因为被调用的子程序只是获得该数据的备份,而不是获得该数据的指针。
要改变这种属性需要对IDL进行大改,然而这是不可能的。
有两种方法解决这个问题。
第一种是将数据读入一个循环中的临时变量。
这种方法最好是运用文本编辑器将命令输入文件中来完成,因为很难在IDL命令行上编写多行循环。
可用Point_Lun命令将文件指针返回到数据文件的起始处。
在文本文件loopread.pro中输入下列命令。
temp1=0.0
temp2=0.0
temp3=0.0
FORj=0,4