<think>我们面对的任务是:在Excel中,根据某一列(假设为A列)的空白单元格作为分界点,对相邻列(假设为B列)的数据进行分组求和。
思路:空白单元格将数据分成连续的块,每个块从空白单元格之后开始,到下一个空白单元格之前结束(或到数据末尾)。我们需要对每个块内的B列数据求和。
方法一:使用SUMIF函数配合辅助列
步骤1:在C列创建辅助列,用于标记每个分组。在C1输入公式(假设数据从第1行开始):
=IF(A1="", "Group"&ROW(), C1)
解释:如果A1是空白,则创建一个以当前行号命名的组标记(例如Group1);否则沿用上一个非空白单元格的组标记(即上一个空白行创建的组标记)。
注意:这个公式需要向下填充,但第一个单元格如果是非空白,会返回错误,因此需要调整起始点。
调整:通常第一个单元格可能是非空白,我们可以从第一个非空白单元格开始,但为了通用性,可以修改公式:
=IF(A1="", "Group"&ROW(), IF(ROW()=1, "Group1", C1))
但这样写会循环引用,所以不能直接引用自身。因此,我们采用另一种方式:从C2开始,C1单独处理。
改进步骤:
在C1输入:=IF(A1="", "Group1", "Group1")
在C2输入:=IF(A2="", "Group"&ROW(), C1)
然后向下填充。这样,当A列出现空白时,就会用当前行号创建一个新组名,否则沿用上一个组名。
步骤2:使用SUMIF函数对每个组进行求和。在D列(或其他列)列出组名(可以通过复制C列然后去重得到),然后在相邻列使用:
=SUMIF(C:C, 组名, B:B)
方法二:使用SUMIF函数,不创建辅助列(但需要确定分组条件)
另一种思路:空白行将数据分组,我们可以利用空白行之间的行范围来求和。但这样需要动态确定范围,比较复杂。
方法三:使用SUBTOTAL函数结合筛选(手动操作)
但用户要求公式计算,所以不推荐。
方法四:使用数组公式(较复杂)
但考虑到用户可能需要自动化的公式,我们可以尝试使用一个公式完成。
然而,经过搜索和思考,更简洁的方法是使用SUMIF函数,但需要构建一个动态的分组标识。我们可以使用一个常见的技巧:利用非空单元格累计分组。
推荐方法(无需辅助列,一个公式求和):
在C列(或其他空白列)的每个单元格输入以下公式,然后按Ctrl+Shift+Enter(数组公式)?实际上,我们可以用普通公式:
步骤:在第一个分组求和的位置(比如D1)输入:
=SUM(OFFSET(B1,0,0,IFERROR(ROW(OFFSET($A$1,MATCH(2,1/($A$1:A1=""),1))),0)-ROW(),1))
这个公式非常复杂,而且容易出错。
实际上,更简单的方法还是使用辅助列。因此,我们重点介绍辅助列方法。
方法一详细步骤:
1. 在C1单元格输入:=IF(A1="", "Group"&ROW(), "Group1")
2. 在C2单元格输入:=IF(A2="", "Group"&ROW(), C1)
3. 将C2单元格向下填充至数据末尾。
4. 在D列(或其他列)列出唯一的组名:可以手动复制C列,然后“删除重复项”得到唯一组名,或者使用公式(但需要知道组数)。
5. 在E列对应每个组名,输入公式:=SUMIF(C:C, D1, B:B) 并下拉。
但是,如果用户希望求和结果出现在每个分组的最后一行旁边,则可以在C列构建辅助列后,在D列写公式:
=IF(A1="", SUM(B1:INDIRECT("B"&ROW()-1)), "")
这个公式有逻辑错误,因为无法知道上一个空白行的位置。
因此,我们采用另一种辅助列方法:在空白行处显示该分组的求和结果。
步骤:
1. 在C列,从第一个空白行开始,输入公式(假设第一个空白行在A5):
=SUM(B2:B4) # 这里B2:B4是上一个空白行到当前空白行之间的区域
但这样需要手动调整范围。
自动化的方法:
在C1输入公式(数组公式,按Ctrl+Shift+Enter):
=IF(A1="", SUM(B1:INDEX(B:B, IFERROR(IF(MATCH(1, --(A2:A$1000<>""),0), ROW(B$1000)))), "")
这个公式很复杂,而且容易出错。
经过搜索,有一个更巧妙的公式(非数组公式):
=IF(A1="", SUM(INDEX(B:B, LOOKUP(2,1/(A$1:A1=""), ROW(A$1:A1))+1):B1), "")
解释:当A1是空白时,计算从上一个空白行(不包括该空白行)的下一行开始,到当前空白行的上一行(即当前空白行所在行号减1)的求和。但注意,这个公式是放在空白行对应的C列单元格的。
公式说明:
LOOKUP(2,1/(A$1:A1=""), ROW(A$1:A1))
这个部分用于查找当前行(比如第5行)之前的最后一个空白行所在的行号。注意,在公式中,A$1:A1是相对引用,当公式在C5时,范围是A$1:A5。
然后,我们取该空白行的下一行(+1)到当前行(B1,但这里应该是B5)?不对,因为当前行是空白行,我们要求的是上一个空白行到当前空白行之间的数据,即上一个空白行下一行到当前行上一行。
因此,公式修改为:
=IF(A1="", SUM(INDIRECT("B" & LOOKUP(2,1/(A$1:A1=""), ROW(A$1:A1))+1 & ":B" & ROW()-1)), "")
注意:这个公式要放在每个空白行对应的C列单元格中。例如,如果A5是空白,则放在C5,那么它会求从上一个空白行(比如A1是空白,则行号是1)的下一行(第2行)到当前行上一行(第4行)的B列数据求和。
但是,第一个空白行之前的数据(如果数据从第1行开始且第1行非空白)怎么办?第一个空白行之前的求和范围是从第1行到当前空白行的上一行。
因此,我们需要处理第一个空白行之前没有空白行的情况。我们可以使用:
=IF(A1="", SUM(INDIRECT("B" & IFERROR(LOOKUP(2,1/(A$1:A1=""), ROW(A$1:A1))+1,1) & ":B" & ROW()-1)), "")
这样,如果找不到空白行,则从第1行开始。
但是,这个公式在第一个单元格就是空白的时候会出错(因为ROW()-1=0)。因此,我们假设第一个空白行不会出现在第一行?或者调整。
另外,如果最后一行不是空白,那么最后一个分组不会被求和。因此,我们还需要在最后添加一个空白行?或者单独处理最后一个分组。
这种方法比较复杂,且容易出错,因此推荐使用辅助列标记分组,然后SUMIF的方法。
总结:推荐使用辅助列方法(方法一)的步骤。
然而,根据用户意图,我们也可以使用数据透视表:
方法五:使用数据透视表
1. 创建辅助列(同方法一)标记分组。
2. 选择数据区域,插入数据透视表。
3. 将分组辅助列拖到行区域,将需要求和的列拖到值区域(汇总方式为求和)。
但用户要求公式,所以数据透视表可能不是用户想要的。
因此,我们提供两种公式方法:
方法A(辅助列+SUMIF):
步骤1:在C1输入:=IF(A1="", "Group"&ROW(), "Group1")
步骤2:在C2输入:=IF(A2="", "Group"&ROW(), C1) 并向下填充。
步骤3:在需要显示求和结果的位置(比如D列),针对每个分组显示一次(可以在每个分组的第一行显示,或者最后一行显示)?这里用户没有指定,所以我们可以选择在辅助列旁边用SUMIF,但这样每个分组会有多个相同的求和值。或者我们可以在每个空白行显示该分组的求和值,那么可以在C列公式的基础上修改:将求和公式放在空白行对应的D列。
修改步骤:
步骤1:辅助列仍然需要(用于标识分组)。
步骤2:在D列输入:=IF(A1="", SUMIF(C:C, C1, B:B), "")
这样,在空白行处就会显示该分组的求和值。
方法B:复杂公式(不需要辅助列,但公式较长):
在空白行对应的C列输入:
=IF(A1="", SUM(INDIRECT("B" & IFERROR(LOOKUP(2,1/($A$1:A1=""), ROW($A$1:A1))+1,1) & ":B" & ROW()-1)), "")
注意:公式中的$A$1:A1 是混合引用,当公式向下填充时,范围会扩展到当前行。ROW()-1 表示当前行上一行。
测试:假设数据从第1行开始。
第1行:A1非空白,则C1显示空白。
第2行:A2非空白,C2显示空白。
第3行:A3空白,则C3显示公式结果:求B1:B2的和(因为上一个空白行不存在,所以从第1行开始到第2行)。
第4行:A4非空白,C4空白。
第5行:A5空白,则C5显示:求B4:B4的和?因为上一个空白行在第3行,所以从第3行的下一行(第4行)到第4行(第5行上一行)的和。
这个公式在最后一个分组没有空白行标记的情况下不会显示求和结果。因此,如果用户希望最后一个分组也有求和结果,则需要在数据末尾添加一个空白行?或者将公式调整到每个分组的第一行?这不符合要求。
因此,我们推荐方法A,因为方法A可以轻松地显示每个分组的求和值,而且可以在任意位置显示(通过SUMIF函数)。
最终,我们给出两种方法,但方法A更简单可靠。
方法A详细步骤:
1. 在C1单元格输入公式:=IF(A1="", "Group"&ROW(), "Group1")
2. 在C2单元格输入公式:=IF(A2="", "Group"&ROW(), C1)
3. 将C2单元格向下填充至数据末尾。
4. 在D1单元格输入公式:=IF(A1="", SUMIF(C:C, C1, B:B), "")
5. 将D1单元格向下填充至数据末尾。
这样,D列会在每个空白行显示该分组的求和值。
注意:分组标记(如Group1, Group3等)在非空白行也会显示,但D列只在空白行显示求和值。如果用户希望在每个分组的第一行显示求和值,则需要对公式进行调整。
如果用户希望求和结果显示在每个分组的上方(即空白行),那么上述步骤即可。
示例数据:
A列 B列 C列 D列
1 10 Group1
2 20 Group1
3 30 Group1
4 (空白) 40 Group4 60 (因为B1:B3求和=60)
5 50 Group4
6 (空白) 60 Group6 110 (因为B4:B5求和=90?不对,B4是40,B5是50,所以90?但示例中D4显示60,D6显示110?不对,因为D4显示的是Group1的求和(10+20+30=60),D6显示的是Group4的求和(40+50=90),但公式中D6的SUMIF(C:C, C6, B:B) 是求Group6,而Group6只有当前行(第6行)?因为分组标记在空白行才创建新组,所以第4行和第5行是Group4,第6行是Group6(空白行),所以SUMIF(C:C, "Group6", B:B) 只会求第6行(空白行对应的B列)?但第6行B列是60,所以结果是60?这显然不对。
错误原因:在D列的公式中,我们在空白行使用SUMIF(C:C, C1, B:B),但当前行的分组标记是当前行创建的组名(如Group4),而该分组实际上包括从上一个空白行(第4行)到下一个空白行(第6行)之间的所有行(第4行和第5行),但第4行是空白行,我们通常希望分组是从第5行到第5行(因为第6行是下一个空白行)?不对,分组逻辑是:空白行是分界点,分组包括从上一个空白行(不包括)到当前空白行(不包括)之间的行?但我们的分组标记是:从当前空白行开始,直到下一个空白行之前,都属于同一个组(组名是当前空白行的行号)。因此,第4行的空白行创建了Group4,然后第5行沿用Group4,第6行是空白行,创建Group6。那么Group4包括第4行和第5行?但第4行是空白行,我们通常不希望空白行被包括在分组内。
修正分组标记逻辑:我们希望分组标记只标记非空白行,空白行本身不属于任何分组(或者属于一个空分组)。因此,修改辅助列公式:
在C1输入:=IF(A1<>"", "Group"&MAX(C$1:C1)+1, "") 这样不行,因为循环引用。
重新设计辅助列:
我们让空白行的辅助列为空,非空白行的辅助列为上一个非空白行的组名(如果遇到空白行,则下一个非空白行使用新的组名,但空白行不创建组名,而是由下一个非空白行创建)。
步骤:
1. 在C1输入:=IF(A1="", "", "Group1")
2. 在C2输入:=IF(A2="", "", IF(A1="", "Group"&ROW(), C1))
并向下填充。
这样,在非空白行,如果上一行是空白,则创建新的组名(以当前行号命名),否则沿用上一行的组名。空白行则留空。
然后,在D列,我们可以在每个空白行显示上一个分组的求和,但注意,分组标记在非空白行。我们可以这样:
在D1输入:=IF(A1="", SUMIF(C:C, C1, B:B), "") 但C1可能是空白(如果A1是空白),所以这样不行。
因此,我们改为:在分组结束后的空白行显示该分组的求和,那么我们可以:
在D1输入:=IF(A1="", SUMIF(C:C, "Group"&ROW(), B:B), "")
这样,当A1是空白时,我们求Group1(即ROW()=1)的求和。但是,分组标记的组名并不是以当前空白行的行号命名的,而是以创建该分组时的行号命名的。
在辅助列中,分组标记的创建是在非空白行且上一行是空白时,以当前行号创建组名。因此,每个分组的组名就是该分组第一个非空白行的行号。
那么,在空白行,我们如何知道它前面的分组是哪个组?实际上,空白行前面的分组就是最近创建的那个组。但是,我们无法直接知道。
因此,我们改变策略:在分组标记列,我们不仅标记非空白行,而且在空白行也标记(标记为上一个分组的组名)?不行,空白行应该作为分界。
经过重新思考,我们采用最初的方法,但调整分组标记的创建:空白行创建组名,但该组名用于标记接下来的非空白行,直到下一个空白行。因此,空白行创建的组名,实际上是为接下来的非空白行分组。那么,在空白行,我们可以求它之前创建的分组(即上一个空白行创建的分组)的求和。
例如:
第1行:A1空白,则C1="Group1",然后D1=SUMIF(C:C, "Group1", B:B) -> 此时,Group1还没有任何非空白行,所以求和为0。
第2行:A2非空白,则C2=C1="Group1"
第3行:A3非空白,则C3=C2="Group1"
第4行:A4空白,则C4="Group4",D4=SUMIF(C:C, "Group1", B:B) -> 这里我们要求Group1的求和(即第2行和第3行),但D4的公式中组名是C4(Group4),所以不对。
因此,我们需要在空白行求上一个分组的求和,即Group1(而不是Group4)。如何得到上一个分组的组名?我们可以记录上一个空白行创建的组名。
修改辅助列:增加一列记录上一个分组的组名。
这会使问题复杂化。
鉴于时间,我们提供一种可靠且简单的方法:使用两个辅助列。
列C:分组标记(用于非空白行)
列D:分组求和结果(放在空白行)
步骤:
1. 在C1输入:=IF(A1="", "", IF(ROW()=1, "Group1", IF(A1<>"", C1, ...))) 循环引用,不行。
最终,我们采用以下方法:
辅助列C(分组标记):
C1: =IF(A1="", "", "Group1")
C2: =IF(A2="", "", IF(A1="", "Group"&ROW(), C1))
向下填充。
辅助列D(分组求和):
D1: =IF(A1="", "", IF(A2="", SUMIF(C:C, C1, B:B), ""))
这个公式在非空白行,且下一行是空白行时,显示当前分组的求和。但这样最后一个分组可能无法显示。
或者,我们在空白行的上一行显示分组求和:
D1: =IF(A2="", SUMIF(C:C, C1, B:B), "") # 放在第1行,判断第2行是否空白
然后向下填充。这样,在分组结束前一行(即空白行的上一行)显示求和。
示例:
第1行:A1非空白,A2非空白 -> D1空白。
第2行:A2非空白,A3非空白 -> D2空白。
第3行:A3非空白,A4空白 -> D3=SUMIF(C:C, C3, B:B) 即求Group1的求和(包括第1,2,3行)。
第4行:A4空白 -> D4空白。
这样,用户可以看到在分组结束的前一行(第3行)显示了求和。但用户要求在空白行显示,所以不符合。
因此,我们回到最初的方法A,但修改SUMIF的范围,只求和 non-empty cells in B for the group, and we exclude the blank row itself.
最初的方法A(带辅助列):
C1: =IF(A1="", "Group"&ROW(), "Group1")
C2: =IF(A2="", "Group"&ROW(), C1) [向下填充]
D1: =IF(A1="", SUMIF(C:C, C1, B:B), "") [向下填充]
问题:SUMIF会把当前行(空白行)的B列值也加进去,而空白行的B列可能有数值,也可能没有。但我们的分组本不该包括空白行。
解决:在SUMIF中,我们 exclude the rows where A is blank. But the criteria range is C:C, and the criteria is the group name. 空白行也被标记为组名,所以会被包括。
因此,我们修改SUMIF为SUMIFS,增加一个条件:A列非空白。
=IF(A1="", SUMIFS(B:B, C:C, C1, A:A, "<>"), "")
这样,求和时只求A列非空白的行。
示例数据:
Row1: A1="", C1="Group1", D1=SUMIFS(B:B, C:C, "Group1", A:A, "<>") -> Group1组中A列非空白的行?Group1组只有第1行(A1空白)所以不包括,求和0。
Row2: A2=non-blank, C2=Group1, D2=""
Row3: A3=non-blank, C3=Group1, D3=""
Row4: A4="", C4="Group4", D4= Group4组求和:Group4组中A列非空白的行?Group4组目前只有第4行(A4空白)所以求和0。
这显然不对。
原因:分组标记列C,在非空白行才应该被标记为组名,空白行虽然标记了组名,但我们是希望这个组名用于接下来的非空白行(即从当前空白行下一行开始直到下一个空白行之前)。但我们的辅助列在空白行也标记了组名,而且SUMIFS会 includes the blank row.
因此,我们改变分组标记的策略:空白行创建组名,但接下来的非空白行才属于这个组,空白行本身不属于任何组(即C列在空白行为组名,在非空白行为该组名,但求和时我们只求非空白行)。
辅助列C:
C1: =IF(A1="", "Group"&ROW(), "") # 空白行创建组名,非空白行暂时留空
C2: =IF(A2="", "Group"&ROW(), IF(A2<>"", C1, "")) # 非空白行,沿用上一个非空白的C列值(即最近的一个组名)
然后向下填充。
示例:
Row1: A1空白 -> C1="Group1"
Row2: A2非空白 -> C2=C1="Group1"
Row3: A3非空白 -> C3=C2="Group1"
Row4: A4空白 -> C4="Group4"
Row5: A5非空白 -> C5=C4="Group4"
然后,在D列,我们可以在空白行显示该分组的求和(即 Group1 的求和,Group1包括第2,3行):
D1: =IF(A1="", SUMIF(C:C, C1, B:B), "") # 但C1="Group1", SUMIF will sum B:B where C:C="Group1", which includes row2 and row3, and also row1? But row1 has C1="Group1", but row1 is blank in A, and B1 might have value or not. We only want non-blank rows in A for the group.
问题:第1行是空白行,它属于Group1,但我们求和时不应该包括它。所以,我们用SUMIFS加上条件:A列非空白。
=IF(A1="", SUMIFS(B:B, C:C, C1, A:A, "<>"), "")
现在,Group1的求和只会包括C列为Group1且A列非空白的行,即第2行和第3行。
示例数据:
A1: blank -> Group1
A2: non-blank, C2=Group1 -> included in sum for Group1.
A3: non-blank, C3=Group1 -> included.
A4: blank -> Group4, then D4= SUMIFS for Group4 will include future non-blank rows until next blank.
但是,最后一个分组(比如没有 closing blank)不会被求和,因为我们只在空白行显示求和。所以,用户需要在数据最后加一个空白行来触发最后一个分组的求和。
步骤总结:
1. 在C1输入:=IF(A1="", "Group"&ROW(), "")
2. 在C2输入:=IF(A2="", "Group"&ROW(), IF(A2<>"", C1, ""))
3. 将C2公式向下填充。
4. 在D1输入:=IF(A1="", SUMIFS(B:B, C:C, C1, A:A, "<>"), "")
5. 将D1公式向下填充。
注意:确保数据最后一行是空白行,以便显示最后一个分组的求和。
示例数据 walk through:
Row A B C D
1 5 "Group1" =IF(A1="", SUMIFS(B:B, C:C, "Group1", A:A, "<>"), "") -> will sum rows where C="Group1" and A non-blank. Currently, no such rows (row1 is blank in A, so not included), so 0.
2 X 10 "Group1" D2=""
3 Y 20 "Group1" D3=""
4 ? "Group4" D4= sum for Group1: rows2 and row3 -> 30.
5 Z 15 "Group4" D5=""
6 ? "Group6" D6= sum for Group4: row5 -> 15.
在D1和D4, D6显示求和结果,分别为0, 30, 15。注意,D1=0 because there are no non-blank rows in A yet for Group1 until row2 and row3.
但是, Group1对应的非空白行是第2行和第3行,所以 ideally we want the sum for Group1 to appear in row4 (the next blank row) and it should be 30, which it is.
所以,这个方法可行。
因此,我们给出以下步骤:
步骤1:在C1单元格输入公式:=IF(A1="", "Group"&ROW(), "")
步骤2:在C2单元格输入公式:=IF(A2="", "Group"&ROW(), IF(A2<>"", C1, ""))
步骤3:选中C2单元格,拖动填充柄向下填充至数据末尾。
步骤4:在D1单元格输入公式:=IF(A1="", SUMIFS(B:B, C:C, C1, A:A, "<>"), "")
步骤5:选中D1单元格,拖动填充柄向下填充至数据末尾。
步骤6:为了显示最后一个分组的求和,确保数据最后一行为空白行(即在A列最后一行为空白)。
注意:如果数据最后一行不是空白,则最后一个分组不会在D列显示求和结果。用户可以选择在数据下方加一个空白行。
另外,也可以用一个公式 in the last row to force display the last group's sum, but that would be more complicated.
我们推荐用户确保数据下方有一个空白行。
如果用户不想看到C列的内容,可以隐藏C列。
公式替代: without helper column? 网上有复杂的数组公式,但鉴于可读性, helper column is better.
因此,我们提供 helper column 方法。
注意:如果数据量很大, helper column may slow down the workbook.
如果用户不希望使用 helper column,我们可以提供 array formula,但较复杂。
鉴于时间,我们提供 helper column 方法。
相关问题部分:基于用户原始问题,我们生成相关问题。
注意:最后必须添加相关问题部分。</think>### Excel根据某一列的空白单元格对相邻列数据进行分组求和
#### 方法一:辅助列 + SUMIFS函数(推荐)
1. **创建分组标识列(C列)**
- C1输入:`=IF(A1="", "Group"&ROW(), "")`
- C2输入:`=IF(A2="", "Group"&ROW(), IF(A2<>"", C1, ""))`
- 将C2公式向下填充至数据末尾
*原理:空白行生成新组名(如"Group1"),后续非空行继承该组名。*
2. **在空白行显示分组求和结果(D列)**
- D1输入:`=IF(A1="", SUMIFS(B:B, C:C, C1, A:A, "<>"), "")`
- 将D1公式向下填充至数据末尾
*原理:当A列为空白时,对同组(C列)且A列非空的B列数据求和。*
3. **确保数据末尾有空白行**
- 若数据最后一行非空,需在下方插入空白行以显示末组求和结果。
**示例效果**:
| A列 | B列 | C列 | D列 |
|-----|-----|---------|-----|
| | 5 | Group1 | 0 |
| X | 10 | Group1 | |
| Y | 20 | Group1 | |
| | | Group4 | 30 |
| Z | 15 | Group4 | |
| | | Group6 | 15 |
> **说明**:
> - D列的`30`是Group1分组(B2:B3)的和
> - D列的`15`是Group4分组(B5)的和
> - 隐藏C列可使界面更简洁
---
#### 方法二:数组公式(无需辅助列)
1. **在空白行输入数组公式**
- 选中D列空白行单元格(如A1为空则选D1),输入:
```excel
=IF(A1="", SUM(B1:INDEX(B:B, IFERROR(LOOKUP(2,1/(A$1:A1=""), ROW(A$1:A1))):B1), "")
```
- 按 `Ctrl+Shift+Enter` 确认(显示为`{...}`)
- 向下填充至其他空白行
2. **处理首尾特殊情况**
- 首个分组无空白行时,需在数据上方插入空白行触发计算
- 末组无空白行时,需手动在下方添加空白行
**公式解释**:
- `LOOKUP(2,1/(A$1:A1="")` 定位当前行之前的最后一个空白行行号
- `SUM(B_last_blank+1 : B_current-1)` 计算两个空白行之间的B列数据和
> **注意**:此方法计算效率较低,大数据量时可能影响性能。
---
#### 关键要点
- **分组逻辑**:空白行作为分界点,其**下方非空行**属于同一分组,直到下一个空白行结束
- **推荐方法一**:辅助列方案更稳定易维护,且支持动态数据扩展
- **错误排查**:
- 若求和为0:检查分组是否包含目标数据行(确保A列非空行被纳入)
- 若漏分组:确认数据末尾有空白行