feiyu02
2025-09-12 61871594dfa0a5ac2c4d895d9ec4034feba57094
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package com.flightfeather.uav.biz.dataprocess
 
import com.flightfeather.uav.common.utils.ExcelUtil
import com.flightfeather.uav.lightshare.bean.DataVo
import com.flightfeather.uav.socket.eunm.FactorType
import org.apache.poi.xssf.streaming.SXSSFWorkbook
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
 
/**
 * 数据处理
 * 目标:小时数据、日数据和日变化3类
 * 指标:对每类数据,计算记录数、均值、标准差、最小值、最大值;如果计算量可接受,计算10/25/50/75/90  %分位值。
 * 输出样式:(列数据)时间、记录数、均值、标准差、最小值、最大值,分位值;时间可以是yyyymmddhh…简化格式或标准时间格式;小时数据标记后记(时间记在后,如17时表示16~17时之间的结果)或前记方式,日变化的小时亦同。
 */
class DataProcess(
    private val outPutPath: String
) {
    companion object {
        const val SHEET1 = "小时数据"
        const val SHEET2 = "日数据"
        const val SHEET3 = "日变化"//需要计算的项目
        val needFactor: List<FactorType> = listOf(
            FactorType.NO2,
            FactorType.CO,
            FactorType.H2S,
            FactorType.SO2,
            FactorType.O3,
            FactorType.PM25,
            FactorType.PM10,
            FactorType.VOC
        )
        val items = listOf(
            "记录数", "均值", "标准差", "最小值", "最大值", "10%分位值", "25%分位值", "50%分位值", "75%分位值", "90%分位值"
        )
 
    }
    //每日小时数据
    private val dateData = mutableMapOf<String?, PreData>()
    //每日数据
    private val dayData = mutableMapOf<String?, PreData>()
    //日小时变化数据
    private val dailyVariationData = mutableMapOf<String?, PreData>()
 
    //写入excel文件
    private var workBook = SXSSFWorkbook(1000)
    //输出流
    private lateinit var out: FileOutputStream
    //输入流
    private lateinit var input: FileInputStream
    //excel 每张sheet当前写入的行数
    private val sheetRow = mutableMapOf<String, Int>().apply {
        put(SHEET1, 0)
        put(SHEET2, 0)
        put(SHEET3, 0)
    }
 
    init {
        outPutHead()
    }
 
    /**
     * 执行数据预处理
     * 1. 单次输入的数据要求为一天的数据,输入后会直接计算“每日小时数据”和“每日数据”的结果并写入excel
     * 2. 日小时变化数据由于跨日统计,需要手动调用
     */
    fun process(dataList: List<DataVo>) {
        dateData.clear()
        dayData.clear()
//        dailyVariationData.clear()
        dataList.forEach {
            val date = it.time?.substring(0, 13)
            val day = it.time?.substring(0, 10)
            val hour = it.time?.substring(11, 13)
 
            if (!dateData.containsKey(date)) {
                dateData[date] = PreData(date)
            }
            dateData[date]?.add(it)
 
            if (!dayData.containsKey(day)) {
                dayData[day] = PreData(day)
            }
            dayData[day]?.add(it)
 
            if (!dailyVariationData.containsKey(hour)) {
                dailyVariationData[hour] = PreData(hour, needQuartile = false)
            }
            dailyVariationData[hour]?.add(it)
        }
 
        outPut()
    }
 
    /**
     * 输出文档标题
     */
    private fun outPutHead() {
        val file = File(outPutPath)
        out = FileOutputStream(file)
 
        val contents = mutableListOf<Array<Any>>()
        //第一行为时间以及监测因子名称,并且需要根据下一行的统计项合并列
        val firstRow = mutableListOf<ExcelUtil.MyCell>()
        firstRow.add(ExcelUtil.MyCell("时间", 2))
        needFactor.forEach { firstRow.add(ExcelUtil.MyCell(it.des, colSpan = items.size)) }
        contents.add(firstRow.toTypedArray())
        //第二行为每种监测因子对应的统计项,具体为记录数、均值、标准差、最小值、最大值、10/25/50/75/90%分位值,每种监测因子有10列
        val secondRow = mutableListOf<String>()
        secondRow.add("")
        repeat(needFactor.size) { secondRow.addAll(items) }
        contents.add(secondRow.toTypedArray())
        //分sheet建立标题
        sheetRow.forEach { (s, i) ->
            val row = ExcelUtil.write(emptyList(), contents, workBook, s, i)
            sheetRow[s] = row
        }
        workBook.write(out)
        workBook.close()
        out.flush()
        out.close()
    }
 
    /**
     * 写入每日小时数据和每日数据结果
     * 自动调用, 要求输入的数据以每日为一组
     */
    private fun outPut() {
        input = FileInputStream(outPutPath)
        workBook = SXSSFWorkbook(XSSFWorkbook(input), 1000)
        out = FileOutputStream(outPutPath)
        //第三行开始为计算结果,每种监测因子都有对应的一系列统计项
 
        //每日小时数据
        val contents = mutableListOf<Array<Any>>()
        dateData.forEach { (_, pData) ->
            contents.add(pData.getOutPutContent())
        }
        sheetRow[SHEET1] = ExcelUtil.write(emptyList(), contents, workBook, SHEET1, sheetRow[SHEET1] ?: 0)
 
        //每日数据
        contents.clear()
        dayData.forEach { (_, pData) ->
            contents.add(pData.getOutPutContent())
        }
        sheetRow[SHEET2] = ExcelUtil.write(emptyList(), contents, workBook, SHEET2, sheetRow[SHEET2] ?: 0)
 
        workBook.write(out)
        workBook.close()
        input.close()
        out.flush()
        out.close()
    }
 
    /**
     * 写入日小时变化数据
     * 手动调用
     */
    fun outPutDailyVariation() {
        input = FileInputStream(outPutPath)
        workBook = SXSSFWorkbook(XSSFWorkbook(input), 1000)
        out = FileOutputStream(outPutPath)
        //日小时变化数据
        val contents = mutableListOf<Array<Any>>()
        dailyVariationData.forEach { (_, pData) ->
            contents.add(pData.getOutPutContent())
        }
        sheetRow[SHEET3] = ExcelUtil.write(emptyList(), contents, workBook, SHEET3, sheetRow[SHEET3] ?: 0)
 
        workBook.write(out)
        workBook.close()
        input.close()
        out.flush()
        out.close()
    }
 
    /**
     * 数据处理结束
     * 调用以关闭输出流,释放内存
     */
    fun done() {
        workBook.close()
        input.close()
        out.flush()
        out.close()
    }
}