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.

Loc Phan
sumber
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);
Jon Skeet
sumber
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.

akosicki
sumber
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())));
Kovalsky Dmitryi
sumber
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 :-)

Lucio Paiva
sumber
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).

Luciano Fiandesio
sumber
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");
Stefan Endrullis
sumber
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
Andreas Dolk
sumber
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.

Harry Karadimas
sumber
15

Anda dapat menggunakan kode berikut dari Java

new String(Files.readAllBytes(Paths.get(getClass().getResource("example.txt").toURI())));
Raghu K Nair
sumber
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.

Witbrock
sumber
2

Gunakan FileUtils Apache commons. Ini memiliki metode readFileToString

Suraj Chandran
sumber
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.

BullyWiiPlaza
sumber
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
Michal Kordas
sumber
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;
    }
}
sklimkovitch
sumber
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(), ...)
pengguna1050755
sumber
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());
Gary S.
sumber
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.

philipjkim
sumber
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
    }
}
Java_Fire_Within
sumber
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.

zakmck
sumber
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)

jolumg
sumber
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");
Vicky
sumber
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);
    }
}
Dillon Ryan Redding
sumber
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
}
espreso
sumber
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 ...
    }
bobmarksie
sumber
-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");
Khắc Nghĩa Từ
sumber
Silakan tambahkan penjelasan singkat untuk jawaban Anda.
Nikolay Mihaylov