Pertanyaan Bagaimana cara membuat string Java dari isi file?


Saya telah menggunakan idiom di bawah ini untuk beberapa waktu sekarang. Dan tampaknya yang paling luas, setidaknya di situs yang pernah 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();
    }
}

1210
2017-11-28 18:32


asal


Jawaban:


Baca semua teks dari file

Inilah idiom yang ringkas dan kuat untuk Java 7, yang 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 a metode kenyamanan untuk membaca file sebagai baris teks, diwakili sebagai List<String>. Pendekatan ini "lossy" karena pemisah garis dilucuti dari ujung setiap baris.

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

Di Java 8, BufferedReader menambahkan metode baru, lines() untuk menghasilkan Stream<String>. Jika IOException ditemui saat membaca file, itu dibungkus dalam UncheckedIOException, sejak Stream tidak menerima lambdas yang mengecualikan pengecualian.

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

Ada juga a Files.lines() metode yang melakukan sesuatu yang sangat mirip, mengembalikan Stream<String> langsung. Tapi saya tidak suka itu. Itu Stream membutuhkan close() panggilan; ini tidak didokumentasikan dengan baik di API, dan saya kira banyak orang bahkan tidak menyadarinya Stream mempunyai sebuah close() metode. Jadi kode Anda akan terlihat sangat mirip, seperti ini:

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

Perbedaannya adalah Anda memiliki Stream ditugaskan ke variabel, dan saya mencoba menghindari itu sebagai praktik sehingga saya tidak sengaja mencoba untuk memohon aliran dua kali.

Pemanfaatan memori

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

Metode kedua, membaca garis, biasanya lebih efisien memori, karena input byte buffer untuk decoding tidak perlu memuat 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 aliran, memprosesnya, dan kemudian berpindah ke yang berikutnya, menggunakan kembali blok memori berukuran tetap yang sama. Di sini, "besar" tergantung pada spesifikasi komputer. Saat ini, ambang ini mungkin banyak gigabyte RAM. Metode ketiga, menggunakan a Stream<String> adalah salah satu cara untuk melakukan ini, jika masukan Anda "mencatat" terjadi menjadi garis individu. (Menggunakan readLine() metode dari BufferedReader adalah prosedural yang setara dengan pendekatan ini.)

Encoding karakter

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

Itu StandardCharsets kelas mendefinisikan beberapa konstanta untuk pengkodean yang dibutuhkan dari semua runtime Java:

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

Default platform tersedia dari itu Charsetkelas diri:

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 dari dihapus sampai buffer yang dipetakan adalah sampah yang dikumpulkan. Anda dapat melihat versi lama melalui tautan "diedit" pada jawaban ini.


1251
2017-11-28 18:56



Commons FileUtils.readFileToString:

public static String readFileToString(File file)
                       throws IOException

Membaca isi file ke dalam String menggunakan pengkodean default   untuk VM. File selalu tertutup.

Parameter:

  • file - file untuk dibaca, tidak boleh nol

Pengembalian:   isi file, tidak pernah batal

Melempar:    - IOException - jika ada kesalahan I / O

Sejak:   Commons IO 1.3.1

Kode yang digunakan (secara tidak langsung) oleh kelas itu adalah:

IOUtils.java dibawah Lisensi Apache 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;
}

Ini sangat mirip dengan yang digunakan oleh Ritche_W.


296
2017-11-28 18:44



Dari halaman ini solusi yang sangat ramping:

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

atau

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

Jika Anda ingin mengatur charset


159
2017-09-16 20:02



Jika Anda mencari alternatif yang tidak melibatkan pustaka pihak ketiga (mis. Commons I / O), Anda dapat menggunakan Scanner kelas:

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

68
2017-11-28 19:00



Jambu biji memiliki metode yang mirip dengan yang dari Commons IOUtils yang Willi aus Rohr sebutkan:

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

// ...

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

EDIT oleh Oscar Reyes

Ini adalah kode yang mendasari (yang 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 );

Edit (oleh Jonik): Di atas tidak cocok dengan kode sumber versi Guava terbaru. Untuk sumber saat ini, lihat kelas File, CharStreams, ByteSource dan CharSource di com.google.common.io paket.


63
2018-04-16 14:33



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

50
2017-10-29 08:51



Jika Anda membutuhkan pemrosesan string (pemrosesan paralel), Java 8 memiliki Stream API 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/BulkDataOperations yang dapat diunduh Halaman unduh Oracle Java SE 8 

Contoh satu liner lainnya

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

44
2017-11-28 19:56



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

Berikut ini adalah alternatif yang tidak melakukan itu, dan mana yang (IMO) lebih mudah dipahami daripada kode NIO (meskipun masih digunakan 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();
    }        
}

44
2017-10-28 07:04



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

karena java 7 Anda bisa melakukannya dengan cara ini.


40
2017-10-17 15:34