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.


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

21
@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 = new Scanner(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.


41
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.
Kenny Cason

90

Untuk java 7:

new String(Files.readAllBytes(Paths.get(getClass().getResource("foo.txt").toURI())));

3
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
 */
static String getResourceFileAsString(String fileName) throws IOException {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    try (InputStream is = classLoader.getResourceAsStream(fileName)) {
        if (is == null) return null;
        try (InputStreamReader isr = new InputStreamReader(is);
             BufferedReader reader = new BufferedReader(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:

new InputStreamReader(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:

const fs = require("fs");
const contents = fs.readFileSync("some-file.txt", "utf-8");

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


4
@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:

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

String content = Files.toString(new File("/home/x1/text.log"), Charsets.UTF_8);

Metode ini tidak memerlukan file berada di classpath (seperti dalam jawaban Jon Skeet sebelumnya).


2
Atau jika ini adalah input stream, jambu biji juga memiliki cara yang bagus untuk iniString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Eran Medan

1
Ini tidak berlaku lagi di Guava 24.1
Andrey

47

yegor256 telah menemukan solusi yang bagus menggunakan Apache Commons IO :

import org.apache.commons.io.IOUtils;

String text = IOUtils.toString(this.getClass().getResourceAsStream("foo.xml"),
                               "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);
Abdull

39

apache-commons-io memiliki nama utilitas FileUtils:

URL url = Resources.getResource("myFile.txt");
File myFile = new File(url.toURI());

String content = FileUtils.readFileToString(myFile, "UTF-8");  // or any other encoding

1
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.
Feuermurmel

Apache FileUtils . readLines (file) & copyURLToFile (URL, tempFile).
Yash

2
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 = new StringBuffer();

BufferedReader br = new BufferedReader(new InputStreamReader(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.


15

Anda dapat menggunakan kode berikut dari Java

new String(Files.readAllBytes(Paths.get(getClass().getResource("example.txt").toURI())));

Pernyataan impor apa yang diperlukan untuk menarik kelas "File" dan "Paths"?
Steve Scherer

1
keduanya adalah bagian dari paket java.nio.file tersedia dari JDK 7+
Raghu K Nair

Tidak berfungsi saat dalam file jar.
Singkirkan

4

Jika Anda ingin mendapatkan String dari sumber daya proyek seperti file testcase / foo.json di src / main / resources di proyek Anda, lakukan ini:

String myString= 
 new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("testcase/foo.json").toURI())));

Perhatikan bahwa metode getClassLoader () tidak ada pada beberapa contoh lainnya.


2

Gunakan FileUtils Apache commons. Ini memiliki metode readFileToString


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:

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Scanner;

public class ResourceUtilities
{
    public static String resourceToString(String filePath) throws IOException, URISyntaxException
    {
        try (InputStream inputStream = ResourceUtilities.class.getClassLoader().getResourceAsStream(filePath))
        {
            return inputStreamToString(inputStream);
        }
    }

    private static String inputStreamToString(InputStream inputStream)
    {
        try (Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"))
        {
            return scanner.hasNext() ? scanner.next() : "";
        }
    }
}

Tidak diperlukan dependensi pihak ketiga.


1

Dengan set impor statis, solusi Guava bisa sangat kompak satu-liner:

toString(getResource("foo.txt"), UTF_8);

Diperlukan impor berikut:

import static com.google.common.io.Resources.getResource
import static com.google.common.io.Resources.toString
import static java.nio.charset.StandardCharsets.UTF_8

1
package test;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Main {
    public static void 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" FOLDER
    public static String getFileFromResources(String fileName) throws Exception {
        ClassLoader classLoader = Main.class.getClassLoader();
        InputStream stream = classLoader.getResourceAsStream(fileName);
        String text = null;
        try (Scanner scanner = new Scanner(stream, StandardCharsets.UTF_8.name())) {
            text = scanner.useDelimiter("\\A").next();
        }
        return text;
    }
}

1

Setidaknya pada Apache commons-io 2.5, metode IOUtils.toString () mendukung argumen URI dan mengembalikan konten file yang terletak di dalam guci di classpath:

IOUtils.toString(SomeClass.class.getResource(...).toURI(), ...)

1

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 = new String(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());

0

Jambu juga memiliki Files.readLines()jika Anda ingin nilai kembali sebagai List<String>baris-demi-baris:

List<String> lines = Files.readLines(new File("/file/path/input.txt"), Charsets.UTF_8);

Silakan merujuk ke sini untuk membandingkan 3 cara ( BufferedReadervs Jambu biji Filesvs Jambu biji Resources) untuk mendapatkan Stringdari file teks.


Apa itu kelas Charsets? bukan asli
e-info128

@ e-info128 Charsetsjuga ada di Guava. Lihat ini: google.github.io/guava/releases/23.0/api/docs
philipjkim

0

Inilah pendekatan saya yang bekerja dengan baik

public String getFileContent(String fileName) {
    String filePath = "myFolder/" + fileName+ ".json";
    try(InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath)) {
        return IOUtils.toString(stream, "UTF-8");
    } catch (IOException e) {
        // Please print your Exception
    }
}

2
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.


0

Jika Anda memasukkan Jambu Biji, maka Anda dapat menggunakan:

String fileContent = Files.asCharSource(new File(filename), Charset.forName("UTF-8")).read();

(Solusi lain menyebutkan metode lain untuk Jambu tetapi mereka sudah usang)


0

Cod berikut ini berfungsi untuk saya:

compile group: 'commons-io', name: 'commons-io', version: '2.6'

@Value("classpath:mockResponse.json")
private Resource mockResponse;

String mockContent = FileUtils.readFileToString(mockResponse.getFile(), "UTF-8");

0

Berikut ini solusi menggunakan Java 11 Files.readString:

public class Utils {
    public static String readResource(String name) throws URISyntaxException, IOException {
        var uri = Utils.class.getResource("/" + name).toURI();
        var path = Paths.get(uri);
        return Files.readString(path);
    }
}

0

Saya membuat metode statis NO-dependensi seperti ini:

import java.nio.file.Files;
import java.nio.file.Paths;

public class ResourceReader {
    public  static String asString(String resourceFIleName) {
        try  {
            return new String(Files.readAllBytes(Paths.get(new CheatClassLoaderDummyClass().getClass().getClassLoader().getResource(resourceFIleName).toURI())));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
class CheatClassLoaderDummyClass{//cheat class loader - for sql file loading
}

0

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

public class FileUtils {

    public static String getResource(String classpathLocation) {
        try {
            String message = IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),
                    Charset.defaultCharset());
            return message;
        }
        catch (IOException e) {
            throw new RuntimeException("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

    @Test
    public void shouldDoSomething () {
        String json = FileUtils.getResource("/json/input.json");

        // Use json as part of test ...
    }

-2
public static byte[] readResoureStream(String resourcePath) throws IOException {
    ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
    InputStream in = CreateBffFile.class.getResourceAsStream(resourcePath);

    //Create buffer
    byte[] buffer = new byte[4096];
    for (;;) {
        int nread = in.read(buffer);
        if (nread <= 0) {
            break;
        }
        byteArray.write(buffer, 0, nread);
    }
    return byteArray.toByteArray();
}

Charset charset = StandardCharsets.UTF_8;
String content = new   String(FileReader.readResoureStream("/resource/...*.txt"), charset);
String lines[] = content.split("\\n");

Silakan tambahkan penjelasan singkat untuk jawaban Anda.
Nikolay Mihaylov
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.