Bagaimana cara membuat string Java dari konten file?

1513

Saya telah menggunakan idiom di bawah ini untuk beberapa waktu sekarang. Dan itu tampaknya menjadi yang paling luas, setidaknya di situs yang saya kunjungi.

Apakah ada cara yang lebih baik / berbeda untuk membaca file menjadi string di 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();
    }
}
OscarRyz
sumber
7
Adakah yang bisa menjelaskan saya dengan cara yang sangat sederhana ada apa dengan NIO? Setiap kali saya membaca tentang hal itu, saya tersesat di saluran menyebutkan :(
OscarRyz
7
ingat bahwa tidak dijamin bahwa pemisah baris dalam file tidak perlu sama dengan pemisah garis sistem.
Henrik Paul
138
Bisakah Anda memasukkan percobaan yang tepat yang akhirnya menutup pembaca? Seseorang mungkin benar-benar menggunakan contoh ini dan memasukkan bug ke dalam kodenya.
Hans-Peter Störr
6
Kode di atas memiliki bug untuk menambahkan baris char tambahan baru di baris terakhir. Seharusnya sesuatu seperti mengikuti if (line = reader.readLine ())! = Null) {stringBuilder.append (line); } while (line = reader.readLine ())! = null) {stringBuilder.append (ls); stringBuilder.append (baris); }
Jauh
27
Java 7 memperkenalkan byte[] Files.readAllBytes(file);Kepada mereka, yang menyarankan solusi Pemindai 'satu baris': Tidakkah Anda perlu menutupnya?
Val

Jawaban:

1536

Baca semua teks dari file

Java 11 menambahkan metode readString () untuk membaca file kecil sebagai String, mempertahankan terminator garis:

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

Untuk versi antara Java 7 dan 11, berikut adalah idiom yang ringkas dan kuat, terbungkus dalam metode utilitas:

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

Baca baris teks dari file

Java 7 menambahkan metode kenyamanan untuk membaca file sebagai baris teks, direpresentasikan sebagai List<String>. Pendekatan ini "lossy" karena pemisah garis dilucuti dari akhir setiap baris.

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

Java 8 menambahkan Files.lines()metode untuk menghasilkan a Stream<String>. Sekali lagi, metode ini lossy karena pemisah garis dilucuti. Jika IOExceptionditemui saat membaca file, itu dibungkus dalam UncheckedIOException, karena Streamtidak menerima lambdas yang melempar pengecualian yang diperiksa.

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

Ini Streammemang membutuhkan close()panggilan; ini tidak terdokumentasi dengan baik di API, dan saya curiga banyak orang yang bahkan tidak menyadari Streamadanyaclose() metode. Pastikan untuk menggunakan blok ARM seperti yang ditunjukkan.

Jika Anda bekerja dengan sumber selain file, Anda dapat menggunakan lines()metode ini diBufferedReader sebagai gantinya.

Pemanfaatan memori

Metode pertama, yang mempertahankan jeda baris, untuk sementara waktu membutuhkan memori beberapa kali ukuran file, karena untuk waktu yang singkat isi file mentah (array byte), dan karakter yang diterjemahkan (masing-masing adalah 16 bit bahkan jika dikodekan) sebagai 8 bit dalam file) berada di memori sekaligus. Itu paling aman untuk diterapkan ke file yang Anda tahu kecil relatif terhadap memori yang tersedia.

Metode kedua, membaca baris, biasanya lebih efisien memori, karena buffer byte input untuk decoding tidak perlu mengandung seluruh file. Namun, itu masih tidak cocok untuk file yang sangat besar relatif terhadap memori yang tersedia.

Untuk membaca file besar, Anda memerlukan desain yang berbeda untuk program Anda, yang membaca sepotong teks dari stream, memprosesnya, dan kemudian pindah ke yang berikutnya, menggunakan kembali blok memori berukuran tetap yang sama. Di sini, "besar" tergantung pada spesifikasi komputer. Saat ini, ambang ini mungkin banyak RAM gigabytes. Metode ketiga, menggunakan a Stream<String>adalah salah satu cara untuk melakukan ini, jika input Anda "catatan" kebetulan menjadi baris individual. (Menggunakan readLine()metode BufferedReaderadalah prosedur yang setara dengan pendekatan ini.)

Pengkodean karakter

Satu hal yang hilang dari sampel dalam posting asli adalah pengkodean karakter. Ada beberapa kasus khusus di mana platform default adalah apa yang Anda inginkan, tetapi jarang, dan Anda harus dapat membenarkan pilihan Anda.

The StandardCharsetskelas mendefinisikan beberapa konstanta untuk pengkodean diperlukan dari semua runtimes Jawa:

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

Platform standar tersedia dari yang Charsetkelas itu sendiri:

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

Catatan: Jawaban ini sebagian besar menggantikan versi Java 6 saya. Utilitas Java 7 dengan aman menyederhanakan kode, dan jawaban lama, yang menggunakan buffer byte yang dipetakan, mencegah file yang dibaca tidak dihapus sampai buffer yang dipetakan dikumpulkan dari sampah. Anda dapat melihat versi lama melalui tautan "diedit" pada jawaban ini.

erickson
sumber
3
Secara teknis, ini O (n) dalam ruang dan waktu. Secara kualitatif, karena persyaratan kekekalan dari String, ini cukup sulit untuk diingat; untuk sementara ada dua salinan data char dalam memori, ditambah ruang untuk byte yang disandikan. Dengan asumsi beberapa pengkodean byte tunggal, itu akan (sementara) membutuhkan memori 5 byte untuk setiap karakter dalam file. Karena pertanyaannya meminta String secara khusus, itulah yang saya tunjukkan, tetapi jika Anda dapat bekerja dengan CharBuffer yang dikembalikan oleh "decode", persyaratan memori jauh lebih sedikit. Dari segi waktu, saya tidak berpikir Anda akan menemukan sesuatu yang lebih cepat di inti Java libs.
erickson
5
Kemungkinan salah ketik? NIO memiliki kelas Charset (bukan CharSet) yang disebut java.nio.charset.Charset. Apakah ini yang seharusnya CharSet?
Jonathan Wright
31
Catatan: setelah melakukan sedikit kode itu, saya menemukan bahwa Anda tidak dapat dengan andal menghapus file setelah membacanya dengan metode ini, yang mungkin bukan masalah dalam beberapa kasus, tetapi bukan milik saya. Mungkin itu terkait dengan masalah ini: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 ? Saya akhirnya setuju dengan Jon Skeet yang tidak menderita bug ini. Ngomong-ngomong, saya hanya ingin memberikan info, untuk orang lain, untuk berjaga-jaga ...
Sébastien Nussbaumer
5
@ Sébastien Nussbaumer: Saya juga menemui masalah ini. Luar biasa bahwa bug telah ditandai "Tidak Akan Memperbaiki". Ini pada dasarnya berarti bahwa FileChannel#mapsecara umum tidak dapat digunakan.
Joonas Pulakka
4
@ Sébastien Nussbaumer: Bug telah dihapus dari Oracle / Sun Bug Database: "Bug ini tidak tersedia." Google membuat cache situs di webcache.googleusercontent.com/search?q=cache:bugs.sun.com/…
bobndrew
351

Jika Anda ingin menggunakan perpustakaan eksternal, periksa Apache Commons IO (200KB JAR). Ini berisi org.apache.commons.io.FileUtils.readFileToString()metode yang memungkinkan Anda untuk membaca keseluruhan Filemenjadi Stringdengan satu baris kode.

Contoh:

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);
}
Willi aus Rohr
sumber
Saya tidak menemukan metode itu di URL yang Anda berikan.
OscarRyz
2
Ada di kelas org.apache.commons.io.FileUtils
Cyrille Ka
2
Saya menggunakan FileUtils juga, tapi saya bertanya-tanya apa yang lebih baik antara menggunakan FileUtils atau jawaban nio yang diterima?
Guillaume
4
@Guillaume: Pertanyaan terbesar adalah apakah Anda merasa nyaman memiliki ketergantungan pada perpustakaan pihak ke-3. Jika Anda memiliki Commons IO atau Guava di proyek Anda, gunakan itu (hanya untuk kesederhanaan kode; jika tidak, kemungkinan tidak akan ada perbedaan yang nyata).
Jonik
183

Solusi yang sangat ramping berdasarkan Scanner:

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

Atau, jika Anda ingin mengatur rangkaian karakter:

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

Atau, dengan blok coba-dengan-sumber daya , yang akan memanggil scanner.close()Anda:

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

Ingat bahwa Scannerkonstruktor dapat melempar IOException. Dan jangan lupa untuk mengimpor java.iodan java.util.

Sumber: blog Pat Niemeyer

Pablo Grisafi
sumber
4
\\ A berfungsi karena tidak ada "awal file lain", jadi Anda sebenarnya membaca token terakhir ... yang juga merupakan yang pertama. Belum pernah mencoba dengan \\ Z. Juga perhatikan Anda dapat membaca apa pun yang Dapat Dibaca, seperti File, InputStreams, saluran ... Saya kadang-kadang menggunakan kode ini untuk membaca dari jendela tampilan gerhana, ketika saya tidak yakin apakah saya membaca satu file atau yang lain .. .ya, classpath membingungkan saya.
Pablo Grisafi
1
Sebagai poster, saya dapat mengatakan saya benar-benar tidak tahu apakah dan ketika file ditutup dengan benar ... Saya tidak pernah menulis ini dalam kode produksi, saya menggunakannya hanya untuk tes atau debug.
Pablo Grisafi
2
Saya kira memiliki batas 1024 karakter
Whimusical
20
Scanner mengimplementasikan Closeable (itu memanggil dekat pada sumber) - jadi meskipun elegan itu seharusnya tidak menjadi satu-liner. Ukuran default buffer adalah 1024, tetapi Scanner akan menambah ukuran seperlunya (lihat Scanner # makeSpace ())
earcam
8
Ini gagal untuk file kosong dengan a java.util.NoSuchElementException.
SpaceTrucker
117
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);

sejak java 7 Anda bisa melakukannya dengan cara ini.

JoBⅈN
sumber
Ini harus diterima sebagai jawaban - baris tunggal, tidak ada lib eksternal.
Cherry
Ini menambahkan karakter baris baru di akhir, bahkan jika itu tidak ada dalam file
Stefan Haberl
79

Jika Anda mencari alternatif yang tidak melibatkan perpustakaan pihak ketiga (mis. Commons I / O ), Anda bisa menggunakan kelas 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();
    }
}
Dónal
sumber
2
Saya pikir ini adalah cara terbaik. Lihat java.sun.com/docs/books/tutorial/essential/io/scanning.html
Tarski
3
Konstruktor pemindai yang menerima string tidak memperlakukan string sebagai nama file untuk dibaca, tetapi sebagai teks yang akan dipindai. Saya melakukan kesalahan itu sepanjang waktu. : - /
Alan Moore
@Lan, tangkapan yang bagus. Saya mengedit sedikit jawaban Don untuk memperbaikinya (saya harap).
Jonik
3
fileContents.append (scanner.nextLine ()). append (lineSeparator);
Larangan geoengineering
1
Ubah pernyataan inisialisasi menjadi Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));. Kalau tidak, Anda hanya dapat menangkap sebagian file.
Wei Yang
71

Jambu biji memiliki metode yang mirip dengan yang ada di Commons IOUtils yang disebutkan oleh 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 oleh PiggyPiglet
Files#toString sudah usang, dan akan dihapus Octobor 2019. Sebagai gantinya gunakan Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

EDIT oleh Oscar Reyes

Ini adalah kode dasar (disederhanakan) pada pustaka yang dikutip:

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

Sunting (oleh Jonik): Di atas tidak cocok dengan kode sumber versi Jambu terbaru. Untuk sumber saat ini, lihat kelas Files , CharStreams , ByteSource dan CharSource dalam paket com.google.common.io .

OscarRyz
sumber
Kode ini telah di-casting dari panjang ke int yang bisa memunculkan beberapa perilaku gila dengan file besar. Punya ruang ekstra dan di mana Anda menutup inputstream?
Mohamed Taher Alrefaie
@MTA: Aliran ini ditutup, perhatikan penggunaan Closerdi CharSource . Kode dalam jawaban bukanlah sumber aktual Guava saat ini.
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 "";
    }
pengguna590444
sumber
6
Atau bahkan lebih sederhana:new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));
12
atau new String(Files.readAllBytes(Paths.get(filename)));:-)
assafmo
1
Dimainkan dengan baik, dan untuk menyelamatkan orang berikutnya Googling, Pathstampaknya 1,7+ apa adanya FileSystems. (
Sial
4
Sayang sekali jawaban ini tidak memiliki suara lebih banyak. Saya sedang mencari cara tercepat dan termudah untuk mendapatkan file teks menjadi sebuah String. Ini dia dan jika saya tidak menggulir ke bawah dan ke bawah dan ke bawah, saya akan melewatkannya. OP harus mempertimbangkan menerima jawaban ini untuk memindahkannya ke atas.
Thorn
@Thorn Jawaban ini memiliki penanganan kesalahan yang mengerikan. Jangan gunakan metode ini dalam kode produksi, atau lebih baik: tidak pernah.
xehpuk
51

Jika Anda memerlukan pemrosesan string (pemrosesan paralel) Java 8 memiliki API Stream yang hebat.

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

Lebih banyak contoh tersedia dalam sampel JDK sample/lambda/BulkDataOperationsyang dapat diunduh dari halaman unduhan Oracle Java SE 8

Contoh satu liner lainnya

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));
Andrei N
sumber
Apakah .parallel () terjadi setelah Anda membaca baris atau sebelum itu?
Istvan
Pekerjaan nyata dimulai sejak operasi terminal mengumpulkan (...) dipanggil. Aliran diisi dengan malas baris demi baris. Tidak perlu membaca seluruh file dalam memori sebelum diproses (mis. Pemfilteran dan pemetaan).
Andrei N
potong sebelum memilih jalur yang tidak kosong?
Thorbjørn Ravn Andersen
50

Kode itu akan menormalkan jeda baris, yang mungkin atau tidak mungkin benar-benar ingin Anda lakukan.

Berikut adalah alternatif yang tidak melakukan itu, dan yang (IMO) lebih mudah dipahami daripada kode NIO (meskipun masih menggunakan 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();
    }        
}
Jon Skeet
sumber
1
Maafkan saya karena menghidupkan kembali komentar yang lama ini, tetapi apakah Anda bermaksud meneruskan objek String yang disebut "file", atau haruskah itu menjadi objek File?
Bryan Larson
28

Kumpulkan semua cara yang mungkin untuk membaca File sebagai String dari Disk atau Jaringan.

  • Jambu: Google menggunakan kelas Resources,Files

    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 - COMMONS IO menggunakan kelas IOUtils, FileUtils

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

  • Java 8 BufferReader menggunakan Stream API

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

  • Kelas Scanner dengan regex \A. yang cocok dengan awal input.

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

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

Contoh dengan metode utama untuk mengakses metode di atas.

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

@Lihat

Yash
sumber
26

Jika itu file teks, mengapa tidak menggunakan apache commons-io ?

Ini memiliki metode berikut

public static String readFileToString(File file) throws IOException

Jika Anda ingin garis sebagai daftar gunakan

public static List<String> readLines(File file) throws IOException
Rumah tepat waktu
sumber
25

Sejak 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
leventov
sumber
Mengapa, oh mengapa, memperkenalkan metode baru yang mengandalkan charset default pada 2018?
mryan
2
@mryan metode ini tidak mengandalkan charset sistem default. Standarnya adalah UTF-8, itu tidak masalah.
leventov
@leventov kamu benar! begitu pula Files.readAllLines! yang membuat file API tidak terlalu konsisten dengan metode yang lebih lama tapi itu menjadi lebih baik :)
mryan
17

Untuk membaca File sebagai biner dan mengonversi di akhir

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();
    }
}
Peter Lawrey
sumber
16

Dengan Java 7, ini adalah pilihan saya untuk membaca file UTF-8:

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

Sejak Java 7, JDK memiliki java.nio.fileAPI baru , yang menyediakan banyak pintasan, sehingga perpustakaan pihak ketiga tidak selalu diperlukan untuk operasi file yang sederhana.

Moritz Petersen
sumber
15

Java berupaya menjadi sangat umum dan fleksibel dalam semua hal yang dilakukannya. Akibatnya, sesuatu yang relatif sederhana dalam bahasa scripting (kode Anda akan diganti dengan " open(file).read()" dengan python) jauh lebih rumit. Tampaknya tidak ada cara yang lebih pendek untuk melakukannya, kecuali menggunakan perpustakaan eksternal (seperti yang disebutkan oleh Willi aus Rohr ). Pilihan Anda:

  • Gunakan perpustakaan eksternal.
  • Salin kode ini ke semua proyek Anda.
  • Buat perpustakaan mini Anda sendiri yang berisi fungsi yang sering Anda gunakan.

Taruhan terbaik Anda mungkin yang ke-2, karena memiliki dependensi paling sedikit.

Claudiu
sumber
4
Yap. Itu membuat bahasa tingkat "tinggi" mengambil makna yang berbeda. Jawa tingkat tinggi dibandingkan dengan C tetapi rendah dibandingkan dengan Python atau Ruby
OscarRyz
3
Setuju bahwa Java panjang pada abstraksi tingkat tinggi tetapi kekurangan metode kenyamanan
Dónal
3
Benar, Java memiliki sejumlah cara yang gila untuk berurusan dengan File dan banyak dari mereka tampak rumit. Tapi ini cukup dekat dengan apa yang kita miliki dalam bahasa tingkat yang lebih tinggi:byte[] bytes = Files.readAllBytes(someFile.toPath());
Thorn
11

Menggunakan JDK 8 atau lebih tinggi:

tidak ada perpustakaan eksternal yang digunakan

Anda dapat membuat objek String baru dari konten file (Menggunakan kelas dari java.nio.filepaket):

public String readStringFromFile(String filePath) throws IOException {
    String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
    return fileContent;
}
Saikat
sumber
Duplikat jawaban Moritz Petersen yang menulis: String content = new String (Files.readAllBytes (Paths.get (nama file)), "UTF-8");
Jean-Christophe Blanchard
8

Ada variasi pada tema yang sama yang menggunakan loop untuk, alih-alih loop sementara, untuk membatasi ruang lingkup variabel baris. Apakah itu "lebih baik" adalah masalah selera pribadi.

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}
Dan Dyer
sumber
3
Ini akan mengubah baris baru ke choise baris baru default. Ini mungkin diinginkan, atau tidak diinginkan.
Peter Lawrey
Putar kembali hasil edit ke jawaban ini karena intinya adalah mempersempit cakupan linevariabel. Hasil edit menyatakannya dua kali, yang merupakan kesalahan kompilasi.
Dan Dyer
7

Jika Anda tidak memiliki akses ke Fileskelas, Anda dapat menggunakan solusi asli.

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);
}
Ilya Gazman
sumber
contoh charset untuk dipanggil?
Thufir
4

Solusi fleksibel menggunakan IOUtils dari Apache commons-io dalam kombinasi dengan StringWriter :

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

Ini berfungsi dengan pembaca apa pun atau aliran input (tidak hanya dengan file), misalnya saat membaca dari URL.

wau
sumber
3

Berhati-hatilah saat menggunakan fileInputStream.available()integer yang dikembalikan tidak harus mewakili ukuran file yang sebenarnya, tetapi jumlah byte yang ditebak oleh sistem harus dapat dibaca dari stream tanpa memblokir IO. Cara yang aman dan sederhana bisa terlihat seperti ini

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

Harus dipertimbangkan bahwa pendekatan ini tidak cocok untuk pengkodean karakter multi-byte seperti UTF-8.

Henry
sumber
1
Kode ini dapat memberikan hasil yang tidak terduga. Menurut dokumentasi dari available()metode, tidak ada jaminan bahwa akhir file tercapai dalam hal metode mengembalikan 0. Dalam hal ini Anda mungkin berakhir dengan file yang tidak lengkap. Yang lebih buruk, jumlah byte yang benar-benar dibaca bisa lebih kecil dari nilai yang dikembalikan oleh available(), dalam hal ini Anda mendapatkan output yang rusak.
wau
3

Yang ini menggunakan metode RandomAccessFile.readFully, tampaknya tersedia dari 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
        }
    }
}
barjak
sumber
3

Anda dapat mencoba kelas Pemindai dan File, beberapa solusi garis

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

Pengguna java.nio.Filesmembaca semua baris file.

public String readFile() throws IOException {
        File fileToRead = new File("file path");
        List<String> fileLines = Files.readAllLines(fileToRead.toPath());
        return StringUtils.join(fileLines, StringUtils.EMPTY);
}
Nitin Vavdiya
sumber
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();
}
Scott S. McCoy
sumber
Saya pikir ini memiliki ketidaknyamanan menggunakan platform encoding default. +1 tetap :)
OscarRyz
7
Sepertinya saya bahwa blok akhirnya tidak tahu variabel yang didefinisikan dalam blok coba. javac 1.6.0_21 melempar kesalahan cannot find symbol.
ceving
Apakah Anda pernah mencoba kode Anda sendiri? Anda telah mendefinisikan pembaca di blok coba / tangkap, sehingga tidak akan dapat diakses pada akhirnya.
mauron85
2

Saya belum dapat mengomentari entri lain, jadi saya akan meninggalkannya di sini.

Salah satu jawaban terbaik di sini ( 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();
}
}

masih memiliki satu kelemahan. Itu selalu menempatkan baris baru char di akhir string, yang dapat menyebabkan beberapa bug aneh. Saran saya adalah mengubahnya menjadi:

    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();
    }
}
Ajk
sumber
Dalam kasus pertama, Anda mungkin menambahkan baris baru tambahan di bagian akhir. dalam kasus kedua Anda mungkin menghilangkan satu. Jadi keduanya sama-sama salah. Lihat artikel ini
Patrick Parker
2

Setelah Ctrl + F'ing setelah Scanner, saya pikir solusi Scanner juga harus terdaftar. Dalam mode yang paling mudah dibaca, bunyinya seperti ini:

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

Jika Anda menggunakan Java 7 atau yang lebih baru (dan memang harus demikian) pertimbangkan untuk menggunakan sumber daya coba-pakai untuk membuat kode lebih mudah dibaca. Tidak ada lagi hal-hal dot-close yang mengotori segalanya. Tapi itu kebanyakan metode pilihan gaya.

Saya memposting ini sebagian besar untuk penyelesaian, karena jika Anda perlu melakukan ini banyak, harus ada hal-hal di java.nio.file.Files yang seharusnya melakukan pekerjaan dengan lebih baik.

Saran saya adalah menggunakan Files # readAllBytes (Path) untuk mengambil semua byte, dan memasukkannya ke String baru (byte [] Charset) untuk mendapatkan sebuah String dari itu yang dapat Anda percayai. Charsets akan berarti bagi Anda selama hidup Anda, jadi waspadalah terhadap hal ini sekarang.

Yang lain telah memberikan kode dan barang, dan saya tidak ingin mencuri kemuliaan mereka. ;)

Haakon Løtveit
sumber
2

Menggunakan perpustakaan ini , ini adalah satu baris:

String data = IO.from(new File("data.txt")).toString();
satnam
sumber
1
jika garis-garis di dalam perpustakaan tidak dihitung.
Ari
2

Juga jika file Anda berada di dalam toples, Anda juga dapat menggunakan ini:

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

Path harus dimulai dengan / misalnya jika toples Anda

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

Maka Anda ingin memanggilnya seperti ini:

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

Dalam satu baris (Java 8), dengan asumsi Anda memiliki Reader:

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

Berdasarkan jawaban @ erickson, Anda dapat menggunakan:

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