Java: How to read a text file

后端 未结 9 2248
青春惊慌失措
青春惊慌失措 2020-11-22 06:58

I want to read a text file containing space separated values. Values are integers. How can I read it and put it in an array list?

Here is an example of contents of t

9条回答
  •  青春惊慌失措
    2020-11-22 07:03

    All the answers so far given involve reading the file line by line, taking the line in as a String, and then processing the String.

    There is no question that this is the easiest approach to understand, and if the file is fairly short (say, tens of thousands of lines), it'll also be acceptable in terms of efficiency. But if the file is long, it's a very inefficient way to do it, for two reasons:

    1. Every character gets processed twice, once in constructing the String, and once in processing it.
    2. The garbage collector will not be your friend if there are lots of lines in the file. You're constructing a new String for each line, and then throwing it away when you move to the next line. The garbage collector will eventually have to dispose of all these String objects that you don't want any more. Someone's got to clean up after you.

    If you care about speed, you are much better off reading a block of data and then processing it byte by byte rather than line by line. Every time you come to the end of a number, you add it to the List you're building.

    It will come out something like this:

    private List readIntegers(File file) throws IOException {
        List result = new ArrayList<>();
        RandomAccessFile raf = new RandomAccessFile(file, "r");
        byte buf[] = new byte[16 * 1024];
        final FileChannel ch = raf.getChannel();
        int fileLength = (int) ch.size();
        final MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0,
                fileLength);
        int acc = 0;
        while (mb.hasRemaining()) {
            int len = Math.min(mb.remaining(), buf.length);
            mb.get(buf, 0, len);
            for (int i = 0; i < len; i++)
                if ((buf[i] >= 48) && (buf[i] <= 57))
                    acc = acc * 10 + buf[i] - 48;
                else {
                    result.add(acc);
                    acc = 0;
                }
        }
        ch.close();
        raf.close();
        return result;
    }
    

    The code above assumes that this is ASCII (though it could be easily tweaked for other encodings), and that anything that isn't a digit (in particular, a space or a newline) represents a boundary between digits. It also assumes that the file ends with a non-digit (in practice, that the last line ends with a newline), though, again, it could be tweaked to deal with the case where it doesn't.

    It's much, much faster than any of the String-based approaches also given as answers to this question. There is a detailed investigation of a very similar issue in this question. You'll see there that there's the possibility of improving it still further if you want to go down the multi-threaded line.

提交回复
热议问题