按行读取只使用\n换行,忽略\r
我们查看调用链,发现使用了Files和BufferedReader两个类,需要修改的代码是BufferedReader的String readLine(boolean ignoreLF)方法,这里写死了以\r和\n换行,我们只需要修改这里代码就行,所以我们重写这两个类,能继承用继承,不能继承copy源码来改就行了。
调用入口
Path path=Paths.get("test.txt");
List<String> lines= FilesExtend.readAllLines(path, Charset.forName("utf8"));
重写Files类
package org.xxx.utils;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static java.nio.file.Files.newInputStream;
/**
* Description Files文件操作类,使用我们的BufferExtend基础类
* author dragonKJ
* createTime 2021/11/21 12:59
*/
public class FilesExtend {
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:18
* @param path
* @param cs
* @return java.util.List<java.lang.String>
*/
public static List<String> readAllLines(Path path, Charset cs) throws IOException {
//使用我们的继承类BufferedReaderExtend
try (BufferedReaderExtend reader = newBufferedReader(path, cs)) {
List<String> result = new ArrayList<>();
for (;;) {
String line = reader.readLine();
if (line == null)
break;
result.add(line);
}
return result;
}
}
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:18
* @param path
* @param cs
* @return BufferExtend
*/
public static BufferedReaderExtend newBufferedReader(Path path, Charset cs)
throws IOException
{
CharsetDecoder decoder = cs.newDecoder();
Reader reader = new InputStreamReader(newInputStream(path), decoder);
return new BufferedReaderExtend(reader);
}
}
重写BufferedReader
package org.xxx.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
/**
* Description BufferedReader继承类,为了实现文件按行读取,只以\n换行,忽略\r
* author dragonKJ
* createTime 2021/11/21 12:49
*/
public class BufferedReaderExtend extends BufferedReader {
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private Reader in;
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private char cb[];
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private int nChars, nextChar;
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private static final int INVALIDATED = -2;
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private static final int UNMARKED = -1;
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private int markedChar = UNMARKED;
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
/**
* If the next character is a line feed, skip it
*/
private boolean skipLF = false;
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private static int defaultCharBufferSize = 8192;
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*/
private static int defaultExpectedLineLength = 80;
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:12
*
* @param in
*/
public BufferedReaderExtend(Reader in) {
this(in, defaultCharBufferSize);
}
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:13
*
* @param in
* @param sz
*/
public BufferedReaderExtend(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in;
cb = new char[sz];
nextChar = nChars = 0;
}
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:13
*
* @return java.lang.String
*/
@Override
public String readLine() throws IOException {
return readLine(false);
}
/**
* Description 文件按行读取,只以\n换行,忽略\r
* author dragonKJ
* time 2021/11/21 14:13
*
* @param ignoreLF
* @return java.lang.String
*/
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
// 确保底层的inputStream未被关闭
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
// 接下来是两个循环,第一层bufferLoop主要是用来往底层的数组里填充字符,这个底层数组就相当于一个缓冲区
// 而这个缓冲区的大小可以通过BufferedReader(Reader in, int
// sz)这个构造方法的第二个参数来指定,默认为8192bytes
// 而charLoop则是用来遍历底层数组,每次读完底层数组里的数据,就把这些数据写到一个StringBuffer里,
// 直到读到"\n"的时候,写入最后一批数据之后就返回结果并退出整个循环
bufferLoop:
for (; ; ) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
// 注意:这个类的修改点就是这里,修改点删除\r跳出循环判断
// 修改之前:退出这一层循环有两种情况:1、读到"\r"或者"\n" 2、底层数组cb被读完了
// 修改之后:退出这一层循环有两种情况:1、读到"\n" 2、底层数组cb被读完了
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:14
*/
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/* Reallocate buffer to accommodate read-ahead limit */
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
/**
* Description TODO
* author dragonKJ
* time 2021/11/21 14:14
*/
private void ensureOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
}
}