如何在 Java 中两次读取同一个文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34086500/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can i read the same file two times in Java?
提问by Damis Berzovitis
I want to counter the lines of the file and in the second pass i want to take every single line and manipulating it. It doesn't have a compilation error but it can't go inside the second while ((line = br.readLine()) != null)
.
Is there a different way to get the lines(movies) of the file and storing in an array ?
我想反击文件的行,在第二遍中,我想获取每一行并对其进行操作。它没有编译错误,但不能进入第二个while ((line = br.readLine()) != null)
. 有没有不同的方法来获取文件的行(电影)并存储在数组中?
BufferedReader br = null;
try { // try to read the file
br = new BufferedReader(new FileReader("movies.txt"));
String line;
int numberOfMovies = 0;
while ((line = br.readLine()) != null) {
numberOfMovies++;
}
Movie[] movies = new Movie[numberOfMovies]; // store in a Movie
// array every movie of
// the file
String title = "";
int id = 0;
int likes = 0;
int icounter = 0; // count to create new movie for each line
while ((line = br.readLine()) != null) {
line = line.trim();
line = line.replaceAll("/t", "");
line = line.toLowerCase();
String[] tokens = line.split(" "); // store every token in a
// string array
id = Integer.parseInt(tokens[0]);
likes = Integer.parseInt(tokens[tokens.length]);
for (int i = 1; i < tokens.length; i++) {
title = title + " " + tokens[i];
}
movies[icounter] = new Movie(id, title, likes);
icounter++;
}
} catch (IOException e) {
e.printStackTrace();
}
采纳答案by Calvin P.
Simplest way would be to reset br
again.
最简单的方法是br
再次重置。
try { // try to read the file
br = new BufferedReader(new FileReader("movies.txt"));
String line; int numberOfMovies = 0;
while (br.hasNextLine()){
numberOfMovies++;
}
br.close();
Movie[] movies = new Movie[numberOfMovies];
// store in a Movie
// array every movie of
// the file
String title = "";
int id = 0;
int likes = 0;
int icounter = 0;
// count to create new movie for each line
br = new BufferedReader(new FileReader("movies.txt"));
while ((br.hasNextLine()) {
line = line.trim();
line = line.replaceAll("/t", "");
line = line.toLowerCase();
String[] tokens = line.split(" ");
// store every token in a
// string array
id = Integer.parseInt(tokens[0]);
likes = Integer.parseInt(tokens[tokens.length]);
for (int i = 1; i < tokens.length; i++) {
title = title + " " + tokens[i];
}
movies[icounter] = new Movie(id, title, likes);
icounter++;
}
} catch (IOException e) { e.printStackTrace(); }
I changed br.nextLine() != null
to br.hasNextLine()
because it's shorter and more appropriate in this case. Plus it won't consume a line.
我换br.nextLine() != null
到br.hasNextLine()
,因为它是在这种情况下更短,更合适。另外它不会消耗一条线。
回答by biziclop
There are two things here:
这里有两件事:
InputStream
s andReader
s are one-shot structures: once you've read them to the end, you either need to explicitly rewindthem (if they support rewinding), or you need to close them (always close your streams and readers!) and open a new one.However in this case the two passes are completely unnecessary, just use a dynamically growing structure to collect your
Movie
objects instead of arrays: anArrayList
for example.
InputStream
s 和Reader
s 是一次性结构:一旦您将它们读到最后,您要么需要明确地倒带它们(如果它们支持倒带),要么需要关闭它们(始终关闭您的流和阅读器!)并打开一个新的。然而,在这种情况下,这两次传递是完全不必要的,只需使用动态增长的结构来收集您的
Movie
对象而不是数组:ArrayList
例如。
回答by kstandell
Firstly, there is no need to read the file twice.
首先,不需要两次读取文件。
Secondly, why don't you use the java.nio.file.Files
class to read your file.
其次,为什么不使用java.nio.file.Files
该类来读取文件。
It has a method readAllLines(Path path, Charset cs)
that gives you back a List<String>
.
它有一个方法readAllLines(Path path, Charset cs)
可以让你返回一个List<String>
.
Then if you want to know how many lines just call the size()
method on the list and you can use the list to construct the Movie
objects.
然后,如果您想知道有多少行,只需调用size()
列表上的方法,您就可以使用列表来构造Movie
对象。
List<Movie> movieList = new ArrayList<>();
for (String line : Files.readAllLines(Paths.get("movies.txt"), Charset.defaultCharset())) {
// Construct your Movie object from each individual line and add to the list of Movies
movieList.add(new Movie(id, title, likes));
}
The use of the Files
class also reduces your boilerplate code as it will handle closing the resource when it has completed reading meaning you will not need a finally
block to close anything.
使用Files
该类还可以减少您的样板代码,因为它会在完成读取后处理关闭资源,这意味着您不需要一个finally
块来关闭任何东西。
回答by Arnaud
If you use the same Reader, everything is already read once you reach the second loop.
如果您使用相同的阅读器,则一旦到达第二个循环,所有内容都已被读取。
Close the first Reader, then create another one to read a second time.
关闭第一个阅读器,然后创建另一个阅读器以进行第二次阅读。
回答by Do Re
You are running through the file with the BufferedReader
, until the nextline points towards null
. As your BufferedReader
IS null
, it won't even enter the second while((line = br.readline) != null)
, as the first read line is null
.
您正在使用 , 遍历文件BufferedReader
,直到下一行指向null
。作为您的BufferedReader
IS null
,它甚至不会进入第二个while((line = br.readline) != null)
,因为第一个读取行是null
。
Try getting a new BufferedReader. something like this:
尝试获取一个新的 BufferedReader。像这样:
...
int id = 0;
int likes = 0;
int icounter = 0;
br = new BufferedReader(new FileReader("movies.txt")) //Re-initialize the br to point
//onto the first line again
while ((line = br.readLine()) != null)
...
EDIT:Close the reader first..
编辑:首先关闭阅读器..
回答by whaley
This is a combination of a couple of other answers already on this post, but this is how I would go about rewriting your code to populate a List. This doubly solves the problem of 1) needing to read the file twice 2) removing the boilerplate around using BufferedReader while using Java8 Streams to make the initializing of your List as concise as possible:
这是这篇文章中已有的其他几个答案的组合,但这就是我将如何重写您的代码以填充列表。这双重解决了 1) 需要读取文件两次 2) 在使用 Java8 Streams 时使用 BufferedReader 删除样板文件的问题,以使 List 的初始化尽可能简洁:
private static class Movie {
private Movie(int id, String title, int likes) {
//TODO: set your instance state here
}
}
private static Movie movieFromFileLine(String line) {
line = line.trim();
line = line.replaceAll("/t", "");
line = line.toLowerCase();
String[] tokens = line.split(" "); // store every token in a
String title = "";
int id = Integer.parseInt(tokens[0]);
int likes = Integer.parseInt(tokens[tokens.length]);
for (int i = 1; i < tokens.length; i++) {
title = title + " " + tokens[i];
}
return new Movie(id, title, likes);
}
public static void main(String[] args) throws IOException {
List<Movie> movies = Files.readAllLines(Paths.get("movies.txt"), Charset.defaultCharset()).stream().map
(App::movieFromFileLine).collect(Collectors.toList());
//TODO: Make some magic with your list of Movies
}
For cases where you absolutely need to read a source (file, URL, or other) twice, then you need to be aware that it is quite possible for the contents to change between the first and second readings and be prepared to handle those differences.
对于您绝对需要阅读源(文件、URL 或其他)两次的情况,那么您需要意识到内容很可能在第一次和第二次阅读之间发生变化,并准备好处理这些差异。
If you can make a reasonable assumption that the content of the source will fit in to memory and your code fully expects to work on multiple instances of Readers/InputStreams, you may first consider using an appropriate IOUtils.copy method from commons-ioto read the contents of the source and copy it to a ByteArrayOutputStream to create a byte[] that can be re-read over and over again.
如果您可以合理假设源的内容适合内存并且您的代码完全期望在 Readers/InputStreams 的多个实例上工作,您可以首先考虑使用来自commons-io的适当 IOUtils.copy 方法来读取源的内容并将其复制到 ByteArrayOutputStream 以创建可以反复读取的 byte[]。