Utilitas untuk membaca file teks sumber ke String (Java) [ditutup]
215
Apakah ada utilitas yang membantu untuk membaca file teks di sumber menjadi String. Saya kira ini adalah persyaratan yang populer, tetapi saya tidak dapat menemukan utilitas apa pun setelah Googling.
tolong jelaskan apa yang Anda maksud dengan "file teks sumber daya" vs "file teks dalam sumber daya" - tidak mudah untuk memahami apa yang Anda coba capai.
Mat
Itu hanya file teks di bawah classpath seperti "classpath *: mytext / text.txt"
Loc Phan
Jawaban:
301
Ya, Guava menyediakan ini di Resourceskelas. Sebagai contoh:
URL url =Resources.getResource("foo.txt");String text =Resources.toString(url,StandardCharsets.UTF_8);
@JonSkeet Ini bagus, namun untuk aplikasi web mungkin bukan solusi terbaik, implementasi getResourcemenggunakan Resource.class.getClassLoadertetapi dalam aplikasi web, ini mungkin bukan "Anda" loader kelas, jadi disarankan (misalnya dalam [1]) untuk menggunakan Thread.currentThread().getContextClassLoader().getResourceAsStreamsebagai gantinya (referensi [1]: stackoverflow.com/questions/676250/… )
Eran Medan
2
@EranMedan: Ya, jika Anda ingin classloader konteks Anda ingin menggunakannya secara eksplisit.
Jon Skeet
6
Dalam kasus khusus ketika sumber daya di sebelah kelas Anda, Anda dapat melakukan Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)yang menjamin penggunaan loader kelas yang benar.
Bogdan Calmac
2
com.google.common.io.Resourcesditandai tidak stabil menurut SonarQube
Ghilteras
1
guavatelah mengubah implementasinya. Untuk jambu 23 implementasinya suka mengikuti. ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
xxy
170
Anda dapat menggunakan oneliner trik Stupid Scanner tua untuk melakukannya tanpa ketergantungan tambahan seperti jambu biji:
String text =newScanner(AppropriateClass.class.getResourceAsStream("foo.txt"),"UTF-8").useDelimiter("\\A").next();
Kawan, jangan gunakan barang pihak ketiga kecuali Anda benar-benar membutuhkannya. Sudah banyak fungsi di JDK.
Menghindari pihak ketiga adalah prinsip yang masuk akal. Sayangnya perpustakaan inti tampaknya alergi untuk memodelkan kasus penggunaan kehidupan nyata. Lihatlah File Java 7, dan katakan padaku mengapa membaca semuanya dari sumber classpath tidak termasuk di sana? Atau setidaknya menggunakan 'sistem file' standar.
Dilum Ranatunga
3
Apakah - atau tidak - perlu untuk menutup aliran juga? Jambu biji secara internal menutup aliran.
virgo47
Bekerja dengan baik untuk saya juga! Saya setuju tentang hal pihak ke-3 juga: Dalam banyak jawaban, respons default tampaknya selalu menggunakan beberapa perpustakaan pihak ketiga - baik dari Apache atau orang lain.
Terje Dahl
1
ubah CartApplication.class.getResourceAsStreamuntuk CartApplication.class.getClassLoader().getResourceAsStreammemuat sumber daya di toples saat ini..seperti srm / test / resource
Chris DaMour
5
Meskipun saya sudah menggunakan ini, saya sepenuhnya tidak setuju untuk menghindari paket pihak ke-3. Fakta bahwa di Jawa, satu-satunya cara untuk dengan mudah membaca file ke string adalah dengan trik pemindai cukup menyedihkan. Alternatif untuk menggunakan lib pihak ke-3 adalah bahwa setiap orang hanya akan membuat bungkusnya sendiri. Guava untuk IO secara langsung menang jika Anda memiliki banyak kebutuhan untuk jenis operasi ini. Di mana saya AKAN setuju adalah bahwa Anda tidak boleh mengimpor paket pihak ke-3 jika Anda hanya memiliki satu tempat dalam kode Anda di mana Anda ingin melakukan ini. Itu akan menjadi imo yang berlebihan.
Jelaskan tolong mengapa ini bekerja, mengapa itu lebih baik daripada alternatif lain, dan pertimbangan kinerja / pengkodean apa pun diperlukan.
nanofarad
5
Ini adalah nio 2 di java 1.7. Ini adalah feture asli dari java. Untuk pengkodean, gunakan String baru (byte, StandardCharsets.UTF_8)
Kovalsky Dmitryi
5
dalam kasus saya, saya membutuhkan getClass().getClassLoader()tetapi sebaliknya solusi hebat!
Emmanuel Touzery
3
Ini tidak akan berfungsi, setelah aplikasi dimasukkan ke dalam toples.
Daniel Bo
65
Solusi Java 8+ yang murni dan sederhana, ramah guci
Metode sederhana di bawah ini akan baik-baik saja jika Anda menggunakan Java 8 atau lebih tinggi:
/**
* Reads given resource file as a string.
*
* @param fileName path to the resource file
* @return the file's contents
* @throws IOException if read fails for any reason
*/staticString getResourceFileAsString(String fileName)throwsIOException{ClassLoader classLoader =ClassLoader.getSystemClassLoader();try(InputStream is = classLoader.getResourceAsStream(fileName)){if(is ==null)returnnull;try(InputStreamReader isr =newInputStreamReader(is);BufferedReader reader =newBufferedReader(isr)){return reader.lines().collect(Collectors.joining(System.lineSeparator()));}}}
Dan itu juga berfungsi dengan sumber daya dalam file jar .
Tentang penyandian teks: InputStreamReaderakan menggunakan charset sistem default jika Anda tidak menentukannya. Anda mungkin ingin menentukannya sendiri untuk menghindari masalah decoding, seperti ini:
newInputStreamReader(isr,StandardCharsets.UTF_8);
Hindari ketergantungan yang tidak perlu
Selalu lebih suka tidak bergantung pada perpustakaan besar dan gemuk. Kecuali jika Anda sudah menggunakan Guava atau Apache Commons IO untuk tugas-tugas lain, menambahkan pustaka-pustaka itu ke proyek Anda hanya untuk dapat membaca dari sebuah file sepertinya terlalu banyak.
Metode "Sederhana"? Kamu pasti bercanda
Saya mengerti bahwa Java murni tidak melakukan pekerjaan dengan baik ketika melakukan tugas-tugas sederhana seperti ini. Misalnya, ini adalah cara kami membaca dari file di Node.js:
Sederhana dan mudah dibaca (walaupun orang masih suka mengandalkan banyak dependensi, sebagian besar karena ketidaktahuan). Atau dengan Python:
with open('some-file.txt','r')as f:
content = f.read()
Ini menyedihkan, tetapi masih sederhana untuk standar Java dan yang harus Anda lakukan adalah menyalin metode di atas untuk proyek Anda dan menggunakannya. Saya bahkan tidak meminta Anda untuk memahami apa yang terjadi di sana, karena itu benar-benar tidak masalah bagi siapa pun. Itu hanya berfungsi, titik :-)
@zakmck, cobalah untuk membuat komentar Anda konstruktif. Ketika Anda tumbuh sebagai pengembang yang matang, Anda belajar bahwa kadang-kadang Anda memang ingin "menemukan kembali roda". Misalnya, Anda mungkin perlu menjaga biner Anda di bawah ukuran ambang sesuatu. Perpustakaan sering membuat ukuran aplikasi Anda bertambah dengan urutan besarnya. Orang bisa saja berpendapat sebaliknya dari apa yang Anda katakan: "Tidak perlu menulis kode. Ya, mari kita mengimpor perpustakaan setiap waktu". Apakah Anda benar-benar lebih suka mengimpor perpustakaan hanya untuk menghemat 3 baris kode? Saya yakin menambahkan perpustakaan akan meningkatkan LOC Anda lebih dari itu. Kuncinya adalah keseimbangan.
Lucio Paiva
3
Yah, tidak semua orang menjalankan hal-hal di cloud. Ada sistem tertanam di mana-mana menjalankan Java, misalnya. Saya hanya tidak melihat maksud Anda dalam mengkritik jawaban yang memberikan pendekatan yang benar-benar valid, mengingat Anda menyebut diri Anda bahwa Anda akan menerima saran untuk menggunakan JDK secara langsung dalam kode Anda sendiri. Bagaimanapun, mari kita coba untuk menjaga komentar secara ketat untuk membantu meningkatkan jawaban, bukan untuk membahas pendapat.
Lucio Paiva
1
Solusi JDK-only yang bagus. Saya hanya akan menambahkan memeriksa apakah InputStreamvariabel isadalah nullatau tidak.
scrutari
2
Bagus. Saya menggunakan ini. Anda dapat mempertimbangkan untuk menutup aliran / pembaca juga.
dimplex
1
@RobertBain Saya mengedit jawaban untuk menambahkan info tentang peringatan charset. Beri tahu saya jika Anda menemukan apa yang salah dengan loader kelas di AWS sehingga saya dapat menambahkannya ke jawabannya juga. Terima kasih!
Lucio Paiva
57
Guava memiliki metode "toString" untuk membaca file menjadi sebuah String:
Atau jika ini adalah input stream, jambu biji juga memiliki cara yang bagus untuk iniString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Saya lebih suka "" dalam hal ini jika ini tidak tersedia
user833970
11
Sama seperti kompak, tetapi dengan penutupan yang tepat dari input stream: IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8").
Bogdan Calmac
1
Jika solusi ini tidak berhasil, coba tambahkan getClassLoader()ke rantai metode: String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
URL url =Resources.getResource("myFile.txt");File myFile =newFile(url.toURI());String content =FileUtils.readFileToString(myFile,"UTF-8");// or any other encoding
Mengapa kita harus menentukan pengkodean, saya tidak mengerti. Jika saya membaca file, saya hanya ingin apa yang ada di dalamnya, itu harus mencari tahu apa pengkodeannya seperti editor saya. Ketika saya buka di Notepad atau ++, saya tidak memberi tahu kode apa yang harus digunakan. Saya menggunakan metode ini dan kemudian writeStringToFile ... tetapi isinya berbeda. Saya mendapatkan token aneh dalam file kloning .. saya tidak mengerti mengapa saya harus menentukan pengkodean.
mmm
11
@ Hamidan, memilih penyandian yang tepat adalah algoritma yang sangat kompleks. Ini sering diimplementasikan dalam editor teks tetapi mereka kadang-kadang gagal mendeteksi pengkodean yang benar. Saya tidak akan mengharapkan API pembacaan file untuk menyematkan algoritma yang kompleks untuk membaca file saya.
Vincent Robert
1
@SecretService Juga, algoritma tersebut menggunakan informasi seperti bahasa sistem operasi, lokal, dan pengaturan regional lainnya yang berarti bahwa membaca file tanpa menentukan pengkodean dapat bekerja pada pengaturan Anda tetapi tidak pada orang lain.
Saya tidak berpikir ini akan berhasil jika sumber daya ditemukan di dalam toples. Maka itu tidak akan menjadi file.
Ville Oikarinen
16
Saya sendiri sering mengalami masalah ini. Untuk menghindari ketergantungan pada proyek-proyek kecil, saya sering menulis fungsi utilitas kecil ketika saya tidak memerlukan commons io atau semacamnya. Berikut adalah kode untuk memuat konten file dalam buffer string:
StringBuffer sb =newStringBuffer();BufferedReader br =newBufferedReader(newInputStreamReader(getClass().getResourceAsStream("path/to/textfile.txt"),"UTF-8"));for(int c = br.read(); c !=-1; c = br.read()) sb.append((char)c);System.out.println(sb.toString());
Menentukan pengkodean adalah penting dalam hal ini, karena Anda mungkin telah diedit file Anda dalam UTF-8, dan kemudian memasukkannya ke dalam toples, dan komputer yang membuka file tersebut mungkin memiliki CP-1251 sebagai file encoding asli (misalnya) ; jadi dalam hal ini Anda tidak pernah tahu target encoding, oleh karena itu informasi encoding eksplisit sangat penting. Juga loop untuk membaca file char oleh char tampaknya tidak efisien, tetapi digunakan pada BufferedReader, dan sebenarnya cukup cepat.
File hanya berfungsi untuk sumber daya classpath yang, baik, file. Tidak jika mereka elemen dalam file .jar, atau bagian dari guci lemak, salah satu implementasi classloader lainnya.
toolforger
2
Saya menggunakan berikut ini untuk membaca file sumber daya dari classpath:
package test;import java.io.InputStream;import java.nio.charset.StandardCharsets;import java.util.Scanner;publicclassMain{publicstaticvoid main(String[] args){try{String fileContent = getFileFromResources("resourcesFile.txt");System.out.println(fileContent);}catch(Exception e){
e.printStackTrace();}}//USE THIS FUNCTION TO READ CONTENT OF A FILE, IT MUST EXIST IN "RESOURCES" FOLDERpublicstaticString getFileFromResources(String fileName)throwsException{ClassLoader classLoader =Main.class.getClassLoader();InputStream stream = classLoader.getResourceAsStream(fileName);String text =null;try(Scanner scanner =newScanner(stream,StandardCharsets.UTF_8.name())){
text = scanner.useDelimiter("\\A").next();}return text;}}
Setidaknya pada Apache commons-io 2.5, metode IOUtils.toString () mendukung argumen URI dan mengembalikan konten file yang terletak di dalam guci di classpath:
Saya suka jawaban akosicki dengan Trik Pemindai Bodoh. Ini yang paling sederhana yang saya lihat tanpa dependensi eksternal yang berfungsi di Java 8 (dan sebenarnya semua jalan kembali ke Java 5). Inilah jawaban yang bahkan lebih sederhana jika Anda dapat menggunakan Java 9 atau lebih tinggi (sejak InputStream.readAllBytes()ditambahkan di Java 9):
String text =newString(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());
Dari mana IOUtils berasal? Sumber harus dirujuk dengan jelas.
ehecatl
0
Saya telah menulis metode readResource () di sini , untuk dapat melakukannya dalam satu permintaan sederhana. Itu tergantung pada perpustakaan Guava, tapi saya suka metode JDK saja yang disarankan dalam jawaban lain dan saya pikir saya akan mengubahnya seperti itu.
publicclassUtils{publicstaticString readResource(String name)throwsURISyntaxException,IOException{
var uri =Utils.class.getResource("/"+ name).toURI();
var path =Paths.get(uri);returnFiles.readString(path);}}
Saya menyukai utilitas commons Apache untuk jenis barang ini dan menggunakan case-use yang tepat ini (membaca file dari classpath) secara luas saat pengujian, terutama untuk membaca file JSON dari /src/test/resourcessebagai bagian dari unit / pengujian integrasi. misalnya
publicclassFileUtils{publicstaticString getResource(String classpathLocation){try{String message =IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),Charset.defaultCharset());return message;}catch(IOException e){thrownewRuntimeException("Could not read file [ "+ classpathLocation +" ] from classpath", e);}}}
Untuk tujuan pengujian, akan lebih baik untuk menangkap IOExceptiondan melempar RuntimeException- kelas tes Anda bisa terlihat seperti misalnya
@Testpublicvoid shouldDoSomething (){String json =FileUtils.getResource("/json/input.json");// Use json as part of test ...}
Jawaban:
Ya, Guava menyediakan ini di
Resources
kelas. Sebagai contoh:sumber
getResource
menggunakanResource.class.getClassLoader
tetapi dalam aplikasi web, ini mungkin bukan "Anda" loader kelas, jadi disarankan (misalnya dalam [1]) untuk menggunakanThread.currentThread().getContextClassLoader().getResourceAsStream
sebagai gantinya (referensi [1]: stackoverflow.com/questions/676250/… )Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)
yang menjamin penggunaan loader kelas yang benar.com.google.common.io.Resources
ditandai tidak stabil menurut SonarQubeguava
telah mengubah implementasinya. Untuk jambu 23 implementasinya suka mengikuti.ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
Anda dapat menggunakan oneliner trik Stupid Scanner tua untuk melakukannya tanpa ketergantungan tambahan seperti jambu biji:
Kawan, jangan gunakan barang pihak ketiga kecuali Anda benar-benar membutuhkannya. Sudah banyak fungsi di JDK.
sumber
CartApplication.class.getResourceAsStream
untukCartApplication.class.getClassLoader().getResourceAsStream
memuat sumber daya di toples saat ini..seperti srm / test / resourceUntuk java 7:
sumber
getClass().getClassLoader()
tetapi sebaliknya solusi hebat!Solusi Java 8+ yang murni dan sederhana, ramah guci
Metode sederhana di bawah ini akan baik-baik saja jika Anda menggunakan Java 8 atau lebih tinggi:
Dan itu juga berfungsi dengan sumber daya dalam file jar .
Tentang penyandian teks:
InputStreamReader
akan menggunakan charset sistem default jika Anda tidak menentukannya. Anda mungkin ingin menentukannya sendiri untuk menghindari masalah decoding, seperti ini:Hindari ketergantungan yang tidak perlu
Selalu lebih suka tidak bergantung pada perpustakaan besar dan gemuk. Kecuali jika Anda sudah menggunakan Guava atau Apache Commons IO untuk tugas-tugas lain, menambahkan pustaka-pustaka itu ke proyek Anda hanya untuk dapat membaca dari sebuah file sepertinya terlalu banyak.
Metode "Sederhana"? Kamu pasti bercanda
Saya mengerti bahwa Java murni tidak melakukan pekerjaan dengan baik ketika melakukan tugas-tugas sederhana seperti ini. Misalnya, ini adalah cara kami membaca dari file di Node.js:
Sederhana dan mudah dibaca (walaupun orang masih suka mengandalkan banyak dependensi, sebagian besar karena ketidaktahuan). Atau dengan Python:
Ini menyedihkan, tetapi masih sederhana untuk standar Java dan yang harus Anda lakukan adalah menyalin metode di atas untuk proyek Anda dan menggunakannya. Saya bahkan tidak meminta Anda untuk memahami apa yang terjadi di sana, karena itu benar-benar tidak masalah bagi siapa pun. Itu hanya berfungsi, titik :-)
sumber
InputStream
variabelis
adalahnull
atau tidak.Guava memiliki metode "toString" untuk membaca file menjadi sebuah String:
Metode ini tidak memerlukan file berada di classpath (seperti dalam jawaban Jon Skeet sebelumnya).
sumber
String stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
yegor256 telah menemukan solusi yang bagus menggunakan Apache Commons IO :
sumber
IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")
.getClassLoader()
ke rantai metode:String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
apache-commons-io memiliki nama utilitas
FileUtils
:sumber
Saya sendiri sering mengalami masalah ini. Untuk menghindari ketergantungan pada proyek-proyek kecil, saya sering menulis fungsi utilitas kecil ketika saya tidak memerlukan commons io atau semacamnya. Berikut adalah kode untuk memuat konten file dalam buffer string:
Menentukan pengkodean adalah penting dalam hal ini, karena Anda mungkin telah diedit file Anda dalam UTF-8, dan kemudian memasukkannya ke dalam toples, dan komputer yang membuka file tersebut mungkin memiliki CP-1251 sebagai file encoding asli (misalnya) ; jadi dalam hal ini Anda tidak pernah tahu target encoding, oleh karena itu informasi encoding eksplisit sangat penting. Juga loop untuk membaca file char oleh char tampaknya tidak efisien, tetapi digunakan pada BufferedReader, dan sebenarnya cukup cepat.
sumber
Anda dapat menggunakan kode berikut dari Java
sumber
Jika Anda ingin mendapatkan String dari sumber daya proyek seperti file testcase / foo.json di src / main / resources di proyek Anda, lakukan ini:
Perhatikan bahwa metode getClassLoader () tidak ada pada beberapa contoh lainnya.
sumber
Gunakan FileUtils Apache commons. Ini memiliki metode readFileToString
sumber
Saya menggunakan berikut ini untuk membaca file sumber daya dari
classpath
:Tidak diperlukan dependensi pihak ketiga.
sumber
Dengan set impor statis, solusi Guava bisa sangat kompak satu-liner:
Diperlukan impor berikut:
sumber
sumber
Setidaknya pada Apache commons-io 2.5, metode IOUtils.toString () mendukung argumen URI dan mengembalikan konten file yang terletak di dalam guci di classpath:
sumber
Saya suka jawaban akosicki dengan Trik Pemindai Bodoh. Ini yang paling sederhana yang saya lihat tanpa dependensi eksternal yang berfungsi di Java 8 (dan sebenarnya semua jalan kembali ke Java 5). Inilah jawaban yang bahkan lebih sederhana jika Anda dapat menggunakan Java 9 atau lebih tinggi (sejak
InputStream.readAllBytes()
ditambahkan di Java 9):sumber
Jambu juga memiliki
Files.readLines()
jika Anda ingin nilai kembali sebagaiList<String>
baris-demi-baris:Silakan merujuk ke sini untuk membandingkan 3 cara (
BufferedReader
vs Jambu bijiFiles
vs Jambu bijiResources
) untuk mendapatkanString
dari file teks.sumber
Charsets
juga ada di Guava. Lihat ini: google.github.io/guava/releases/23.0/api/docsInilah pendekatan saya yang bekerja dengan baik
sumber
Saya telah menulis metode readResource () di sini , untuk dapat melakukannya dalam satu permintaan sederhana. Itu tergantung pada perpustakaan Guava, tapi saya suka metode JDK saja yang disarankan dalam jawaban lain dan saya pikir saya akan mengubahnya seperti itu.
sumber
Jika Anda memasukkan Jambu Biji, maka Anda dapat menggunakan:
(Solusi lain menyebutkan metode lain untuk Jambu tetapi mereka sudah usang)
sumber
Cod berikut ini berfungsi untuk saya:
sumber
Berikut ini solusi menggunakan Java 11
Files.readString
:sumber
Saya membuat metode statis NO-dependensi seperti ini:
sumber
Saya menyukai utilitas commons Apache untuk jenis barang ini dan menggunakan case-use yang tepat ini (membaca file dari classpath) secara luas saat pengujian, terutama untuk membaca file JSON dari
/src/test/resources
sebagai bagian dari unit / pengujian integrasi. misalnyaUntuk tujuan pengujian, akan lebih baik untuk menangkap
IOException
dan melemparRuntimeException
- kelas tes Anda bisa terlihat seperti misalnyasumber
sumber