add LineCounter

This commit is contained in:
Looly 2024-06-12 16:32:42 +08:00
parent 8ccdf408f9
commit c3aabfcd14
2 changed files with 107 additions and 38 deletions

View File

@ -23,6 +23,7 @@ import org.dromara.hutool.core.io.resource.FileResource;
import org.dromara.hutool.core.io.resource.Resource;
import org.dromara.hutool.core.io.resource.ResourceUtil;
import org.dromara.hutool.core.io.stream.BOMInputStream;
import org.dromara.hutool.core.io.stream.LineCounter;
import org.dromara.hutool.core.io.unit.DataSizeUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.Console;
@ -551,7 +552,7 @@ public class FileUtil extends PathUtil {
* @since 5.7.22
*/
public static int getTotalLines(final File file) {
return getTotalLines(file, 1024);
return getTotalLines(file, -1);
}
/**
@ -563,46 +564,12 @@ public class FileUtil extends PathUtil {
* @return 该文件总行数
* @since 5.8.28
*/
public static int getTotalLines(final File file, int bufferSize) {
public static int getTotalLines(final File file, final int bufferSize) {
if (false == isFile(file)) {
throw new IORuntimeException("Input must be a File");
}
if (bufferSize < 1) {
bufferSize = 1024;
}
try (final InputStream is = getInputStream(file)) {
final byte[] c = new byte[bufferSize];
int readChars = is.read(c);
if (readChars == -1) {
// 空文件返回0
return 0;
}
// 起始行为1
// 如果只有一行无换行符则读取结束后返回1
// 如果多行最后一行无换行符最后一行需要单独计数
// 如果多行最后一行有换行符则空行算作一行
int count = 1;
while (readChars == bufferSize) {
for (int i = 0; i < bufferSize; i++) {
if (c[i] == CharUtil.LF) {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
for (int i = 0; i < readChars; i++) {
if (c[i] == CharUtil.LF) {
++count;
}
}
readChars = is.read(c);
}
return count;
try (final LineCounter lineCounter = new LineCounter(getInputStream(file), bufferSize)) {
return lineCounter.getCount();
} catch (final IOException e) {
throw new IORuntimeException(e);
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.io.stream;
import org.dromara.hutool.core.io.IORuntimeException;
import org.dromara.hutool.core.text.CharUtil;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
/**
* 行数计数器
*
* @since 6.0.0
*/
public class LineCounter implements Closeable {
private final InputStream is;
private final int bufferSize;
private int count = -1;
/**
* 构造
*
* @param is 输入流
* @param bufferSize 缓存大小小于1则使用默认的1024
*/
public LineCounter(final InputStream is, final int bufferSize) {
this.is = is;
this.bufferSize = bufferSize < 1 ? 1024 : bufferSize;
}
/**
* 获取行数
*
* @return 行数
*/
public int getCount() {
if (this.count < 0) {
try {
this.count = count();
} catch (final IOException e) {
throw new IORuntimeException(e);
}
}
return this.count;
}
@Override
public void close() throws IOException {
if (null != this.is) {
this.is.close();
}
}
private int count() throws IOException {
final byte[] c = new byte[bufferSize];
int readChars = is.read(c);
if (readChars == -1) {
// 空文件返回0
return 0;
}
// 起始行为1
// 如果只有一行无换行符则读取结束后返回1
// 如果多行最后一行无换行符最后一行需要单独计数
// 如果多行最后一行有换行符则空行算作一行
int count = 1;
while (readChars == bufferSize) {
for (int i = 0; i < bufferSize; i++) {
if (c[i] == CharUtil.LF) {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
for (int i = 0; i < readChars; i++) {
if (c[i] == CharUtil.LF) {
++count;
}
}
readChars = is.read(c);
}
return count;
}
}