【问题标题】:Reading a plain text file in Java用Java读取纯文本文件
【发布时间】:2011-06-10 15:09:33
【问题描述】:

在Java中似乎有不同的方式来读取和写入文件数据。

我想从文件中读取 ASCII 数据。有哪些可能的方式及其区别?

【问题讨论】:

标签: java file-io ascii


【解决方案1】:

ASCII 是一个 TEXT 文件,因此您可以使用 Readers 进行阅读。 Java 还支持使用InputStreams 从二进制文件中读取。如果正在读取的文件很大,那么您可能希望在FileReader 之上使用BufferedReader 来提高读取性能。

通过this article了解如何使用Reader

我还建议您下载并阅读这本名为 Thinking In Java 的精彩(但免费)书

在 Java 7 中

new String(Files.readAllBytes(...))

(docs)

Files.readAllLines(...)

(docs)

在 Java 8 中

Files.lines(..).forEach(...)

(docs)

【讨论】:

  • 选择阅读器实际上取决于您需要文件内容的目的。如果文件很小(ish)并且您需要它,那么使用 FileReader 并读取所有内容(或至少足够大的块)会更快(我们的基准测试:1.8-2x)。如果您正在逐行处理它,那么请使用 BufferedReader。
  • 使用“Files.lines(..).forEach(...)”时是否会保留行序。我的理解是这个操作之后的顺序会是任意的。
  • Files.lines(…).forEach(…) 不保留行的顺序,而是并行执行,@Dash。如果订单很重要,您可以使用Files.lines(…).forEachOrdered(…),它应该保留订单(虽然没有验证)。
  • @Palec 这很有趣,但你能引用文档中说Files.lines(...).forEach(...) 是并行执行的吗?我认为只有当您使用 Files.lines(...).parallel().forEach(...) 显式使流并行时才会出现这种情况。
  • 我的原始配方不是防弹的,@KlitosKyriacou。关键是forEach 不保证任何顺序,原因是易于并行化。如果要保留订单,请使用forEachOrdered
【解决方案2】:

最简单的方法是使用Java 中的Scanner 类和FileReader 对象。简单例子:

Scanner in = new Scanner(new FileReader("filename.txt"));

Scanner 有多种读取字符串、数字等的方法...您可以在 Java 文档页面上查找更多信息。

例如将整个内容读入String

StringBuilder sb = new StringBuilder();
while(in.hasNext()) {
    sb.append(in.next());
}
in.close();
outString = sb.toString();

此外,如果您需要特定的编码,您可以使用它来代替 FileReader

new InputStreamReader(new FileInputStream(fileUtf8), StandardCharsets.UTF_8)

【讨论】:

  • while (in.hasNext()) { System.out.println (in.next()); }
  • @Hissain 不过比BufferedReader好用多了
  • 必须用 try Catch 包围它
  • @JesusRamos 不是真的,你为什么这么认为?这有什么比while ((line = br.readLine()) != null) { sb.append(line); } 更容易的呢?
【解决方案3】:

我最喜欢读取小文件的方法是使用 BufferedReader 和 StringBuilder。它非常简单明了(虽然不是特别有效,但对于大多数情况来说已经足够了):

BufferedReader br = new BufferedReader(new FileReader("file.txt"));
try {
    StringBuilder sb = new StringBuilder();
    String line = br.readLine();

    while (line != null) {
        sb.append(line);
        sb.append(System.lineSeparator());
        line = br.readLine();
    }
    String everything = sb.toString();
} finally {
    br.close();
}

有人指出,在 Java 7 之后你应该使用try-with-resources(即自动关闭)功能:

try(BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    StringBuilder sb = new StringBuilder();
    String line = br.readLine();

    while (line != null) {
        sb.append(line);
        sb.append(System.lineSeparator());
        line = br.readLine();
    }
    String everything = sb.toString();
}

当我读到这样的字符串时,我通常想对每行进行一些字符串处理,所以我选择了这个实现。

虽然如果我只想将文件读入字符串,我总是使用 Apache Commons IO 和类 IOUtils.toString() 方法。您可以在这里查看源代码:

http://www.docjar.com/html/api/org/apache/commons/io/IOUtils.java.html

FileInputStream inputStream = new FileInputStream("foo.txt");
try {
    String everything = IOUtils.toString(inputStream);
} finally {
    inputStream.close();
}

使用 Java 7 甚至更简单:

try(FileInputStream inputStream = new FileInputStream("foo.txt")) {     
    String everything = IOUtils.toString(inputStream);
    // do something with everything string
}

【讨论】:

  • 我做了一个小的调整,如果到达最后一行,就停止添加换行符 ( \n )。 code while (line != null) { sb.append(line); line = br.readLine(); // 仅当 curline 不是最后一行时才添加新行.. if(line != null) { sb.append("\n"); } }code
  • 与 Apache Common IO IOUtils#toString() 类似的是 sun.misc.IOUtils#readFully(),它包含在 Sun/Oracle JRE 中。
  • 为了提高性能,总是调用 sb.append('\n') 优先于 sb.append("\n"),因为将 char 附加到 StringBuilder 的速度比 String 快
  • FileReader 可能会抛出 FileNotFoundException 和 BufferedRead 可能会抛出 IOException 所以你必须抓住它们。
  • 不需要直接使用阅读器,也不需要ioutils。 java7 内置了读取整个文件/所有行的方法:参见docs.oracle.com/javase/7/docs/api/java/nio/file/…docs.oracle.com/javase/7/docs/api/java/nio/file/…
【解决方案4】:

org.apache.commons.io.FileUtils 中的方法也可能很方便,例如:

/**
 * Reads the contents of a file line by line to a List
 * of Strings using the default encoding for the VM.
 */
static List readLines(File file)

【讨论】:

【解决方案5】:

到目前为止,我还没有在其他答案中看到它。但如果“最佳”意味着速度,那么新的 Java I/O (NIO) 可能会提供最快的性能,但对于学习者来说并不总是最容易理解的。

http://download.oracle.com/javase/tutorial/essential/io/file.html

【讨论】:

  • 你应该说明它是如何完成的,而不是给出一个链接
【解决方案6】:

你想对文本做什么?文件是否足够小以适合内存?我会尝试找到最简单的方法来处理您需要的文件。 FileUtils 库非常适合这个。

for(String line: FileUtils.readLines("my-text-file"))
    System.out.println(line);

【讨论】:

【解决方案7】:

我编写的这段代码对于非常大的文件要快得多:

public String readDoc(File f) {
    String text = "";
    int read, N = 1024 * 1024;
    char[] buffer = new char[N];

    try {
        FileReader fr = new FileReader(f);
        BufferedReader br = new BufferedReader(fr);

        while(true) {
            read = br.read(buffer, 0, N);
            text += new String(buffer, 0, read);

            if(read < N) {
                break;
            }
        }
    } catch(Exception ex) {
        ex.printStackTrace();
    }

    return text;
}

【讨论】:

  • 如果你使用简单的字符串连接而不是 StringBuilder,我怀疑它会快得多...
  • 我认为主要的速度增益来自读取 1MB (1024 * 1024) 块。但是,您只需将 1024 * 1024 作为第二个参数传递给 BufferedReader 构造函数即可。
  • 我根本不相信这是经过测试的。以这种方式使用+= 为您提供了应该是线性复杂度的任务的二次(!)复杂度。这将开始抓取超过几 MB 的文件。要解决这个问题,您应该将文本块保存在列表中 或使用上述字符串构建器。
  • 比什么快得多?它肯定比附加到 StringBuffer 快。 -1
  • @gb96 我对缓冲区大小也有同样的想法,但this question 中的详细实验在类似的情况下给出了令人惊讶的结果:16KB 的缓冲区始终明显更快。
【解决方案8】:

这是不使用外部库的另一种方法:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public String readFile(String filename)
{
    String content = null;
    File file = new File(filename); // For example, foo.txt
    FileReader reader = null;
    try {
        reader = new FileReader(file);
        char[] chars = new char[(int) file.length()];
        reader.read(chars);
        content = new String(chars);
        reader.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(reader != null){
            reader.close();
        }
    }
    return content;
}

【讨论】:

  • 或使用“try-with-resources”try(FileReader reader = new FileReader(file))
  • 我注意到了 file.length(),它对 utf-16 文件的效果如何?
  • 此技术假定 read() 填充缓冲区;字符数等于字节数;字节数适合内存;并且字节数适合整数。 -1
  • @HermesTrismegistus 我提供了四个错误的原因。 StefanReich 同意我的观点是完全正确的。
【解决方案9】:

可能不如缓冲 I/O 快,但相当简洁:

    String content;
    try (Scanner scanner = new Scanner(textFile).useDelimiter("\\Z")) {
        content = scanner.next();
    }

\Z 模式告诉Scanner 分隔符是 EOF。

【讨论】:

  • 一个非常相关的,already existing answer 是耶稣拉莫斯。
  • 正确,应该是:if(scanner.hasNext()) content = scanner.next();
  • 这对我来说在 Android 4.4 上失败了。仅读取 1024 个字节。 YMMV。
【解决方案10】:

这是一个简单的解决方案:

String content = new String(Files.readAllBytes(Paths.get("sample.txt")));

或读作列表:

List<String> content = Files.readAllLines(Paths.get("sample.txt"))

【讨论】:

  • @Nery Jr,优雅简约
  • 最好最简单的。
  • readAllLines 需要 Android O (>= 8.0)。
【解决方案11】:

在 Java 中从文件中读取数据最简单的方法是使用 File 类读取文件并使用 Scanner 类读取文件的内容文件。

public static void main(String args[])throws Exception
{
   File f = new File("input.txt");
   takeInputIn2DArray(f);
}

public static void takeInputIn2DArray(File f) throws Exception
{
    Scanner s = new Scanner(f);
    int a[][] = new int[20][20];
    for(int i=0; i<20; i++)
    {
        for(int j=0; j<20; j++)
        {
            a[i][j] = s.nextInt();
        }
    }
}

PS:别忘了导入 java.util.*;让扫描仪工作。

【讨论】:

    【解决方案12】:

    对于基于 JSF 的 Maven Web 应用程序,只需使用 ClassLoader 和 Resources 文件夹来读取您想要的任何文件:

    1. 将您要阅读的任何文件放入 Resources 文件夹中。
    2. 将 Apache Commons IO 依赖项放入您的 POM:

      <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-io</artifactId>
          <version>1.3.2</version>
      </dependency>
      
    3. 使用下面的代码读取它(例如下面是读取 .json 文件):

      String metadata = null;
      FileInputStream inputStream;
      try {
      
          ClassLoader loader = Thread.currentThread().getContextClassLoader();
          inputStream = (FileInputStream) loader
                  .getResourceAsStream("/metadata.json");
          metadata = IOUtils.toString(inputStream);
          inputStream.close();
      }
      catch (FileNotFoundException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
      }
      catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
      }
      return metadata;
      

    您可以对文本文件、.properties 文件、XSD 架构等执行相同操作。

    【讨论】:

    • 你不能在“任何你想要的文件”上使用它。您只能将其用于已打包到 JAR 或 WAR 文件中的资源。
    【解决方案13】:

    使用 BufferedReader:

    import java.io.BufferedReader;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    
    BufferedReader br;
    try {
        br = new BufferedReader(new FileReader("/fileToRead.txt"));
        try {
            String x;
            while ( (x = br.readLine()) != null ) {
                // Printing out each line in the file
                System.out.println(x);
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
    catch (FileNotFoundException e) {
        System.out.println(e);
        e.printStackTrace();
    }
    

    【讨论】:

      【解决方案14】:

      这与耶稣拉莫斯的回答基本相同,除了使用 File 而不是 FileReader 加上迭代以逐步遍历文件的内容。

      Scanner in = new Scanner(new File("filename.txt"));
      
      while (in.hasNext()) { // Iterates each line in the file
          String line = in.nextLine();
          // Do something with line
      }
      
      in.close(); // Don't forget to close resource leaks
      

      ...抛出FileNotFoundException

      【讨论】:

      • File vs FileReader:使用 FileReader,文件必须存在并且操作系统权限必须允许访问。使用文件,可以测试这些权限或检查文件是否为目录。 File 有有用的函数:isFile()、isDirectory()、listFiles()、canExecute()、canRead()、canWrite()、exists()、mkdir()、delete()。 File.createTempFile() 写入系统默认临时目录。这个方法会返回一个文件对象,可以用来打开FileOutputStream对象等source
      【解决方案15】:

      如果是为了结构简单,请使用Java kiss

      import static kiss.API.*;
      
      class App {
        void run() {
          String line;
          try (Close in = inOpen("file.dat")) {
            while ((line = readLine()) != null) {
              println(line);
            }
          }
        }
      }
      

      【讨论】:

        【解决方案16】:

        Guava 为此提供了一个单行:

        import com.google.common.base.Charsets;
        import com.google.common.io.Files;
        
        String contents = Files.toString(filePath, Charsets.UTF_8);
        

        【讨论】:

          【解决方案17】:

          我必须对不同的方式进行基准测试。我将对我的发现发表评论,但简而言之,最快的方法是在 FileInputStream 上使用普通的旧 BufferedInputStream。如果必须读取许多文件,则三个线程会将总执行时间减少到大约一半,但添加更多线程会逐渐降低性能,直到用 20 个线程完成比只用一个线程花费的时间要长三倍。

          假设您必须读取一个文件并对其内容做一些有意义的事情。在此处的示例中,从日志中读取行并计算包含超过某个阈值的值的行。所以我假设单行 Java 8 Files.lines(Paths.get("/path/to/file.txt")).map(line -&gt; line.split(";")) 不是一种选择。

          我在 Java 1.8、Windows 7 以及 SSD 和 HDD 驱动器上进行了测试。

          我写了六个不同的实现:

          rawParse:在 FileInputStream 上使用 BufferedInputStream,然后逐字节剪切读取的行。这优于任何其他单线程方法,但对于非 ASCII 文件可能非常不方便。

          lineReaderParse:在 FileReader 上使用 BufferedReader,逐行读取,通过调用 String.split() 拆分行。这比 rawParse 慢了大约 20%。

          lineReaderParseParallel:这与 lineReaderParse 相同,但它使用多个线程。在所有情况下,这是总体上最快的选项。

          nioFilesParse:使用 java.nio.files.Files.lines()

          nioAsyncParse:使用带有完成处理程序和线程池的 AsynchronousFileChannel。

          nioMemoryMappedParse:使用内存映射文件。产生执行时间至少比任何其他实现长三倍,这确实是一个坏主意。

          这些是在四核 i7 和 SSD 驱动器上读取 204 个 4 MB 文件的平均时间。这些文件是动态生成的,以避免磁盘缓存。

          rawParse                11.10 sec
          lineReaderParse         13.86 sec
          lineReaderParseParallel  6.00 sec
          nioFilesParse           13.52 sec
          nioAsyncParse           16.06 sec
          nioMemoryMappedParse    37.68 sec
          

          我发现在 SSD 上运行或在 HDD 驱动器上运行 SSD 快约 15% 之间的差异比我预期的要小。这可能是因为文件是在未分段的 HDD 上生成的,并且它们是按顺序读取的,因此旋转驱动器几乎可以像 SSD 一样运行。

          我对 nioAsyncParse 实现的低性能感到惊讶。要么我以错误的方式实现了某些东西,要么使用 NIO 和完成处理程序的多线程实现与使用 java.io API 的单线程实现执行相同(甚至更糟)。此外,与在旧流上直接实现相比,使用 CompletionHandler 进行异步解析的代码行要长得多,而且要正确实现也很棘手。

          现在有六个实现,后面是一个包含它们的类以及一个可参数化的 main() 方法,该方法允许使用文件数量、文件大小和并发度。请注意,文件的大小变化加上负 20%。这是为了避免由于所有文件的大小完全相同而产生任何影响。

          原始解析

          public void rawParse(final String targetDir, final int numberOfFiles) throws IOException, ParseException {
              overrunCount = 0;
              final int dl = (int) ';';
              StringBuffer lineBuffer = new StringBuffer(1024);
              for (int f=0; f<numberOfFiles; f++) {
                  File fl = new File(targetDir+filenamePreffix+String.valueOf(f)+".txt");
                  FileInputStream fin = new FileInputStream(fl);
                  BufferedInputStream bin = new BufferedInputStream(fin);
                  int character;
                  while((character=bin.read())!=-1) {
                      if (character==dl) {
          
                          // Here is where something is done with each line
                          doSomethingWithRawLine(lineBuffer.toString());
                          lineBuffer.setLength(0);
                      }
                      else {
                          lineBuffer.append((char) character);
                      }
                  }
                  bin.close();
                  fin.close();
              }
          }
          
          public final void doSomethingWithRawLine(String line) throws ParseException {
              // What to do for each line
              int fieldNumber = 0;
              final int len = line.length();
              StringBuffer fieldBuffer = new StringBuffer(256);
              for (int charPos=0; charPos<len; charPos++) {
                  char c = line.charAt(charPos);
                  if (c==DL0) {
                      String fieldValue = fieldBuffer.toString();
                      if (fieldValue.length()>0) {
                          switch (fieldNumber) {
                              case 0:
                                  Date dt = fmt.parse(fieldValue);
                                  fieldNumber++;
                                  break;
                              case 1:
                                  double d = Double.parseDouble(fieldValue);
                                  fieldNumber++;
                                  break;
                              case 2:
                                  int t = Integer.parseInt(fieldValue);
                                  fieldNumber++;
                                  break;
                              case 3:
                                  if (fieldValue.equals("overrun"))
                                      overrunCount++;
                                  break;
                          }
                      }
                      fieldBuffer.setLength(0);
                  }
                  else {
                      fieldBuffer.append(c);
                  }
              }
          }
          

          lineReaderParse

          public void lineReaderParse(final String targetDir, final int numberOfFiles) throws IOException, ParseException {
              String line;
              for (int f=0; f<numberOfFiles; f++) {
                  File fl = new File(targetDir+filenamePreffix+String.valueOf(f)+".txt");
                  FileReader frd = new FileReader(fl);
                  BufferedReader brd = new BufferedReader(frd);
          
                  while ((line=brd.readLine())!=null)
                      doSomethingWithLine(line);
                  brd.close();
                  frd.close();
              }
          }
          
          public final void doSomethingWithLine(String line) throws ParseException {
              // Example of what to do for each line
              String[] fields = line.split(";");
              Date dt = fmt.parse(fields[0]);
              double d = Double.parseDouble(fields[1]);
              int t = Integer.parseInt(fields[2]);
              if (fields[3].equals("overrun"))
                  overrunCount++;
          }
          

          lineReaderParseParallel

          public void lineReaderParseParallel(final String targetDir, final int numberOfFiles, final int degreeOfParalelism) throws IOException, ParseException, InterruptedException {
              Thread[] pool = new Thread[degreeOfParalelism];
              int batchSize = numberOfFiles / degreeOfParalelism;
              for (int b=0; b<degreeOfParalelism; b++) {
                  pool[b] = new LineReaderParseThread(targetDir, b*batchSize, b*batchSize+b*batchSize);
                  pool[b].start();
              }
              for (int b=0; b<degreeOfParalelism; b++)
                  pool[b].join();
          }
          
          class LineReaderParseThread extends Thread {
          
              private String targetDir;
              private int fileFrom;
              private int fileTo;
              private DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
              private int overrunCounter = 0;
          
              public LineReaderParseThread(String targetDir, int fileFrom, int fileTo) {
                  this.targetDir = targetDir;
                  this.fileFrom = fileFrom;
                  this.fileTo = fileTo;
              }
          
              private void doSomethingWithTheLine(String line) throws ParseException {
                  String[] fields = line.split(DL);
                  Date dt = fmt.parse(fields[0]);
                  double d = Double.parseDouble(fields[1]);
                  int t = Integer.parseInt(fields[2]);
                  if (fields[3].equals("overrun"))
                      overrunCounter++;
              }
          
              @Override
              public void run() {
                  String line;
                  for (int f=fileFrom; f<fileTo; f++) {
                      File fl = new File(targetDir+filenamePreffix+String.valueOf(f)+".txt");
                      try {
                      FileReader frd = new FileReader(fl);
                      BufferedReader brd = new BufferedReader(frd);
                      while ((line=brd.readLine())!=null) {
                          doSomethingWithTheLine(line);
                      }
                      brd.close();
                      frd.close();
                      } catch (IOException | ParseException ioe) { }
                  }
              }
          }
          

          nioFilesParse

          public void nioFilesParse(final String targetDir, final int numberOfFiles) throws IOException, ParseException {
              for (int f=0; f<numberOfFiles; f++) {
                  Path ph = Paths.get(targetDir+filenamePreffix+String.valueOf(f)+".txt");
                  Consumer<String> action = new LineConsumer();
                  Stream<String> lines = Files.lines(ph);
                  lines.forEach(action);
                  lines.close();
              }
          }
          
          
          class LineConsumer implements Consumer<String> {
          
              @Override
              public void accept(String line) {
          
                  // What to do for each line
                  String[] fields = line.split(DL);
                  if (fields.length>1) {
                      try {
                          Date dt = fmt.parse(fields[0]);
                      }
                      catch (ParseException e) {
                      }
                      double d = Double.parseDouble(fields[1]);
                      int t = Integer.parseInt(fields[2]);
                      if (fields[3].equals("overrun"))
                          overrunCount++;
                  }
              }
          }
          

          nioAsyncParse

          public void nioAsyncParse(final String targetDir, final int numberOfFiles, final int numberOfThreads, final int bufferSize) throws IOException, ParseException, InterruptedException {
              ScheduledThreadPoolExecutor pool = new ScheduledThreadPoolExecutor(numberOfThreads);
              ConcurrentLinkedQueue<ByteBuffer> byteBuffers = new ConcurrentLinkedQueue<ByteBuffer>();
          
              for (int b=0; b<numberOfThreads; b++)
                  byteBuffers.add(ByteBuffer.allocate(bufferSize));
          
              for (int f=0; f<numberOfFiles; f++) {
                  consumerThreads.acquire();
                  String fileName = targetDir+filenamePreffix+String.valueOf(f)+".txt";
                  AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get(fileName), EnumSet.of(StandardOpenOption.READ), pool);
                  BufferConsumer consumer = new BufferConsumer(byteBuffers, fileName, bufferSize);
                  channel.read(consumer.buffer(), 0l, channel, consumer);
              }
              consumerThreads.acquire(numberOfThreads);
          }
          
          
          class BufferConsumer implements CompletionHandler<Integer, AsynchronousFileChannel> {
          
                  private ConcurrentLinkedQueue<ByteBuffer> buffers;
                  private ByteBuffer bytes;
                  private String file;
                  private StringBuffer chars;
                  private int limit;
                  private long position;
                  private DateFormat frmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
          
                  public BufferConsumer(ConcurrentLinkedQueue<ByteBuffer> byteBuffers, String fileName, int bufferSize) {
                      buffers = byteBuffers;
                      bytes = buffers.poll();
                      if (bytes==null)
                          bytes = ByteBuffer.allocate(bufferSize);
          
                      file = fileName;
                      chars = new StringBuffer(bufferSize);
                      frmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                      limit = bufferSize;
                      position = 0l;
                  }
          
                  public ByteBuffer buffer() {
                      return bytes;
                  }
          
                  @Override
                  public synchronized void completed(Integer result, AsynchronousFileChannel channel) {
          
                      if (result!=-1) {
                          bytes.flip();
                          final int len = bytes.limit();
                          int i = 0;
                          try {
                              for (i = 0; i < len; i++) {
                                  byte by = bytes.get();
                                  if (by=='\n') {
                                      // ***
                                      // The code used to process the line goes here
                                      chars.setLength(0);
                                  }
                                  else {
                                          chars.append((char) by);
                                  }
                              }
                          }
                          catch (Exception x) {
                              System.out.println(
                                  "Caught exception " + x.getClass().getName() + " " + x.getMessage() +
                                  " i=" + String.valueOf(i) + ", limit=" + String.valueOf(len) +
                                  ", position="+String.valueOf(position));
                          }
          
                          if (len==limit) {
                              bytes.clear();
                              position += len;
                              channel.read(bytes, position, channel, this);
                          }
                          else {
                              try {
                                  channel.close();
                              }
                              catch (IOException e) {
                              }
                              consumerThreads.release();
                              bytes.clear();
                              buffers.add(bytes);
                          }
                      }
                      else {
                          try {
                              channel.close();
                          }
                          catch (IOException e) {
                          }
                          consumerThreads.release();
                          bytes.clear();
                          buffers.add(bytes);
                      }
                  }
          
                  @Override
                  public void failed(Throwable e, AsynchronousFileChannel channel) {
                  }
          };
          

          所有案例的完全可运行的实现

          https://github.com/sergiomt/javaiobenchmark/blob/master/FileReadBenchmark.java

          【讨论】:

            【解决方案18】:

            下面是用 Java 8 方式进行的单行代码。假设text.txt文件位于Eclipse项目目录的根目录下。

            Files.lines(Paths.get("text.txt")).collect(Collectors.toList());
            

            【讨论】:

              【解决方案19】:

              以下是三种有效且经过测试的方法:

              使用BufferedReader

              package io;
              import java.io.*;
              public class ReadFromFile2 {
                  public static void main(String[] args)throws Exception {
                      File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
                      BufferedReader br = new BufferedReader(new FileReader(file));
                      String st;
                      while((st=br.readLine()) != null){
                          System.out.println(st);
                      }
                  }
              }
              

              使用Scanner

              package io;
              
              import java.io.File;
              import java.util.Scanner;
              
              public class ReadFromFileUsingScanner {
                  public static void main(String[] args) throws Exception {
                      File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
                      Scanner sc = new Scanner(file);
                      while(sc.hasNextLine()){
                          System.out.println(sc.nextLine());
                      }
                  }
              }
              

              使用FileReader

              package io;
              import java.io.*;
              public class ReadingFromFile {
              
                  public static void main(String[] args) throws Exception {
                      FileReader fr = new FileReader("C:\\Users\\pankaj\\Desktop\\test.java");
                      int i;
                      while ((i=fr.read()) != -1){
                          System.out.print((char) i);
                      }
                  }
              }
              

              使用Scanner 类无循环读取整个文件

              package io;
              
              import java.io.File;
              import java.io.FileNotFoundException;
              import java.util.Scanner;
              
              public class ReadingEntireFileWithoutLoop {
              
                  public static void main(String[] args) throws FileNotFoundException {
                      File file = new File("C:\\Users\\pankaj\\Desktop\\test.java");
                      Scanner sc = new Scanner(file);
                      sc.useDelimiter("\\Z");
                      System.out.println(sc.next());
                  }
              }
              

              【讨论】:

              • 如果项目中存在文件夹,如何给出路径?
              • java.nio.file.Files 怎么样?我们现在可以只使用readAllLinesreadAllByteslines
              【解决方案20】:

              这可能不是问题的确切答案。这只是另一种读取文件的方式,您无需在 Java 代码中明确指定文件的路径,而是将其作为命令行参数读取。

              使用以下代码,

              import java.io.BufferedReader;
              import java.io.InputStreamReader;
              import java.io.IOException;
              
              public class InputReader{
              
                  public static void main(String[] args)throws IOException{
                      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                      String s="";
                      while((s=br.readLine())!=null){
                          System.out.println(s);
                      }
                  }
              }
              

              继续运行它:

              java InputReader < input.txt
              

              这将读取input.txt 的内容并将其打印到您的控制台。

              您也可以通过命令行使System.out.println()写入特定文件,如下所示:

              java InputReader < input.txt > output.txt
              

              这将从input.txt 读取并写入output.txt

              【讨论】:

                【解决方案21】:

                Cactoos 给你一个声明式的单行:

                new TextOf(new File("a.txt")).asString();
                

                【讨论】:

                  【解决方案22】:

                  您可以使用 readAllLines 和 join 方法在一行中获取整个文件内容:

                  String str = String.join("\n",Files.readAllLines(Paths.get("e:\\text.txt")));
                  

                  默认使用UTF-8编码,正确读取ASCII数据。

                  你也可以使用 readAllBytes:

                  String str = new String(Files.readAllBytes(Paths.get("e:\\text.txt")), StandardCharsets.UTF_8);
                  

                  我认为 readAllBytes 更快更精确,因为它不会用\n 替换新行,而且新行可能是\r\n。这取决于您的需求,哪个适合。

                  【讨论】:

                    【解决方案23】:

                    我记录了15 ways to read a file in Java,然后用各种文件大小(从 1 KB 到 1 GB)测试了它们的速度,以下是执行此操作的前三种方法:

                    1. java.nio.file.Files.readAllBytes()

                      经测试可在 Java 7、8 和 9 中运行。

                      import java.io.File;
                      import java.io.IOException;
                      import java.nio.file.Files;
                      
                      public class ReadFile_Files_ReadAllBytes {
                        public static void main(String [] pArgs) throws IOException {
                          String fileName = "c:\\temp\\sample-10KB.txt";
                          File file = new File(fileName);
                      
                          byte [] fileBytes = Files.readAllBytes(file.toPath());
                          char singleChar;
                          for(byte b : fileBytes) {
                            singleChar = (char) b;
                            System.out.print(singleChar);
                          }
                        }
                      }
                      
                    2. java.io.BufferedReader.readLine()

                      经测试可在 Java 7、8、9 中运行。

                      import java.io.BufferedReader;
                      import java.io.FileReader;
                      import java.io.IOException;
                      
                      public class ReadFile_BufferedReader_ReadLine {
                        public static void main(String [] args) throws IOException {
                          String fileName = "c:\\temp\\sample-10KB.txt";
                          FileReader fileReader = new FileReader(fileName);
                      
                          try (BufferedReader bufferedReader = new BufferedReader(fileReader)) {
                            String line;
                            while((line = bufferedReader.readLine()) != null) {
                              System.out.println(line);
                            }
                          }
                        }
                      }
                      
                    3. java.nio.file.Files.lines()

                      经过测试,这可以在 Java 8 和 9 中使用,但由于 lambda 表达式的要求,无法在 Java 7 中使用。

                      import java.io.File;
                      import java.io.IOException;
                      import java.nio.file.Files;
                      import java.util.stream.Stream;
                      
                      public class ReadFile_Files_Lines {
                        public static void main(String[] pArgs) throws IOException {
                          String fileName = "c:\\temp\\sample-10KB.txt";
                          File file = new File(fileName);
                      
                          try (Stream linesStream = Files.lines(file.toPath())) {
                            linesStream.forEach(line -> {
                              System.out.println(line);
                            });
                          }
                        }
                      }
                      

                    【讨论】:

                      【解决方案24】:

                      缓冲流类在实践中的性能要高得多,以至于 NIO.2 API 包含专门返回这些流类的方法,部分原因是鼓励您始终在应用程序中使用缓冲流。

                      这是一个例子:

                      Path path = Paths.get("/myfolder/myfile.ext");
                      try (BufferedReader reader = Files.newBufferedReader(path)) {
                          // Read from the stream
                          String currentLine = null;
                          while ((currentLine = reader.readLine()) != null)
                              //do your code here
                      } catch (IOException e) {
                          // Handle file I/O exception...
                      }
                      

                      你可以替换这段代码

                      BufferedReader reader = Files.newBufferedReader(path);
                      

                      BufferedReader br = new BufferedReader(new FileReader("/myfolder/myfile.ext"));
                      

                      推荐this的文章学习Java NIO和IO的主要用途。

                      【讨论】:

                        【解决方案25】:
                        import java.util.stream.Stream;
                        import java.nio.file.*;
                        import java.io.*;
                        
                        class ReadFile {
                        
                         public static void main(String[] args) {
                        
                            String filename = "Test.txt";
                        
                            try(Stream<String> stream = Files.lines(Paths.get(filename))) {
                        
                                  stream.forEach(System.out:: println);
                        
                            } catch (IOException e) {
                        
                                e.printStackTrace();
                            }
                        
                         }
                        
                         }
                        

                        只需使用 java 8 Stream。

                        【讨论】:

                          【解决方案26】:
                          try {
                            File f = new File("filename.txt");
                            Scanner r = new Scanner(f);  
                            while (r.hasNextLine()) {
                              String data = r.nextLine();
                              JOptionPane.showMessageDialog(data);
                            }
                            r.close();
                          } catch (FileNotFoundException ex) {
                            JOptionPane.showMessageDialog("Error occurred");
                            ex.printStackTrace();
                          }
                          

                          【讨论】:

                            【解决方案27】:

                            最直观的方法在Java 11 Files.readString中引入

                            import java.io.*;
                            import java.nio.file.Files;
                            import java.nio.file.Paths;
                            
                            public class App {
                                public static void main(String args[]) throws IOException {
                                    String content = Files.readString(Paths.get("D:\\sandbox\\mvn\\my-app\\my-app.iml"));
                                    System.out.print(content);
                                }
                            }
                            

                            PHP 几十年来一直拥有这个luxury! ☺

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2011-05-05
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2016-08-08
                              • 2016-07-04
                              相关资源
                              最近更新 更多