如何从文件内容创建Java字符串?


1512

我已经在下面使用过一段时间了。至少在我访问过的网站上,它似乎是分布最广的。

在Java中,是否有更好/不同的方式将文件读取为字符串?

private String readFile(String file) throws IOException {
    BufferedReader reader = new BufferedReader(new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    String         ls = System.getProperty("line.separator");

    try {
        while((line = reader.readLine()) != null) {
            stringBuilder.append(line);
            stringBuilder.append(ls);
        }

        return stringBuilder.toString();
    } finally {
        reader.close();
    }
}

7
谁能以一种非常简单的方式向我解释NIO是什么?每次我读到它,我都会迷失在频道的第n次提及中:(
OscarRyz

7
请记住,不能保证文件中的行分隔符不必与系统的行分隔符相同。
Henrik Paul

138
您能否最后插入一个适当的尝试关闭读者?有人可能会实际使用此示例,并将错误引入其代码中。
汉斯·彼得·斯托尔2010年

6
上面的代码有一个在最后一行添加额外的新行char的错误。它应该类似于if(line = reader.readLine())!= null){stringBuilder.append(line); } while(line = reader.readLine()!! = null){stringBuilder.append(ls); stringBuilder.append(line); }
深夜

27
Java 7引入byte[] Files.readAllBytes(file);那些建议“单行”扫描程序解决方案的人:不需要关闭它吗?
2012年

Answers:


1533

读取文件中的所有文本

Java 11添加了readString()方法来读取小文件,以String保留行终止符:

String content = Files.readString(path, StandardCharsets.US_ASCII);

对于介于Java 7和11之间的版本,这是一个紧凑而健壮的习惯用法,它包装在实用程序方法中:

static String readFile(String path, Charset encoding) 
  throws IOException 
{
  byte[] encoded = Files.readAllBytes(Paths.get(path));
  return new String(encoded, encoding);
}

从文件中读取文本行

Java 7添加了一种便捷方法,可以将文件读取为文本行(以表示)List<String>。这种方法是“有损的”,因为从每行的末端剥去了行分隔符。

List<String> lines = Files.readAllLines(Paths.get(path), encoding);

Java 8添加了Files.lines()生成的方法Stream<String>。同样,此方法是有损的,因为剥去了行分隔符。如果IOException在读取文件时遇到,则会将其包装在中UncheckedIOException,因为Stream它不接受引发检查异常的lambda。

try (Stream<String> lines = Files.lines(path, encoding)) {
  lines.forEach(System.out::println);
}

Stream确实需要close()打电话;这个在API上的文档很少,我怀疑很多人甚至没有注意到Streamclose()方法。确保使用如图所示的ARM模块。

如果使用的是文件以外的源,则可以改用lines()方法BufferedReader

内存利用率

第一种保留换行符的方法可能临时需要占用文件大小几倍的内存,因为在短时间内,原始文件的内容(字节数组)和已解码的字符(即使已编码也为16位) (文件中的8位)一次存储在内存中。将其应用于相对于可用内存较小的文件是最安全的。

第二种方法,读取行,通常会提高内存效率,因为用于解码的输入字节缓冲区不需要包含整个文件。但是,它仍然不适用于相对于可用内存而言非常大的文件。

为了读取大文件,您需要为程序提供不同的设计,即从流中读取文本块,进行处理,然后再移至下一个,重新使用相同的固定大小的内存块。在此,“大”取决于计算机规格。如今,此阈值可能是许多GB的RAM。Stream<String>如果输入的“记录”恰好是单独的行,则使用a的第三种方法是一种方法。(使用的readLine()方法BufferedReader等效于此方法。)

字符编码

原始帖子的示例中缺少的一件事是字符编码。在某些特殊情况下,平台默认值是您想要的,但是很少见,因此您应该可以证明自己的选择合理。

StandardCharsets类中定义的所有Java运行时所需要的编码的一些常量:

String content = readFile("test.txt", StandardCharsets.UTF_8);

该平台默认可从Charset本身:

String content = readFile("test.txt", Charset.defaultCharset());

注意:此答案在很大程度上替代了我的Java 6版本。Java 7的实用程序安全地简化了代码,而使用映射字节缓冲区的旧答案阻止了读取的文件被删除,直到对映射缓冲区进行垃圾回收为止。您可以通过此答案上的“已编辑”链接查看旧版本。


3
从技术上讲,它在时间和空间上为O(n)。定性地讲,由于Strings的不可变性要求,因此很难记忆;暂时在内存中有char数据的两个副本,外加用于编码字节的空间。假设某些单字节编码,它将(临时)为文件中的每个字符需要5个字节的内存。由于问题专门要求一个String,这就是我所显示的,但是如果您可以使用由“ decode”返回的CharBuffer,则对内存的需求将大大减少。从时间角度来看,我认为您不会在核心Java库中更快地找到任何东西。
erickson

5
可能有错字?NIO有一个名为java.nio.charset.Charset的Charset(不是CharSet)类。这是CharSet应该是的吗?
乔纳森·赖特

31
注意:在执行了一些代码之后,我发现使用此方法读取文件后不能立即可靠地删除文件,在某些情况下这可能不是问题,但不是我的。可能与此问题有关:bugs.sun.com/bugdatabase/view_bug.do ? bug_id=4715154吗?我终于接受了Jon Skeet的建议,该建议不受此bug的影响。不管怎么说,我只是想给的信息,对于其他人,以防万一...
塞巴斯蒂安NUSSBAUMER

5
@SébastienNussbaumer:我也碰到了这个问题。令人惊讶的是,该错误已被标记为“将无法修复”。从本质上讲,这FileChannel#map通常是不可用的。
Joonas Pulakka 2010年

4
@SébastienNussbaumer:该错误已从Oracle / Sun错误数据库中删除:“此错误不可用。” 谷歌缓存在现场webcache.googleusercontent.com/search?q=cache:bugs.sun.com/...
bobndrew

350

如果您愿意使用外部库,请查看Apache Commons IO(200KB JAR)。它包含一种org.apache.commons.io.FileUtils.readFileToString()方法,使您可以用一行代码将整个内容读FileString

例:

import java.io.*;
import java.nio.charset.*;
import org.apache.commons.io.*;

public String readFile() throws IOException {
    File file = new File("data.txt");
    return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}

我在您提供的网址中找不到该方法。
OscarRyz

2
它在org.apache.commons.io.FileUtils类中
Cyrille Ka

2
我也正在使用FileUtils,但我想知道使用FileUtils还是公认的nio答案更好?
Guillaume

4
@Guillaume:最大的问题是您是否对依赖第三方库感到满意。如果您的项目中确实有Commons IO或Guava,则使用它们(只是为了简化代码;否则可能不会有明显的区别)。
Jonik 2013年

183

一个非常精简的解决方案基于Scanner

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

或者,如果要设置字符集:

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

或者,使用try-with-resources块,它将要求scanner.close()您:

try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
    String text = scanner.useDelimiter("\\A").next();
}

请记住,Scanner构造函数可以抛出IOException。不要忘了导入java.iojava.util

资料来源:Pat Niemeyer的博客


4
\\ A之所以有效,是因为没有“文件的其他开头”,因此您实际上已读取了最后一个令牌……这也是第一个。从未尝试使用\\ Z。另请注意,您可以读取任何可读的内容,例如文件,InputStreams,通道...当我不确定是否要读取一个文件或另一个文件时,有时会使用此代码从Eclipse的显示窗口读取内容。是的,classpath使我感到困惑。
Pablo Grisafi 2011年

1
作为张贴者,我可以说我真的不知道该文件是否以及何时正确关闭...我从未在生产代码中编写此文件,仅将其用于测试或调试。
Pablo Grisafi 2012年

2
我认为它的上限为1024个字符
异想天开

20
扫描器实现了Closeable(它在源代码上调用close)-因此,尽管优雅,但它实际上并不是单线的。缓冲区的默认大小为1024,但是Scanner会根据需要增加大小(请参阅Scanner#makeSpace())
earcam 2012年

8
对于带有的空文件,此操作将失败java.util.NoSuchElementException
2013年

116
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);

从Java 7开始,您可以使用这种方式。


这应该作为答案接受-单行,没有外部库。
樱桃

即使文件中不存在换行符,也添加了换行符
Stefan Haberl

79

如果您正在寻找不涉及第三方库的替代方案(例如Commons I / O),则可以使用Scanner类:

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());        

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString();
    }
}

2
我认为这是最好的方法。查看java.sun.com/docs/books/tutorial/essential/io/scanning.html
Tarski

3
接受String的Scanner构造函数不会将字符串视为要读取的文件名,而是将其视为要扫描的文本。我一直犯那个错误。:-/
艾伦·摩尔

@Alan,赶上。我稍稍编辑了Don's answer来解决该问题(我希望如此)。
Jonik

3
fileContents.append(scanner.nextLine())。append(lineSeparator);
ban-geoengineering,

1
将初始化语句更改为Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));。否则,您只能捕获文件的一部分。
魏扬

71

番石榴的方法类似于Willi aus Rohr提到的Commons IOUtils的方法:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

// ...

String text = Files.toString(new File(path), Charsets.UTF_8);

PiggyPiglet的EDIT已
Files#toString被弃用,应于Octobor 2019中删除。 Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

奥斯卡·雷耶斯(Oscar Reyes)编辑

这是引用的库上的(简化)基础代码:

InputStream in = new FileInputStream(file);
byte[] b  = new byte[file.length()];
int len = b.length;
int total = 0;

while (total < len) {
  int result = in.read(b, total, len - total);
  if (result == -1) {
    break;
  }
  total += result;
}

return new String( b , Charsets.UTF_8 );

编辑(作者:Jonik):上面的内容与Guava最新版本的源代码不匹配。对于电流源,看到类文件CharStreamsByteSourceCharSourcecom.google.common.io包。


这段代码已从long转换为int,这可能会弹出一些大文件的疯狂行为。有多余的空间吗?您在哪里关闭输入流?
Mohamed Taher Alrefaie

@MTA:数据流关闭,注意使用CloserCharSource。答案中的代码不是当前的实际番石榴来源。
Jonik

54
import java.nio.file.Files;

.......

 String readFile(String filename) {
            File f = new File(filename);
            try {
                byte[] bytes = Files.readAllBytes(f.toPath());
                return new String(bytes,"UTF-8");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
    }

6
或更简单:new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));

12
new String(Files.readAllBytes(Paths.get(filename)));:-)
assafmo 2013年

1
发挥出色,并且为了挽救下一个人,Google Paths显然保持1.7+的状态FileSystems。(
D

4
真可惜,这个答案没有更多的选票。我一直在寻找将文本文件转换为String的最快,最简单的方法。就是这样,如果我不上下滚动,我会错过的。OP应考虑接受此答案以将其移至顶部。
索恩

@Thorn这个答案有可怕的错误处理。不要在生产代码中使用此方法,或者更好:永远不要。
xehpuk

51

如果您需要字符串处理(并行处理),则Java 8具有出色的Stream API。

String result = Files.lines(Paths.get("file.txt"))
                    .parallel() // for parallel processing 
                    .map(String::trim) // to change line   
                    .filter(line -> line.length() > 2) // to filter some lines by a predicate                        
                    .collect(Collectors.joining()); // to join lines

JDK示例中提供了更多示例,这些示例sample/lambda/BulkDataOperations可以从Oracle Java SE 8下载页面下载。

另一个班轮的例子

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));

.parallel()是在您阅读这些行之后还是之前发生的?
Istvan

由于调用了终端操作collect(...),因此实际工作开始了。流是一行一行地懒散地填充的。在处理(例如过滤和映射)之前,无需读取内存中的整个文件。
Andrei N

在选择非空行之前进行修剪?
托尔比约恩Ravn的安德森

50

该代码将规范换行符,这可能是也可能不是您真正想要的。

这是一个不执行此操作的替代方法,并且(IMO)比NIO代码更易于理解(尽管它仍然使用java.nio.charset.Charset):

public static String readFile(String file, String csName)
            throws IOException {
    Charset cs = Charset.forName(csName);
    return readFile(file, cs);
}

public static String readFile(String file, Charset cs)
            throws IOException {
    // No real need to close the BufferedReader/InputStreamReader
    // as they're only wrapping the stream
    FileInputStream stream = new FileInputStream(file);
    try {
        Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[8192];
        int read;
        while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
            builder.append(buffer, 0, read);
        }
        return builder.toString();
    } finally {
        // Potential issue here: if this throws an IOException,
        // it will mask any others. Normally I'd use a utility
        // method which would log exceptions and swallow them
        stream.close();
    }        
}

1
原谅我恢复了这么老的评论,但是您的意思是传入一个名为“ file”的String对象,还是应该改为一个File对象?
布莱恩·拉尔森

28

收集了从磁盘或网络以字符串形式读取文件的所有可能方法。

  • 番石榴:Google使用类ResourcesFiles

    static Charset charset = com.google.common.base.Charsets.UTF_8;
    public static String guava_ServerFile( URL url ) throws IOException {
        return Resources.toString( url, charset );
    }
    public static String guava_DiskFile( File file ) throws IOException {
        return Files.toString( file, charset );
    }

  • APACHE-使用类IOUtils,FileUtils的命令IO

    static Charset encoding = org.apache.commons.io.Charsets.UTF_8;
    public static String commons_IOUtils( URL url ) throws IOException {
        java.io.InputStream in = url.openStream();
        try {
            return IOUtils.toString( in, encoding );
        } finally {
            IOUtils.closeQuietly(in);
        }
    }
    public static String commons_FileUtils( File file ) throws IOException {
        return FileUtils.readFileToString( file, encoding );
        /*List<String> lines = FileUtils.readLines( fileName, encoding );
        return lines.stream().collect( Collectors.joining("\n") );*/
    }

  • 使用Stream API的 Java 8 BufferReader

    public static String streamURL_Buffer( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        BufferedReader reader = new BufferedReader( new InputStreamReader( source ) );
        //List<String> lines = reader.lines().collect( Collectors.toList() );
        return reader.lines().collect( Collectors.joining( System.lineSeparator() ) );
    }
    public static String streamFile_Buffer( File file ) throws IOException {
        BufferedReader reader = new BufferedReader( new FileReader( file ) );
        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
    }

  • 带有正则表达式的Scanner类\A。匹配输入的开始。

    static String charsetName = java.nio.charset.StandardCharsets.UTF_8.toString();
    public static String streamURL_Scanner( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        Scanner scanner = new Scanner(source, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    public static String streamFile_Scanner( File file ) throws IOException {
        Scanner scanner = new Scanner(file, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }

  • Java 7(java.nio.file.Files.readAllBytes

    public static String getDiskFile_Java7( File file ) throws IOException {
        byte[] readAllBytes = java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() ));
        return new String( readAllBytes );
    }

  • BufferedReader使用InputStreamReader

    public static String getDiskFile_Lines( File file ) throws IOException {
        StringBuffer text = new StringBuffer();
        FileInputStream fileStream = new FileInputStream( file );
        BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) );
        for ( String line; (line = br.readLine()) != null; )
            text.append( line + System.lineSeparator() );
        return text.toString();
    }

使用main方法的示例可以访问上述方法。

public static void main(String[] args) throws IOException {
    String fileName = "E:/parametarisation.csv";
    File file = new File( fileName );

    String fileStream = commons_FileUtils( file );
            // guava_DiskFile( file );
            // streamFile_Buffer( file );
            // getDiskFile_Java7( file );
            // getDiskFile_Lines( file );
    System.out.println( " File Over Disk : \n"+ fileStream );


    try {
        String src = "https://code.jquery.com/jquery-3.2.1.js";
        URL url = new URL( src );

        String urlStream = commons_IOUtils( url );
                // guava_ServerFile( url );
                // streamURL_Scanner( url );
                // streamURL_Buffer( url );
        System.out.println( " File Over Network : \n"+ urlStream );
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
}

@看到


26

如果是文本文件,为什么不使用apache commons-io呢?

它具有以下方法

public static String readFileToString(File file) throws IOException

如果要将这些行作为列表使用

public static List<String> readLines(File file) throws IOException

25

从JDK 11开始:

String file = ...
Path path = Paths.get(file);
String content = Files.readString(path);
// Or readString(path, someCharset), if you need a Charset different from UTF-8

为什么,为什么要引入依赖于2018年默认字符集的新方法?
mryan

2
@mryan此方法不依赖于默认系统字符集。它默认为UTF-8,这很好。
leventov '18

@leventov你是对的!File.readAllLines也是如此!这使得文件API与旧方法不太一致,但是更好:)
mryan

17

将文件读取为二进制文件并在末尾进行转换

public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}

16

对于Java 7,这是读取UTF-8文件的首选方法:

String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");

由于Java 7,JDK具有新的java.nio.fileAPI,该API提供了许多快捷方式,因此对于简单的文件操作,并非始终需要第三方库。


15

Java尝试在所有方面都变得极为通用和灵活。结果,在脚本语言中相对简单的事情(您的代码将open(file).read()在python 中用“ ” 代替)要复杂得多。除了使用外部库(例如提到的Willi aus Rohr)外,似乎没有什么更短的方法了。您的选择:

  • 使用外部库。
  • 将此代码复制到您的所有项目中。
  • 创建自己的迷你库,其中包含您经常使用的功能。

您最好的选择可能是第二,因为它具有最少的依赖性。


4
是的 它使“高级”语言具有不同的含义。Java比C高,但与Python或Ruby比低
OscarRyz

3
一致认为Java是长高层次的抽象,但在很短的简便方法
多纳尔

3
的确,Java处理文件的方法非常疯狂,其中许多似乎很复杂。但这与我们使用高级语言所拥有的语言非常接近:byte[] bytes = Files.readAllBytes(someFile.toPath());
Thorn

11

使用JDK 8或更高版本:

没有使用外部库

您可以从文件内容中创建一个新的String对象(使用java.nio.file包中的类):

public String readStringFromFile(String filePath) throws IOException {
    String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
    return fileContent;
}

重复的莫里兹·彼得森(Moritz Petersen)的答案是谁写的:
Jean-Christophe Blanchard '18

8

在同一主题上有一个变体,它使用for循环而不是while循环来限制line变量的范围。是否“更好”取决于个人喜好。

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}

3
这会将换行符更改为默认的换行符选择。这可能是理想的,也可能是意料之外的。
彼得·劳瑞

将编辑回滚到此答案,因为重点是缩小line变量的范围。编辑两次声明它,这将是编译错误。
Dan Dyer

7

如果您无权访问Files该类,则可以使用本机解决方案。

static String readFile(File file, String charset)
        throws IOException
{
    FileInputStream fileInputStream = new FileInputStream(file);
    byte[] buffer = new byte[fileInputStream.available()];
    int length = fileInputStream.read(buffer);
    fileInputStream.close();
    return new String(buffer, 0, length, charset);
}

示例字符集调用?
Thufir

4

结合使用Apache commons-io的IOUtilsStringWriter的灵活解决方案:

Reader input = new FileReader();
StringWriter output = new StringWriter();
try {
  IOUtils.copy(input, output);
} finally {
  input.close();
}
String fileContents = output.toString();

它适用于任何阅读器或输入流(不仅适用于文件),例如,从URL读取时。


3

请注意,使用fileInputStream.available()返回的整数时不必表示实际的文件大小,而应表示系统应该能够从流中读取而不会阻塞IO的猜测字节数。一种安全而简单的方法如下所示

public String readStringFromInputStream(FileInputStream fileInputStream) {
    StringBuffer stringBuffer = new StringBuffer();
    try {
        byte[] buffer;
        while (fileInputStream.available() > 0) {
            buffer = new byte[fileInputStream.available()];
            fileInputStream.read(buffer);
            stringBuffer.append(new String(buffer, "ISO-8859-1"));
        }
    } catch (FileNotFoundException e) {
    } catch (IOException e) { }
    return stringBuffer.toString();
}

应当认为,这种做法是适合多字节字符编码方式,如UTF-8。


1
此代码可能会产生不可预测的结果。根据该方法的文档available()如果该方法返回0,则不能保证到达文件结尾。在这种情况下,您可能会得到不完整的文件。更糟糕的是,实际读取的字节数可能小于所返回的值available(),在这种情况下,输出会损坏。
wau

3

这个使用方法RandomAccessFile.readFully,似乎可以从JDK 1.0中获得!

public static String readFileContent(String filename, Charset charset) throws IOException {
    RandomAccessFile raf = null;
    try {
        raf = new RandomAccessFile(filename, "r");
        byte[] buffer = new byte[(int)raf.length()];
        raf.readFully(buffer);
        return new String(buffer, charset);
    } finally {
        closeStream(raf);
    }
} 


private static void closeStream(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // do nothing
        }
    }
}

3

您可以尝试使用Scanner和File类,几行解决方案

 try
{
  String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
  System.out.println(content);
}
catch(FileNotFoundException e)
{
  System.out.println("not found!");
}

3

用户java.nio.Files读取文件的所有行。

public String readFile() throws IOException {
        File fileToRead = new File("file path");
        List<String> fileLines = Files.readAllLines(fileToRead.toPath());
        return StringUtils.join(fileLines, StringUtils.EMPTY);
}

3
public static String slurp (final File file)
throws IOException {
    StringBuilder result = new StringBuilder();

    BufferedReader reader = new BufferedReader(new FileReader(file));

    try {
        char[] buf = new char[1024];

        int r = 0;

        while ((r = reader.read(buf)) != -1) {
            result.append(buf, 0, r);
        }
    }
    finally {
        reader.close();
    }

    return result.toString();
}

我认为使用平台默认编码会带来不便。无论如何+1 :)
OscarRyz 2010年

7
在我看来,finally块不知道try块中定义的变量。javac 1.6.0_21引发错误cannot find symbol
2012年

您甚至尝试过自己的代码吗?您已经在try / catch块中定义了阅读器,因此在finally块中将无法访问它。
mauron85 '18 -10-31

2

我还不能评论其他条目,所以我就把它留在这里。

最佳答案之一(https://stackoverflow.com/a/326448/1521167):

private String readFile(String pathname) throws IOException {

File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int)file.length());
Scanner scanner = new Scanner(file);
String lineSeparator = System.getProperty("line.separator");

try {
    while(scanner.hasNextLine()) {        
        fileContents.append(scanner.nextLine() + lineSeparator);
    }
    return fileContents.toString();
} finally {
    scanner.close();
}
}

仍然有一个缺陷。它总是将换行符放在字符串的末尾,这可能会导致一些奇怪的错误。我的建议是将其更改为:

    private String readFile(String pathname) throws IOException {
    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int) file.length());
    Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
    String lineSeparator = System.getProperty("line.separator");

    try {
        if (scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine());
        }
        while (scanner.hasNextLine()) {
            fileContents.append(lineSeparator + scanner.nextLine());
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}

在第一种情况下,您可能会在末尾添加额外的换行符。在第二种情况下,您可能会省略一个。因此,两者都是错误的。看到这篇文章
Patrick Parker

2

在扫描仪之后按Ctrl + F后,我认为也应列出扫描仪解决方案。最容易阅读的方式是这样的:

public String fileToString(File file, Charset charset) {
  Scanner fileReader = new Scanner(file, charset);
  fileReader.useDelimiter("\\Z"); // \Z means EOF.
  String out = fileReader.next();
  fileReader.close();
  return out;
}

如果您使用Java 7或更高版本(确实应该),请考虑使用try-with-resources使代码更易于阅读。不再有点滴杂物乱扔一切。但这主要是一种风格选择方法。

我主要出于完成主义的目的发布此文件,因为如果您需要大量执行此操作,则java.nio.file.Files中应该有内容中应该有一些可以做得更好的。

我的建议是使用Files#readAllBytes(Path)抓取所有字节,并将其提供给新的String(byte [] Charset)以从中获得您可以信任的字符串。字符集在您的一生中对您很重要,因此请当心此事。

其他人提供了代码和东西,我不想窃取他们的荣耀。;)



2

同样,如果您的文件恰好在罐子里,您也可以使用以下命令:

public String fromFileInJar(String path) {
    try ( Scanner scanner 
            = new Scanner(getClass().getResourceAsStream(path))) {
        return scanner.useDelimiter("\\A").next();
    }
}

路径应该以/ 例如您的jar为开头

my.jar/com/some/thing/a.txt

然后,您要像这样调用它:

String myTxt = fromFileInJar("/com/com/thing/a.txt");

2

在一行(Java 8)中,假设您具有阅读器:

String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));

2

根据@erickson的回答,您可以使用:

public String readAll(String fileName) throws IOException {
    List<String> lines = Files.readAllLines(new File(fileName).toPath());
    return String.join("\n", lines.toArray(new String[lines.size()]));
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.