第7章文件
GeoGeo支持文本格式与二进制格式数据的磁盘存取。从信息存储字节的水平来说,任何磁盘文件均可以使用二进制方式存取,无论是文本格式或者其它任何数据格式。但是如果预先知道数据的格式会对数据访问带来极大便利。例如,已知数据存储为4字节浮点格式,将其读入4字节浮点格式的缓存比将其读入单字节的缓存再分析数据格式要方便得多。
GeoGeo的文件处理机制可以方便地存取文本格式或者二进制格式数据。
7.1文件的打开与关闭
7.1.1打开文件
打开文件使用Open函数,该函数的原型如下:
int Open(STRING filename, int flag);
函数的第1个参数是待打开文件的文件名;第二个参数是打开方式的标志,该参数值为0时表示以二进制方式打开文件,为1时表示以文本方式打开文件。缺省时该值为0。
该函数有一个整型返回值,返回打开文件的文件编号,后续的访问操作均通过这个编号进行。例如:
int fileID = Open(“文件名.bin”,0);
Read(fileID,buffer);
读文件的函数通过这个编号来确定从哪个打开的文件读取数据。
7.1.2关闭文件
关闭文件使用Close函数:
int Close(int fileID);
函数的唯一参数是打开文件时的文件号。关闭文件成功时函数返回1,否则返回0。
7.2文件的读写
读写文件使用Read和Write函数:
int Read(int fileID,T var);
int Write(int fileID,T var,int flag);
两个函数前面的2个参数相同,第1个参数仍旧是打开文件的文件号,第2个参数是读写文件变量(读写文件数据的存放位置),这个参数的数据类型T表示任意合法的数据类型。函数成功时返回1,否则返回0。
在这两个函数中不显式区分文本文件还是二进制文件,因为在打开文件时文件号对此已经知道是什么类型的文件。
写文件比读文件多一个参数,指示写文件时写完一个变量是否后面要续行。0表示结束本行,1表示续行。缺省时为0。
7.2.1读写文本文件
7.2.1.1 读文本文件
文本文件中可能包含文字、数字等内容,读文本文件时使用不同变量来读取这些不同的信息,请看下面读文件的例子。
程序清单 7.1 7-1-读文本格式数据1.c
1 main(){
2 int n;
3 STRING str;
4 STRING name ="D:\\文本数据.txt";
5 int nID1 =Open(name,1);
6 do{
7 n = Read(nID1,str);
8 Print(str);
9 }while(n);
10 Close(nID1);
11 }
第5行以文本方式打开一个文件,第7行使用Read函数循环读取文件中的每个串,返回值为0时表示没有文件可读或者遇到错误。在第10行关闭这个文件。
在这个例子中,文件中无论是文字还是数字都全部读到一个字符串变量中。实际上文件中如果是数字,也可以由整型或者浮点型变量来读取。
程序清单 7.2 7-2-读文本格式数据2.c
1 struct DATA{
2 STRING name;
3 double lon;
4 double lat;
5 float data[3];
6 };
7 main(){
8 STRING title[6];
9 DATA data;
10 STRING name = "D:\\文本数据.txt";
11 int nID1 = Open(name,1);
12 int n = Read(nID1,title);
13 Print("%s %s %s %s %s %s",title[0],title[1],title[2],title[3],title[4],title[5]);
14 do{
15 n = Read(nID1,data);
16 if(n){
17 Print("%s %f %f %f %f %f",data.name,data.lon,data.lat,data.data[0], data.data[1], data.data[2]);
18 }
19 }while(n);
20 Close(nID1);
21 }
第8行声明了一个具有6个元素的字符串数组title,在第12行读时,可以一次性读来6个字符串。第9行声明了一个自定义数据类型dada,其中包括一个字符串成员,两个双精度浮点成员,和一个有3个元素的单精度浮点数组。在第15行读数据时会自动按各个成员与文件中字段匹配。
运行上述代码,输出为:
名称经度纬度 CH1 CH2 CH3
Rsd0001 121.914421 41.659408 226.000000 253.000000 253.000000
Rsd0002 121.920261 41.658179 181.000000 178.000000 193.000000
…
如果预先知道数据的数目(文本文件都是可以打开查看的),可以用一个数组一次性读入数据。代码改为:
DATA data1[31];
STRING name1 = " D:\\文本数据.txt ";
…
n = Read(nID1,title1);
n = Read(nID1,data1);
省去了循环读取的过程。
7.2.1.2 写文本文件
写文本文件打开文件和读文本文件一样,不区分读和写。写文件如果打开的是一个已经存在的文件,则接在后面续写而不擦除原来文件的内容。如果希望从已经存在的文件开头写,使用Remove函数删除这个文件再用该文件名重新打开。
程序清单 7.3 7-3-写文本格式数据.c
struct MyStruc{
STRING str;
intx;
};
main(){
STRING str ="写文本数据的例子";
double a = 3.14;
MyStruc struc;
struc.str = "结构中的字符串";
struc.x = 16;
STRING name ="D:\\写文本数据例子.txt";
int nID1 =Open(name,1);
Write(nID1,str);
int i;
for(i=0; i<2; i=i+1){
Write(nID1,i,1);
Write(nID1,struc,1);
Write(nID1,a);
}
Close(nID1);
}
运行上述代码,会在D盘根目录下找到一个名为“写文本数据例子.txt”的文本文件,用记事本打开该文件,内容如下:
写文本数据的例子
0 结构中的字符串 16 3.140000
1 结构中的字符串 16 3.140000
注意:写文件的第2个参数需要使用变量,不要使用表达式,下述写法非法:
Write(nID1,i+1,1);
7.2.2读写二进制文件
打开二进制文件只需将Open函数的第2个参数置0,或者不写这个参数
int fileID = Open(“文件名.bin”);
关闭二进制文件与关闭文本文件相同。
7.2.2.1 二进制文件的位置
文本文件由于一些不可显示字符的存在,其文件指针所在位置的意义就不像二进制文件中这样重要。在对二进制文件中的操作中,经常需要将文件指针设置到某特定位置,或者需要随时了解当前文件指针所在位置。
使用Rewind函数将文件指针设置到文件开头。
int Rewind(int fileID);
函数的参数为打开文件时返回的文件号,函数成功时返回1,失败时(通常为文件号失效等)返回0。
使用Seek函数将文件指针定位到需要的位置。
int Seek(int fileID,longlong pos);
函数的参数为打开文件时返回的文件号,第2个参数是一个64位整型值,指定文件指针移动的位置。函数成功时返回1,失败时返回0。
使用GetPos函数读取文件指针当前位置。
Longlong GetPos (int fileID);
函数的参数为打开文件时返回的文件号。返回值为64位长整型的文件指针位置。失败时返回 -1。
7.2.2.2 写二进制文件
写二进制文件与写文本文件使用相同的函数,打开文件时按二进制文件打开,后续的操作自动按照打开时的方式进行。
下面的例子将按文本格式读入的数据再按二进制格式写出到一个文件:
程序清单 7.4 7-4-写二进制.c
1 main(){
2 STRING name1 = "G:\\MyProjects\\脚本\\RSDScript\\脚本代码示例\\文本数据.txt";
3 STRING title[6]; //存储读来文件头的数据
4 DATA data[31]; //存储文件正文的数据
5 int nID1 = Open(name1,1); //打开文本文件
6 int n = Read(nID1,title); //读文件头
7 n = Read(nID1,data); //读文件正文
8 Close(nID1); //关闭文本文件
9 STRING name2 = "D:\\二进制数据.bin";
10 int nID2 = Open(name2); //打开二进制文件
11 int len = SizeOf(title); //求文件头写入的字节数
12 Write(nID2,title); //写文件头
13 Print("写入文件头%d字节",len);
14 len = SizeOf(data); //求正文写入的字节数
15 Write(nID2,data); //写入数据正文
16 Print("写入文件正文%d字节。",len);
17 Close(nID2); //关闭二进制文件
18 }
DATA结构同程序清单7.2第1~6行。文件头是有6个字段的字符串数组,在第11行求算其总长度为21字节。数据在第7行由结构数组data[31]一次性读入,在第15行以二进制格式一次性写入文件。运行上述代码,输出如下:
写文件头 21字节
写文件正文 1085字节
找到输出的文件“二进制数据.bin”,查看其文件长度为1106字节,与写文件计数相符。
注意:GeoGeo写文件如果遇到已经存在的文件则从问价结尾处续写,如果确定以前存在的文件不再需要了,可以使用Remove函数先删除该文件。
7.2.2.3 读二进制文件
读二进制文件与读文本文件一样也使用Read函数,打开文件时按二进制文件打开,读操作也按二进制方式读取。使用上一节输出的“二进制数据.bin”文件,用下述代码读。
程序清单 7.5 读二进制.c
1 main(){
2 STRING str;
3 double lon,lat;
4 float band[3];
5 STRING name = "D:\\二进制数据.bin";
6 int nID = Open(name); //打开二进制文件
7 Seek(nID,21); //越过文件头,共字节
8 int i;
9 for(i=0; i<31; i=i+1){
10 Read(nID,str,7);
11 Read(nID,lon);
12 Read(nID,lat);
13 Read(nID,band);
14 Print("%s %f %f %f %f %f",str,lon,lat,band[0],band[1],band[2]);
15 }
16 Close(nID); //关闭二进制文件
17 }
这里没有使用程序清单7.2第1~6行定义的DATA结构。而读文本文件时使用了这个结构直接读取。这是因为在二进制文件中字符串内容被顺序写入,没有结束标识(0)。无法自动确定字符串的长度。因此单独定义了str、lon、lat和band[3]分别读取,并且根据上一节知道字符串的长度为7。并且已知有31行数据。
运行上述代码,输出为:
Rsd0001 121.914421 41.659408 226.000000 253.000000 253.000000
Rsd0002 121.920261 41.658179 181.000000 178.000000 193.000000
…
Rsd0031 121.837903 41.669697 253.000000 253.000000 253.000000
7.3其它文件操作
7.3.1文件长度
文件长度使用GetFileLen函数
longlong GetFileLen(STRING filename);
7.3.2删除文件
删除一个文件使用RemoveFile函数
int RemoveFile(STRING filename);
(更多内容暂缺)