首页 文章

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

提问于
浏览
1292

我一直在使用下面的成语一段时间了 . 它似乎是最广泛的,至少在我访问过的网站上 .

是否有更好/不同的方式将文件读入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();
    }
}

30 回答

  • 1314

    使用Java 7,这是我读取UTF-8文件的首选选项:

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

    从Java 7开始,JDK具有新的 java.nio.file API,它提供了许多快捷方式,因此简单文件操作并不总是需要第三方库 .

  • 166

    如果您涉及第三方库(例如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

    使用JDK 8或以上版本:

    no external libraries used

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

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

    这个使用方法 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
            }
        }
    }
    
  • 14

    收集了从磁盘或网络读取文件为字符串的所有可能方法 .

    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 );
    }
    

    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") );*/
    }
    

    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()));
    }
    

    • 具有正则表达式 \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();
        }
    }
    

    @看到

  • 1

    来自this page一个非常精益的解决方案:

    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
    

    如果要设置charset

  • 3

    在Scanner之后按Ctrl F'ing后,我认为也应该列出Scanner解决方案 . 以最容易阅读的方式,它是这样的:

    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)以从中获取可信任的字符串 . Charsets在你的一生中对你意味着什么,所以现在要小心这些东西 .

    其他人给了代码和东西,我不想偷走他们的荣耀 . ;)

  • 5

    您可以尝试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!");
    }
    
  • 15

    在同一主题上有一个变体,它使用for循环而不是while循环来限制行变量的范围 . 它是否“更好”是个人品味的问题 .

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

    Guava有一种类似于Commons IOUtils的方法,Willi aus Rohr提到:

    import com.google.common.base.Charsets;
    import com.google.common.io.Files;
    
    // ...
    
    String text = Files.toString(new File(path), Charsets.UTF_8);
    

    EDIT by 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 );
    

    Edit (作者Jonik):以上内容与最近的Guava版本的源代码不符 . 对于当前源,请参阅com.google.common.io包中的类FilesCharStreamsByteSourceCharSource .

  • 2

    使用this library,它是一行:

    String data = IO.from(new File("data.txt")).toString();
    
  • 4

    基于@ 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()]));
    }
    
  • 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();
    }
    }
    

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

    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();
        }
    }
    
  • 2
    String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), "UTF-8");
    

    从java 7开始,你就可以这样做 .

  • 4

    该代码将规范化换行符,这可能是你真正想做的事情,也可能不是 .

    这里's an alternative which doesn' t这样做,哪个(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();
        }        
    }
    
  • 72

    从文件中读取所有文本

    这是Java 7的一个紧凑,健壮的习惯用法,包含在一个实用程序方法中:

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

    从文件中读取文本行

    Java 7添加了convenience method to read a file as lines of text,,表示为 List<String> . 这种方法是"lossy",因为行分隔符是从每行的末尾剥离的 .

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

    在Java 8中, BufferedReader 添加了一个新方法lines()来生成一个 Stream<String> . 如果在读取文件时遇到 IOException ,它将包装在UncheckedIOException中,因为 Stream 不接受抛出已检查异常的lambdas .

    try (BufferedReader r = Files.newBufferedReader(path, encoding)) {
      r.lines().forEach(System.out::println);
    }
    

    还有一个 Files.lines() 方法可以执行非常相似的操作,直接返回 Stream<String> . 但我不喜欢它 . Stream 需要 close() 电话;这在API上记录很少,我怀疑很多人甚至没有注意到 Stream 有一个 close() 方法 . 所以你的代码看起来非常相似,如下所示:

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

    不同的是你有一个 Stream 分配给一个变量,我尝试避免这种做法,以便我不小心尝试两次调用流 .

    内存利用率

    保留换行符的第一种方法可以暂时需要几倍于文件大小的内存,因为短时间内原始文件内容(字节数组)和解码后的字符(即使编码也是16位)因为文件中的8位)一次驻留在内存中 . 最安全的是应用于您知道相对于可用内存较小的文件 .

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

    对于读取大文件,您需要为程序设计不同的设计,一个从流中读取一块文本,处理它,然后继续下一个,重复使用相同的固定大小的内存块 . 在这里,"large"取决于计算机规格 . 如今,这个阈值可能是几千兆字节的RAM . 如果您的输入"records"碰巧是单独的行,则使用 Stream<String> 的第三种方法是执行此操作的一种方法 . (使用 readLine()readLine() 方法是与此方法等效的过程 . )

    字符编码

    原始帖子中的示例中缺少的一件事是字符编码 . 在某些特殊情况下,平台默认值是您想要的,但它们很少见,您应该能够证明您的选择 .

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

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

    平台默认值可从the Charset class本身获得:

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

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

  • 46

    Commons FileUtils.readFileToString

    public static String readFileToString(File file)
    抛出IOException
    使用VM的默认编码将文件内容读入String . 该文件始终关闭 . 参数:file - 要读取的文件,不能为null返回:文件内容,从不返回抛出: - IOException - 如果发生I / O错误,则:Commons IO 1.3.1

    该类(间接)使用的代码是:

    IOUtils.javaApache Licence 2.0下 .

    public static long copyLarge(InputStream input, OutputStream output)
           throws IOException {
       byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
       long count = 0;
       int n = 0;
       while (-1 != (n = input.read(buffer))) {
           output.write(buffer, 0, n);
           count += n;
       }
       return count;
    }
    

    它与Ritche_W使用的非常相似 .

  • 46

    用户 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);
    }
    
  • 23

    从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
    
  • 17

    Java试图在其所有方面都非常通用和灵活 . 因此,在脚本语言中相对简单的东西(您的代码将在python中替换为“ open(file).read() ”)要复杂得多 . 除了使用外部库(如提到的Willi aus Rohr)之外,似乎没有任何更短的方法 . 你的选择:

    • 使用外部库 .

    • 将此代码复制到所有项目中 .

    • 创建自己的迷你库,其中包含您经常使用的功能 .

    你最好的选择可能是第二个,因为它的依赖性最小 .

  • 7

    如果您需要字符串处理(并行处理),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 download page下载

    另一个班轮示例

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

    如果您无权访问 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);
    }
    
  • 15

    使用来自Apache commons-ioIOUtilsStringWriter组合的灵活解决方案:

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

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

  • 51

    在一行(Java 8)中,假设您有一个Reader:

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

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

    它有以下方法

    public static String readFileToString(File file) throws IOException
    

    如果您希望将行作为列表使用

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

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

    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();
        }
    }
    
  • 17

    请注意,在使用 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等多字节字符编码 .

  • 6

    此外,如果您的文件恰好在jar中,您也可以使用:

    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");
    
  • 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();
    }
    
  • 3
    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 "";
        }
    

相关问题