我有以下代码:
public class Reader {
public static void main(String[] args) throws IOException {
try (FileReader in = new FileReader("D:/test.txt")) {
// BufferedReader br = new BufferedReader(in);
int line = in .read();
for (int i = 0; i < line; i++) {
//System.out.println(line);
System.out.println((char) line);
line = in .read();
}
}
}
}
以及包含内容的文件Test.txt
:
Hello Java
当我在代码上面运行时,它只会显示Hello
。我想仅使用FileReader
读取多行。我不想使用BufferedReader
或InputStreamReader
等。这可能吗?
答案 0 :(得分:3)
我认为此版本的代码不会打印“Hello”。
您正在致电:
int line = in.read();
这是做什么的?在Javadocs中查找Reader
:
public int read()
抛出IOException
读取单个字符。此方法将阻塞,直到字符可用,发生I / O错误或结束 到达了溪流。
(强调我的)
您的代码从'Hello'读取'H',其中ASCII为72。
然后它进入你的循环,行== 72,所以它进入循环:
for(int i=0;i<line;i++)
......做出决定“是否小于72?是的,所以我将进入循环区块”。
然后每次读取一个字符时,line
的值都会变为另一个整数,并且每个时间循环都会以i
为增量。所以循环说“只要字符的ASCII值大于我计算的迭代次数,就继续”。
......每次它都会出现,它会将该字符打印在一条线上。
实际上,对于您的输入,它读取文件结束(-1),而作为-1 < i
,则不符合循环继续条件。
但是对于较长的输入,它会在第97个字符后的第一个'a'或第98个字符后的第一个'b'停止,依此类推(因为ASCII'a'是97,等等)
H
e
l
l
o
J
a
v
a
这不是你想要的:
in.read()
返回-1
。你可能已经被教会如何循环直到满足条件。println()
每个角色,因为这会添加您不想要的换行符。使用print()
。您还应该查看Reader.read(byte[] buffer)
方法,看看是否可以编写代码以更大的块工作。
您在编程生涯中一遍又一遍地使用的两种模式是:
Type x = getSomehow();
while(someCondition(x)) {
doSomethingWith(x);
x = getSomehow();
}
......和......
Type x = value_of_x_which_meets_condition;
while(someCondition(x)) {
x = getSomehow();
doSomethingWith(x);
}
看看你是否可以使用FileReader
构建一些东西以及从中获得的值,填写“somehows”。
答案 1 :(得分:1)
您必须通过char读取内容char并解析新的行序列。
新的行序列可以是以下任何一种:
'\r'
'\n'
"\r\n"
修改强>
您可以尝试以下方法:
public List<String> readLinesUsingFileReader(String filename) throws IOException {
List<String> lines = null;
try (FileReader fileReader = new FileReader(filename)) {
lines = readLines(fileReader);
}
return lines;
}
private List<String> readLines(FileReader fileReader) throws IOException {
List<String> lines = new ArrayList<>();
boolean newLine = false;
int c, p = 0;
StringBuilder line = new StringBuilder();
while(-1 != (c = fileReader.read())) {
if(c == '\n' && p != '\r') {
newLine = true;
} else if(c == '\r') {
newLine = true;
} else {
if(c != '\n' && c != '\r') {
line.append((char) c);
}
}
if(newLine) {
lines.add(line.toString());
line = new StringBuilder();
newLine = false;
}
p = c;
}
if(line.length() > 0) {
lines.add(line.toString());
}
return lines;
}
请注意,上面的代码将整个文件读入List
,这可能不适合大文件!在这种情况下,您可能希望实现一种使用流式传输的方法,即一次读取一行,例如String readNextLine(FileReader fileReader) { ... }
。
一些基本测试:
创建要读取的测试文件
private final static String txt0 = "testnl0.txt";
private final static String txt1 = "testnl1.txt";
private final static String txt2 = "testnl2.txt";
@BeforeClass
public static void genTestFile() throws IOException {
try (OutputStream os = new FileOutputStream(txt0)) {
os0.write((
"Hello\n" +
",\r\n" +
"World!" +
"").getBytes());
}
try (OutputStream os = new FileOutputStream(txt1)) {
os.write((
"\n" +
"\r\r" +
"\r\n" +
"").getBytes());
}
try (OutputStream os = new FileOutputStream(txt2)) {
os.write((
"").getBytes());
}
}
使用创建的文件进行测试
@Test
public void readLinesUsingFileReader0() throws IOException {
List<String> lines = readLinesUsingFileReader(txt0);
Assert.assertEquals(3, lines.size());
Assert.assertEquals("Hello", lines.get(0));
Assert.assertEquals(",", lines.get(1));
Assert.assertEquals("World!", lines.get(2));
}
@Test
public void readLinesUsingFileReader1() throws IOException {
List<String> lines = readLinesUsingFileReader(txt1);
Assert.assertEquals(4, lines.size());
Assert.assertEquals("", lines.get(0));
Assert.assertEquals("", lines.get(1));
Assert.assertEquals("", lines.get(2));
Assert.assertEquals("", lines.get(3));
}
@Test
public void readLinesUsingFileReader2() throws IOException {
List<String> lines = readLinesUsingFileReader(txt2);
Assert.assertTrue(lines.isEmpty());
}
答案 2 :(得分:1)
逐个字符地读取文件而没有任何缓冲流是非常无效的。我可能会将FileReader包装在一些BufferedReader中,或者只是使用Scanner来读取文件的含义,但是如果你绝对想要/需要/只需要使用FileReader那么你可以试试
int line = in.read();
while (line != -1) {
System.out.print((char) line);
line = in.read();
}
而不是你的for (int i = 0; i < line; i++) {...}
循环。
仔细阅读slims answer。简而言之:读取条件不应该关心您读取的字符数是否小于当前读取字符(i < line
)的数字表示。就像
My name
is
not important now
此文件包含的字符很少,您通常看不到\r
和\n
,实际上它看起来像
My name\r\n
\r\n
is\r\n
\r\n
not important now
其中\r
的数字表示为10
,因此在您阅读My name\r\n
之后(由于\r
为{9}个字符,而\n
是单个字符表示行分隔符)您的i
将变为10
,因为您将尝试阅读的下一个字符\r
也由10
表示,您的条件i<line
将失败( 10<10
不是真的。)
因此,不应检查i<line
,而应检查读取值是否为read
method documentation中指定的-1
表示的EoF(文件结束或流结束)所以你的情况应该像line != -1
。而且因为您不需要i
,只需在此使用while
循环。
<强>返回:强>
读取的字符,如果已到达流的末尾,则返回-1
答案 3 :(得分:0)
如果您有新的换行符
public static void main(String[]args) throws IOException{
FileReader in = new FileReader("D:/test.txt");
char [] a = new char[50];
in.read(a); // reads the content to the array
for(char c : a)
System.out.print(c); //prints the characters one by one
in.close();
}
会打印
Hello
Java
答案 4 :(得分:0)
Reader.read()返回单个char的int代码或者如果到达文件末尾则返回-1:
http://docs.oracle.com/javase/7/docs/api/java/io/Reader.html#read()
因此,通过char读取文件char并检查LF(换行,'\ n',0x0A,十进制10),CR(回车,'\ r',0x0D,十进制13)和结束线代码。
注意:Windows操作系统使用2个字符对行尾进行编码:“\ r \ n”。其他大多数包括Linux,MacOS等只使用“\ n”来编码行尾。
final StringBuilder line = new StringBuilder(); // line buffer
try (FileReader in = new FileReader("D:/test.txt")) {
int chAr, prevChar = 0x0A; // chAr - just read char, prevChar - previously read char
while (prevChar != -1) { // until the last read char is EOF
chAr = in.read(); // read int code of the next char
switch (chAr) {
case 0x0D: // CR - just
break; // skip
case -1: // EOF
if (prevChar == 0x0A) {
break; // no need a new line if EOF goes right after LF
// or no any chars were read before (prevChar isn't
// changed from its initial 0x0A)
}
case 0x0A: // or LF
System.out.println("line:" + line.toString()); // get string from the line buffer
line.setLength(0); // cleanup the line buffer
break;
default: // if any other char code is read
line.append((char) chAr); // append to the line buffer
}
prevChar = chAr; // remember the current char as previous one for the next iteration
}
}
答案 5 :(得分:0)
我使用此代码解决了上述问题
public class Reader
{
public static void main(String[]args) throws IOException{
try (FileReader in = new FileReader("D:/test.txt")) {
int line = in.read();
while(line!=-1)
{
System.out.print((char)line);
line = in.read();
} }
}
}
但是,如果我为循环而不是像这样写
,还有一个问题for(int i=0;i<line;i++)
它只打印第一行。有人可以告诉我为什么吗?