1、 基于3D模式下海量数据的快速查询 0问题重述 在各种自动化现场,需要安装大量的测点,以便通过这些测点提交的信息来实现自动化流程的顺利进行。为了保证自动化现场所有设备的正常运行,需要将各测点提交的属性数据(监测结果)及时保存下来,以便于设备维护人员能够快速掌握现场设备的运行情况。一旦自动化现场的某设备出现故障,设备维护人员能够通过查询该设备的监控测点在某个时间段或时间点提交的属性数据来分析设备产生故障的原因。因此,为了及时排除故障和提高自动化的运行效率,设备维护人员需要迅速地查询任何测点在任何时刻提交的属性数据,这对于现场设备故障的及时排除和提高劳动生产力具有十分重要的意义。然而,监控现
2、场设备的测点多,每个测点提交的的信息量大,要从庞大的信息库中快速找到需要的信息是一件非常困难的事情。为此,实现海量属性数据的快速查询是急需解决的问题。 1问题分析 一个自动化现场安装有大量的测点, 通过这些测点的相互作用和相互牵制,从而实现自动化现场设备按照工艺流程以串行或并行的方式进行运行。因此,为保证设备的安全运行,需要将这些监控设备的测点提交的属性数据及时保存起来,在需要的时候能够快速查询任何测点提交的历史记录。然而,属性数据能否快速查询的关键取决于数据的存储方式,不同的存储方式决定了不同的查询方式。因此,为实现大量测点提交的海量数据的快速查询,需要为属性数据构建合理的存储格式,只有
3、在该存储结构的基础上才能实现海量属性数据的快速查询。 属性数据的存储方式不外乎两种,文本方式和二进行制方式。如果为每个测点专门分配一个存储文件,则会由于文件的数量太多而不便于管理,同时在不同文件之间来回切换也非常耗费时间。因此,为方便设备的管理和节省查询时间,需要对测点进行分类。也就是说,需要将众多测点在不同时刻提交的大量属性数据保存在同一个数据文件中,以方便数据的管理和查询。 具体来说,如果所有的测点中存在大量采样周期相同的测点,则可以将这些测点归为一类,从而将所有测点划归为不同的类。将测点按照采样周期分类后,就可以将同一类中的所有测点在不同时刻提交的大量属性数据保存在同一个数据文件中。
4、因此,为方便属性数据的查询,在该数据文件中既要说明属于该类的所有测点,同时又要说明这些测点提交属性数据的起始时刻和采样周期。除了这些参数的设置外,接下来就是属性数据的存放问题。如果数据文件用第一行存放测点的相关信息,那么从第二行开始就应该存放各测点在不同时刻提交的属性数据,故需要为实现快速查询而设计合理的存储结构。 在自动化现场的所有测点中,如果测点的周期一般都是各不相同,则需要根据地理位置将测点进行归类。如果存在众多测点的安装位置比较邻近,就可以将这些测点归为同一类,从而将所有测点划归为若干类。与按照测点周期分类不同,此时由于各测点的采样周期不同,故在同一数据文件中保存同一类测点提交的属性
5、数据时,对于每个测点,都要说明该测点的起始时刻和采样周期。因此,为方便后来的快速查询,需要为这些测点提交的属性数据建立合理的存储结构。由于每个测点都会在每个周期内提交属性数据,使得经过一段时间后,每个测点都会提交大量属性数据。将所有这些测点在不同时刻提交的属性数据保存起来,会占用大量的存储空间,同时也需要考虑后来的快速查询问题。 对于按照采样周期进行分类的测点而言,需要对测点进行编号,以便将不同的测点区分开来,同时满足同一类测点连续编号。如此一来,保存同一类测点提交的属性数据的结构就可以这样安排:(1)第一行存放四个参数:最小测点号、最大测点号、采样的起始时刻和采样周期;(2)从第二行开始存
6、放属性数据;(3)横向依次保存各测点在同一时刻提交的属性数据;(4)纵向保存不同时刻各测点提交的属性数据。为方便后面的叙述,不妨将这种存储结构称之为断面提交。 如果根据测点安装的地理位置进行分类,同样需要对测点编号以示区别,而同类测点为方便查询需要连续编号。对于如此分类的测点而言,其属性数据的存储结构如下:(1)先是保存第1个测点的三个参数:测点号、采样的起始时刻和采样周期;(2)从第二行开始,保存第1个测点在不同时刻提交的属性数据;(3)接着是第2个测点的参数设置和不同时刻属性数据的保存;(4)如此类推,进行其他测点的参数设置和不同时刻属性数据的保存。同样,不妨将这种存储方式称之为批量提交
7、 在查询某个测点在某个时刻提交的属性数据,首先要找到该测点在哪一个文件中,然后从该文件中根据时间找到该属性数据所在的行和列。因此,无论是断面提交还是批量提交,都是一个三维存储结构。 通过上面的分析,为实现任何测点在任何时刻提交的属性数据查询,需要解决断面提交数据和批量提交数据的快速查询问题。为此,需要深入分析断面提交数据和批量提交数据的存储结构,从中属性数据的存储规律,进而找出快速查询方法。此外,需要通过分析比较找出更加合理的存储结构。 2一个断面提交快速查询的实例 2.1断面提交的数据存储假设 如前所述,断面提交就是采样周期相同的测点根据采样时刻对数据进行分类存储,在每个采样周
8、期内依次存储各测点提交的属性数据。假设在断面提交文件夹中现有10个文本文件,每个文件都保存有1000个测点在10000个不同时刻所以提交的属性数据。文件的格式均满足:(1)第1行的四个整数依次为:连续编号的最小测点、连续编号的最大测点、数据采样的起始时间和数据的采样周期,而参数之间以空格分开;(2)从第2行开始,每行40个属性数据,数据之间以一个空格分开,而每个属性数据占6个字节;(3)每个文件的测点数为:连续编号的最大测点-连续编号的最大测点+1=1000;(4)每个采样周期内各测点提交的属性数据占25行;(5)总共保存有10000个不同时刻1000个测点提交的属性数据;(6)总共有个属性数
9、据,在数据文件中占行;(7)如果给文件编号,则第个数据文件中的测点范围从至。 在掌握了断面提交属性数据的存储结构以后,接下来就是如何实现数据的快速查询。一般来说,经常需要进行的查询就是问某测点在某个时刻提交的属性数据,进而了解该测点所检测的设备在该时刻的工作是否正常。因此,需要在断面提交的数据存储结构的基础上设计既准确又快速的数据查询方法。 2.2断面提交的符号约定 为方便断面提交数据的查询过程建模,需要对一些变量进行约定,具体表示如下。 (1)表示要查询的测点号;(2)表示要查询的时刻;(3)表示数据文件中的最小测点号;(4)表示文件中的最大测点号;(5)表示测点提交属性数据
10、的起始时刻;(6)表示提交属性数据的时间间隔(采样周期);(7)表示属性数据在二维表中所在的行;(8)表示属性数据在二维表中所在的列;(9)表示属性数据在线性表中的位置;(10)表示属性数据在文件中的地址;(11)表示文件的序号;(12)表示第个数据文件名。 2.3顺序读取属性数据的模型建立及求解 2.3.1顺序读取的模型建立 由前面的分析可知,由于断面提交是一个三维存储结构,为了在数据文件中查询测点在时刻提交的属性数据,首先必须知道该属性数据所在的文件。根据不同文件所存储的测点范围,可知该属性数据所在的文件号计算如下。
11、 (1) 根据式(1)选定了第个文件后,使得查询过程由3D 降为2D,接下来就是在该文件的平面结构中查询测点在时刻所提交的属性数据。 在每个断面提交文件中,属性数据都是从第2行开始存放,而第1行都是存放的四个参数(最小测点号,最大测点号,起始时刻和采样周期)。如果从逻辑上将所有的属性数据从左到右和从上到下看作不同时刻提交的属性数据,则整个数据文件就如同一个线性表,故只要知道该属性数据在线性表中的位置,就可以通过顺序读取的方式得到需要查询的属性数据。 由于属性数据在文件中存储格式是二维的,如果要从其逻辑上将其看作一维线性表,则必须知道该属性数据在二维
12、表中的行和列,然后通过行和列计算出该属性数据在线性表中的具体位置。不妨将文件中的个属性数据看作是一个的二维表,则根据由查询时间,侧点的起始时刻和采样周期可知要查询的属性数据在二维表中行的计算如下。 (2) 由和式(1)可知该属性数据所在二维表中列的计算如下。 (3) 由式(2)和式(3)可知该属性数据在线性表中的位置
13、 (4) 知道了属性数据在线性表中的位置,接下来就是如何将文件指针移到该属性数据的起始位置进行读取的问题。 2.3.2顺序查询属性数据的算法实现 通过断面提交数据的存储规律,查询测点在时刻所提交的属性数据的过程如下: (1)由和式(1)计算属性数据所在的文件号; (2)从文件号所对应的文件中读出第一行的四个整数,分别保存在、、和四个变量中,同时文件指针变量自动移向线性表的第一个属性数据的起始地址; (3)由式(2)计算出该属性数据所在的行; (4)由式(3)计算出该属性数据所在的列; (5)由式(4)计算出该属性数据在线性表中的位置; (6)从文件指针的当
14、前位置开始,从文件中依次连续读出个属性数据,则最后读出的属性数据就是需要查询的数据。 2.3.3断面提交顺序查询的模型分析 如果线性表的第一个属性数据即为所求,则只需要读一次外部文件。 如果线性表的最后一个属性数据是需要查询的数据,则需要读次外部文件。如果把此处的数据查询看作一个等概率事件,则平均读取次数为,即时间复杂度为。显然,在断面提交文件中用顺序读取的方式实现属性数据查询的速度很慢,其原因是为实现文件指针后移需要读取大量与查询结构无关的属性数据。显然,它的优点是对每行的属性数据个数以及每个属性数据的长度均没有限制,而它的缺点是查询速度慢。 本算法的程序源代码见附录1。 2.4随机
15、读取属性数据的模型建立 从上面的顺序查询属性数据的算法可知,为了读取第个属性数据,需要读取个与查询结果无关的属性数据。如果能够避开无关数据的读取,直接读取需要查询的数据,无疑大大提高了查询效率。实际上,如果知道属性数据在文件中的地址,就可以立即读取该数据。在顺序查询中,之所以要读取个与查询无关的属性数据,其目的是实现文件指针的后移,使文件指针最终指向需要查询的第个属性数据。如果能够直接计算出要查询的属性数据在文件中的地址,则将文件指针移到该地址,就可以直接读取需要查询的属性数据,而不需要读取与查询无关的大量属性数据。因此,接下来的工作重心就是要为计算属性数据地址而建模。 2.4.1用间接寻
16、址法实现随机查询 为便于研究,不妨先以第一个断面文件作为研究对象,探索属性数据在断面文件中的地址计算方法,然后将此规律推广到其他断面文件。如果,则根据式子(1)可知待查询的属性数据一定在第一个断面文件中。首先,该文件的第一行占16个字节,故第二行的第一个属性数据的地址为16。从第二行开始,由于每行有40个属性数据,而每个属性数据占6个字节,数据之间有一个空格,再加上每行的回车和换行,故每行占281个字节。 从文件的数据存储结构看,它实际是一个行40列的二维表。由式(4)求出的,可以计算该属性数据在二维表中所在的行如下。
17、 (5) 同样,由可以计算该属性数据在二维表中所在的列如下。 (6) 如果,则说明查询的时间超出范围。否则,待查询的属性数据在文件中的地址计算如下。 (7) 需要说明的是, 式(7)只适合第一个断面文件中属性数据的地址计算。也就是说,只适合的情形。 如果,由于文件第一行的四个参数占19个字节,故待查询的属性数据在文件中的地址计算如下。
18、 (8) 如果,由于文件第一行的四个参数占19个字节,故待查询的属性数据在文件中的地址如下。 (9) 之所以将方法称为间接寻址,是因为该方法需要先计算属性数据在线性表中的位置,然后由该位置计算属性数据在二维表中的行和列,最后通过行和列计算属性数据在断面文件中的起始地址。 要想通过上述方法实现属性数据的随机查询,断面文件的数据存储结构必须满足如下条件:(1)断面文件的第一行保存4个整数参数,分别表示最小测点号,最大测点号,起始时刻和采样周期,数
19、据之间用一个空格分开;(2)从第二行开始,每行40个属性数据,数据之间用一个空格分开;(3)总共1000个测点,每个测点提交10000个属性数据;(4)每个属性数据的长度为6位。如果这些条件有一条不满足,那么此处介绍的方法就不适用。 程序源代码见附录2。 2.4.2用直接寻址法实现随机查询 如前所述,所谓间接寻址就是先要求,然后通过再求属性数据所在的行和列,最后由行和列求属性数据在文件中的地址。能否不求也可以求出属性数据在文件中的地址呢。因此,把这种不需要求而直接求地址的方法称之为直接寻址法。 通过对第一个数据文件结构的研究分析发现,属性数据在二维表中的行计算如下。
20、 (10) 属性数据在二维表中的列计算如下。 (11) 有了式(10)和式(11),根据式(7)就可以计算出属性数据在第一个文件中的地址。 需要指出的是,以上地址计算只适合第一个数据文件的查询。要想实现任意文件数据的查询,则需要建立一个通用的求地址模型。由(1),有属性数据在文件中的行计算如下。 (12) 而属性数据在文件中的列计算如下。 (13) 有了式(12)和式(13),根
21、据式(7),或式(8),或式(9)就可以计算出属性数据在文件中的地址。 要想通过上述方法实现属性数据的随机查询,断面文件的数据存储结构必须满足如下条件:(1)断面文件的第一行保存4个整数参数,分别表示最小测点号,最大测点号,起始时刻和采样周期,数据之间用一个空格分开;(2)从第二行开始,每行40个属性数据,数据之间用一个空格分开;(3)总共1000个测点,每个测点提交10000个属性数据;(4)每个属性数据的长度为6位。如果这些条件有一条不满足,那么此处介绍的方法就不适用。 程序代码见附录3。 3改变文本文件存储结构以实现随机查询 上述的随机查询只适合每行40个属性数据的存储方式。如果
22、文本文件的每行存放1000个属性数据,则每行占个字节。 此时属性数据在文件中的行计算如下。 (14) 属性数据在文件中的列计算如下。 (15) 如果,则待查询的属性数据在文件中的地址如下。 (16) 如果,则待查询的属性数据在文件中的地址如下。 (17)
23、 如果,则待查询的属性数据在文件中的地址如下。 (18) 要想通过上述方法实现属性数据的随机查询,断面文件的数据存储结构必须满足如下条件:(1)断面文件的第一行保存4个整数参数,分别表示最小测点号,最大测点号,起始时刻和采样周期,数据之间用一个空格分开;(2)从第二行开始,每行1000个属性数据,数据之间用一个空格分开;(3)总共1000个测点,每个测点提交10000个属性数据;(4)每个属性数据的长度为6位。如果这些条件有一条不满足,那么此处介绍的方法就不适用。 程序代码见附录4和附录5。 4用文件的二进制存
24、储方式实现随机查询 上述断面提交的直接查询,无论是直接寻址还是间接寻址,都要求:(1)每行的属性数据量相同;(2)属性数据的长度相同;(3)数据之间只能有一个空格。如果不满足任何一个条件,上述直接查询的地址将无法计算。显然,这些条件都限制了这些模型的推广。因此,不妨进一步改变断面提交数据的存储方式。当数据文件以二进制的方式存储式时,则可以将文件看作一个行列的二维表,此时属性数据所在的行计算如下。 (19) 属性数据所在的列计算如下:
25、 (20) 属性数据在文件中的地址计算如下。 (21) 当以二进制方式存储断面提交的属性数据时,一方面不受上述条件的制约,另一方面比文本文件节省存储空间。因此,用二进制存储方式更能方便断面属性数据的存储和查询。 程序代码见附录6和附录7。 5一般断面提交数据的查询 上面的查询比较特殊,具体表现在:(1)只有10个断面数据文件;(2)每个文件都是1000个测点提交的属性数据;(3)属性数据的长度相等,都是6位。(4)每个测点提交10000个属性数据。然而,实际检测中的数据很难满足这些条件。
26、因此,为了使查询的范围更加广泛,必须构造更具一般性的数学模型。 5.1断面数据文件的一般特征 设一共有个文本文件,文件中的测点范围分别表示为,其中表示最小测点号,而表示最小测点号。为了实现测点的顺序编号,对测点号之间的关系规定如下。 (21) 如果用表示测点所在的文件号,则该文件号唯一且满足如下关系。 (22) 显然,文件号是唯一的。因此,总的测点数表示如下。
27、 (23) 假设第个文件中每个测点提交个属性数据,则第个文件中保存的属性数据的个数为 (24) 因此,所有测点提交的属性数据总和表示如下: (25) 此外,还应考虑每个属性数据的长度问题。假设每个文件中的属性数据的长度都相同,则既可以用文本文件也可以用二进制文件实现属性数据的快速存储与查询。如果同一个断面文件中属性数据的长度不唯一,则只能用二进制的存储结构。 5.2断面数据的文本
28、存储格式 总共有个文本文件,其中第个文件的数据格式如下: 第1行是4个整数,分别是最小测点,最大测点,测点的起始时刻和采样周期,数据之间用一个空格隔开。 从第二行开始,每行存放所有测点在一个采样周期内提交的属性数据,数据的长度都是,数据之间以一个空格隔开。由于要统计个不同时刻提交的属性数据,故所有的属性数据组成了一个行列的二维表。 5.3断面数据的顺序查询 首先,需要知道测点所在文本文件的文件号,由于(22)可以计算得到文件号。从第读出最小测点号,最大测点号,起始时刻和采样周期,则有下列关系式。
29、 (26) 其次,需要计算测点在时刻提交的属性数据所在的行和列。根据数据的存储结构,可以计算出属性数据所在的行 (27) 而属性数据所在的列计算如下。 (28) 如果将整个二维表看作一个从左到右,从上到下的线性表,则该属性数据在线性表中的位置计算如下。
30、 (29) 只需要从该文本文件读出个属性数据,则最后读出的属性数据是我们要查询的。需要说明的是,用此方法既适用于等长的属性数据也适用于不等长的属性数据。 5.4断面数据的随机查询 首先,从第个文本文件读出,,和,然后计算出这4个参数所在行所占的空间 (30) 如果属性数据等长,则需要查询的属性数据在文件中的位置计算如下: (31) 将文件指针定位在文件的处,然后从该处即可读出需要的属性数据。 6断面数据的二进制存储格式的查询 当所有的断面数据文件都以二进制方式存储,则每个属性数据均占4
31、个字节,而4个参数占16个字节。根据二进制的存储结构,可以计算出测点在时刻提交的属性数据在文件中的位置计算如下。 (32) 7断面提交一般查询模型的比较 对于一般的断面提交文件,顺序查找的速度最慢,无论是文本结构还是二进制结构,该方法都适用,而且对数据的长度没有要求。文本文件想用随机查找,则需要属性数据长度相同,否则该方法无效。如果断面文件采用二进制的存储方式,则既可以用顺序查找也可以用随机查找,很显然采用随机查找可以大大提高数据的查询效率。顺序查找的时间复杂度为,而随机查找的时间复杂度为。二进制存储方式对属性数据的长度
32、没有任何要求,同时比文本存储方式节省存储空间,故采用二进制存储方式可以极大地提高数据的查询效率。 批量提交数据的快速查询的数学建模 1批量提交数据的顺序查询 根据数据文件的结构,可以将整个数据文件看作一个线性表。如果知道要查询的属性数据在线性表中的位置,则通过顺序读取的方式就可以得到要查询的数据。如果将数据文件看作一个二维表,则文件又可以看作一个1000行10003列的二维表。如果知道要查询的数性数据所在的行和列,则通过行和列可以计算出该属性数据在线性表中的位置。 一方面,通过测点号可以计算出要查询的属性数据所在的文件号。
33、 (1) 另一方面,通过测点号可以计算出该属性数据在二维表中所在的行。 (2) 为了计算该属性数据在二维表中的列,需要先读取前行数据,使文件指针移向第的首位置。因此,需要读取的数据个数如下。 (3) 当从文件中顺序读完个数据后,就下来依次从文件的第行读出前3个整数,它们分别是测点号、起始时刻和采样周期,其中。通
34、过起始时刻和采样周期,可以计算出还需要读的属性数据的个数。 (4) 因此,该属性数据在二维表所在的列如下。 (5) 根据文件指针的当前位置,只要再读出个属性数据即可,则最后读出的数据即为所求。 程序代码见附录8 2批量提交数据的随机查询 2.1间接寻址实现随机查询 当将单个批量数据文件看作由1000个数据块组成,每个数据块由3个整数和10000个属性数据组成。从文件的存储结构
35、很容易发现,这10000个属性数据是的二维表。由于每个数据块的第一行的3个整数所占的空间大小不一,这为数据地址的计算带来不便。 如果用表示第1个数据快的3个整数所占的空间大小,用表示第2个数据快的3个整数所占的空间大小,如此类推,用表示第个数据快的3个整数所占的空间大小,其中。因此,的计算过程如下。 (6) 为了知道对应的和,需要计算第个数据块的起始地址。 (7) 先将文件指针定位在处,然后从该处读出和。 设要查询的属性数据是第个数据块中的
36、第个数据,则有 (8) 从而该属性数据所在的行计算如下。 (9) 属性数据所在的列计算如下。 (10) 因此,属性数据所在的地址计算如下。 (11) 从处读出的属性数据即为所求。 程序代码见附录9。 2.2直接寻
37、址实现随机查询 在算法2.1中,需要进行累加,而需要在读的过程中才能得到。为了做到这一点,需要建立索引文件,而索引文件的内容如下。 ,,,,,。 从索引文件中读出和,则测点所在数据块的起始地址为 (12) 将文件指针移到位置,然后读取。 设要查询的数据是第个数据块中的第个数据,则 (13) 根据属性数据在文件中的存放规律,可知该属性数据在第个数据块中的行
38、 (14) 和所在的列 (15) 从而计算出要查询的属性所在的地址为 (16) 因此,从该地址读出的属性数据即为所求。 程序代码见附录10和附录11。 需要说明的是,上述方法在读取和采用的顺序读取的方式。如果也想随机读取,则只需要用二进制方式存放索引即可。程序代码见附录12。 则此时可以实现属性数据和索引的双随机读取,代码见附录13。 2.3不用索引的直接寻址 之所以
39、无法计算属性数据的地址,是由于每个测点的三个参数所占的空间大小不一致造成的。如果能使这些参数所占的空间大小一样,则就可以直接计算属性数据的地址。在一个断面文件中,这三个参数占多大空间才比较合理?通过扫描这10个文件,发现从第一个到第9个文件中,最大的测点占4位,最大的起始时刻占3位,最大的采样周期占3位,故保存这3个参数至少需要14个字节的空间大小。而对于第10个文件,每3个参数需要15个字节的空间大小。 当对批量文件的格式进行转换后,就可以直接计算每个属性数据的地址,而不需要索引。首先,通过式(1)选择文件。其次,决定属性数据所在的数据快,其计算过程如下:
40、 (17) 为了得到测点的起始时刻和采样周期,需要得到这三个参数的起始地址,其计算过程如下: 如果,则 (18) 否则 (19) 从式(18)或式(19)计算的地址处读三个参数:,,。首先,计算该属性数据在数据块中的位置: (20) 其次,计算该属性数据在数据块中的行:
41、 (21) 最后,计算该属性数据在数据块中的列: (22) 因此,计算该属性数据在文件中的地址计算如下: 如果,则 (23) 否则 (24) 有了式(23)或式(24)计算的地址后,从该地址处所读的数据就是需要查询的属性数据。 2.5将二维表转化为线性表的存
42、储结构 此时,由式(17)可知第个数据块的起始地址计算如下: 如果,则 (25) 否则 (26) 从式(25)或式(26)计算的地址处读三个参数,则属性数据在线性表中的位置计算如下: (27) 从而属性数据的地址计算如下: 如果,则
43、 (28) 否则 (29) 有了式(28)或式(29)计算的地址后,从该地址处所读的数据就是需要查询的属性数据。 附录1 #include"stdio.h" #include"stdlib.h" #include"string.h" void main() { char P[11][50]; strcpy(P[1],"软件大赛测试数据\\断面提交\\shots_tag_1-1001.txt"); strcpy(P[2],"软件大赛测试数据\\断
44、面提交\\shots_tag_1001-2001.txt"); strcpy(P[3],"软件大赛测试数据\\断面提交\\shots_tag_2001-3001.txt"); strcpy(P[4],"软件大赛测试数据\\断面提交\\shots_tag_3001-4001.txt"); strcpy(P[5],"软件大赛测试数据\\断面提交\\shots_tag_4001-5001.txt"); strcpy(P[6],"软件大赛测试数据\\断面提交\\shots_tag_5001-6001.txt"); strcpy(P[7],"软件大赛测试数据\\断面提交\\
45、shots_tag_6001-7001.txt"); strcpy(P[8],"软件大赛测试数据\\断面提交\\shots_tag_7001-8001.txt"); strcpy(P[9],"软件大赛测试数据\\断面提交\\shots_tag_8001-9001.txt"); strcpy(P[10],"软件大赛测试数据\\断面提交\\shots_tag_9001-10001.txt"); int m_id,m_time; printf("请输入测点和时间:"); scanf("%d%d",&m_id,&m_time); if(m_id<1||m_id
46、>10000) { printf("测点号超出范围(1-10000)"); exit(0); } int page=(m_id-1)/1000+1; FILE *fp=fopen(P[page],"r"); if(fp==NULL) { printf("文件不存在"); exit(0); } int begin_id,end_id,begin_time,T; fscanf(fp,"%d%d%d%d",&begin_id,&end_id,&begin_time,&T); int r=(m_time-begin_tim
47、e)/T+1; if(r>10000) { printf("查询时间超出范围"); exit(0); } int c=m_id-1000*(page-1); int n=1000*(r-1)+c; float x; for(int i=1;i<=n;i++) fscanf(fp,"%f",&x); fclose(fp); printf("data=%f\n",x); system("pause");} 附录2 #include"stdio.h" #include"stdlib.h" #incl
48、ude"string.h" void main() { char P[11][50]; strcpy(P[1],"软件大赛测试数据\\断面提交\\shots_tag_1-1001.txt"); strcpy(P[2],"软件大赛测试数据\\断面提交\\shots_tag_1001-2001.txt"); strcpy(P[3],"软件大赛测试数据\\断面提交\\shots_tag_2001-3001.txt"); strcpy(P[4],"软件大赛测试数据\\断面提交\\shots_tag_3001-4001.txt"); strcpy(P[5],"软件大赛测
49、试数据\\断面提交\\shots_tag_4001-5001.txt"); strcpy(P[6],"软件大赛测试数据\\断面提交\\shots_tag_5001-6001.txt"); strcpy(P[7],"软件大赛测试数据\\断面提交\\shots_tag_6001-7001.txt"); strcpy(P[8],"软件大赛测试数据\\断面提交\\shots_tag_7001-8001.txt"); strcpy(P[9],"软件大赛测试数据\\断面提交\\shots_tag_8001-9001.txt"); strcpy(P[10],"软件大赛测试数据\
50、\断面提交\\shots_tag_9001-10001.txt"); int m_id,m_time; printf("请输入测点和时间:"); scanf("%d%d",&m_id,&m_time); if(m_id<1||m_id>10000) { printf("测点号超出范围(1-10000)"); exit(0); } int page=(m_id-1)/1000+1; FILE *fp=fopen(P[page],"r"); if(fp==NULL) { printf("文件不存在"); exit(0)






