Java:如何读取文本文件

82
我想读取一个包含空格分隔值的文本文件。这些值是整数。如何读取并将其放入ArrayList中? 以下是文本文件内容的示例:
1 62 4 55 5 6 77

我希望将它存储为一个数组列表,形如[1, 62, 4, 55, 5, 6, 77]。在Java中应该怎么做?

9个回答

171

您可以使用Files#readAllLines()将文本文件的所有行读入List<String>中。

for (String line : Files.readAllLines(Paths.get("/path/to/file.txt"))) {
    // ...
}

教程:基本输入输出 > 文件输入输出 > 读取、写入和创建文本文件


您可以使用String#split()根据正则表达式将String分割成多个部分。

for (String part : line.split("\\s+")) {
    // ...
}

教程:数字和字符串 > 字符串 > 操作字符串中的字符


你可以使用Integer#valueOf()将一个String转换为Integer

Integer i = Integer.valueOf(part);

教程:数字和字符串 > 字符串 > 数字和字符串之间的转换

您可以使用List#add()将元素添加到List中。

numbers.add(i);

教程:接口 > 列表接口

因此,简而言之(假设文件没有空行或前导/尾随空格)。

List<Integer> numbers = new ArrayList<>();
for (String line : Files.readAllLines(Paths.get("/path/to/file.txt"))) {
    for (String part : line.split("\\s+")) {
        Integer i = Integer.valueOf(part);
        numbers.add(i);
    }
}

如果您已经使用Java 8,则可以使用Stream API,并从Files#lines()开始进行操作。

List<Integer> numbers = Files.lines(Paths.get("/path/to/test.txt"))
    .map(line -> line.split("\\s+")).flatMap(Arrays::stream)
    .map(Integer::valueOf)
    .collect(Collectors.toList());

教程:使用Java 8流处理数据


1
请注意,在Java 7和8中有更好的方法来实现这一点:https://dev59.com/22445IYBdhLWcg3wwcug - Alex Beardsley

34

Java 1.5引入了Scanner类,用于处理从文件和流中读取的输入。

它被用来从文件中获取整数,代码看起来会像这样:

List<Integer> integers = new ArrayList<Integer>();
Scanner fileScanner = new Scanner(new File("c:\\file.txt"));
while (fileScanner.hasNextInt()){
   integers.add(fileScanner.nextInt());
}

不过请查看API。有许多处理不同类型的输入源、不同分隔符和不同数据类型的选项。


2
这绝对比缓冲、io、reader组合更容易记住。 - avanderw

18
这个示例代码向您展示了如何在Java中读取文件。
import java.io.*;

/**
 * This example code shows you how to read file in Java
 *
 * IN MY CASE RAILWAY IS MY TEXT FILE WHICH I WANT TO DISPLAY YOU CHANGE WITH YOUR   OWN      
 */

 public class ReadFileExample 
 {
    public static void main(String[] args) 
    {
       System.out.println("Reading File from Java code");
       //Name of the file
       String fileName="RAILWAY.txt";
       try{

          //Create object of FileReader
          FileReader inputFile = new FileReader(fileName);

          //Instantiate the BufferedReader Class
          BufferedReader bufferReader = new BufferedReader(inputFile);

          //Variable to hold the one line data
          String line;

          // Read file line by line and print on the console
          while ((line = bufferReader.readLine()) != null)   {
            System.out.println(line);
          }
          //Close the buffer reader
          bufferReader.close();
       }catch(Exception e){
          System.out.println("Error while reading file line by line:" + e.getMessage());                      
       }

     }
  }

12

看这个例子,然后尝试做自己的:

import java.io.*;

public class ReadFile {

    public static void main(String[] args){
        String string = "";
        String file = "textFile.txt";

        // Reading
        try{
            InputStream ips = new FileInputStream(file);
            InputStreamReader ipsr = new InputStreamReader(ips);
            BufferedReader br = new BufferedReader(ipsr);
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
                string += line + "\n";
            }
            br.close();
        }
        catch (Exception e){
            System.out.println(e.toString());
        }

        // Writing
        try {
            FileWriter fw = new FileWriter (file);
            BufferedWriter bw = new BufferedWriter (fw);
            PrintWriter fileOut = new PrintWriter (bw);
                fileOut.println (string+"\n test of read and write !!");
            fileOut.close();
            System.out.println("the file " + file + " is created!");
        }
        catch (Exception e){
            System.out.println(e.toString());
        }
    }
}

5

仅供娱乐,以下是我在真实项目中可能会做的事情,其中我已经使用了我最喜欢的库(在这种情况下是Guava,以前被称为Google Collections)。

String text = Files.toString(new File("textfile.txt"), Charsets.UTF_8);
List<Integer> list = Lists.newArrayList();
for (String s : text.split("\\s")) {
    list.add(Integer.valueOf(s));
}

好处:几乎没有自己维护的代码(与这个相比)。编辑:虽然值得注意的是,在这种情况下,tschaible的Scanner解决方案没有更多的代码!

缺点:显然,您可能不想仅为此添加新的库依赖项。 (再说一遍,如果您的项目中不使用Guava,那么您就太傻了;-)


当然,人们也可以使用Google Collections中的transform()和Function来代替循环,但在我看来,那样会更难读,并且甚至不会更短。 - Jonik

4

使用 Apache Commons(IO和Lang)来处理类似这样的简单/常见事情。

导入:

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;

代码:

String contents = FileUtils.readFileToString(new File("path/to/your/file.txt"));
String[] array = ArrayUtils.toArray(contents.split(" "));

完成。

2

使用Java 7和NIO.2读取文件:

导入以下包:

import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

这是读取文件的过程:
Path file = Paths.get("C:\\Java\\file.txt");

if(Files.exists(file) && Files.isReadable(file)) {

    try {
        // File reader
        BufferedReader reader = Files.newBufferedReader(file, Charset.defaultCharset());

        String line;
        // read each line
        while((line = reader.readLine()) != null) {
            System.out.println(line);
            // tokenize each number
            StringTokenizer tokenizer = new StringTokenizer(line, " ");
            while (tokenizer.hasMoreElements()) {
                // parse each integer in file
                int element = Integer.parseInt(tokenizer.nextToken());
            }
        }
        reader.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

一次性读取文件的所有行:

Path file = Paths.get("C:\\Java\\file.txt");
List<String> lines = Files.readAllLines(file, StandardCharsets.UTF_8);

1
到目前为止给出的所有答案都涉及逐行读取文件,将行作为字符串处理,然后处理该字符串。毫无疑问,这是最容易理解的方法,如果文件相当短(比如数万行),从效率上来说也是可以接受的。但如果文件很长,则这是非常低效的做法,原因有两个:
1.每个字符都会被处理两次,一次在构造字符串时,一次在处理字符串时。
2.如果文件中有很多行,垃圾收集器就不会是你的朋友。你为每一行构建一个新的字符串,然后在移动到下一行时将其丢弃。垃圾收集器最终必须处理掉所有这些你不再需要的字符串对象。总得有人替你打扫吧。
如果你关心速度,最好的方法是读取一块数据,然后按字节而不是按行处理它。每当你到达一个数字的结尾时,就将其添加到你正在构建的列表中。
private List<Integer> readIntegers(File file) throws IOException {
    List<Integer> 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;
}

以上代码假设这是ASCII编码(虽然可以轻松调整为其他编码),并且任何不是数字的字符(特别是空格或换行符)表示数字之间的边界。它还假定文件以非数字结尾(实际上,最后一行以换行符结尾),尽管它可以被调整来处理它不以此结尾的情况。与本问题中提供的任何基于String的方法相比,它要快得多。在此问题中对类似问题进行了详细调查。您会发现,如果您想走多线程路线,仍然有进一步改进的可能性。

0

读取文件,然后随心所欲地操作 Java8 Files.lines(Paths.get("c://lines.txt")).collect(Collectors.toList());


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接