Утиліти для читання текстового файлу ресурсу до String (Java) [закрито]


215

Чи є якась утиліта, яка допомагає читати текстовий файл із ресурсу в String. Я вважаю, що це популярна вимога, але я не зміг знайти жодної утиліти після Googling.


1
уточніть, будь ласка, що ви маєте на увазі під "текстовим файлом ресурсу" проти "текстовим файлом у ресурсі" - зрозуміти, що ви намагаєтесь досягти, непросто.
Мат

Це просто текстовий файл під classpath на зразок "classpath *: mytext / text.txt"
Loc Phan

Відповіді:


301

Так, Guava забезпечує це у Resourcesкласі. Наприклад:

URL url = Resources.getResource("foo.txt");
String text = Resources.toString(url, StandardCharsets.UTF_8);

21
@JonSkeet Це чудово, однак для веб-додатків це може бути не найкращим рішенням, реалізація getResourceвикористовується, Resource.class.getClassLoaderале у веб-додатках це може бути не вашим завантажувачем класів, тому рекомендується (наприклад, у [1]) використовувати Thread.currentThread().getContextClassLoader().getResourceAsStreamнатомість (посилання [1]: stackoverflow.com/questions/676250/… )
Еран Медан

2
@EranMedan: Так, якщо ви хочете завантажувач контексту, ви хочете використовувати його явно.
Джон Скіт

6
У спеціальному випадку, коли ресурс знаходиться поруч з вашим класом, ви можете зробити це, Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8)що гарантує використання правильного завантажувача класів.
Богдан Кальмак

2
com.google.common.io.Resourcesпозначається нестабільним згідно з SonarQube
Ghilteras

1
guavaзмінила реалізацію. Для guava 23 реалізація любить наступне. ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
xxy

171

Ви можете використовувати старий хитромудрий сканер Oneliner, щоб зробити це без будь-якої додаткової залежності, як гуава:

String text = new Scanner(AppropriateClass.class.getResourceAsStream("foo.txt"), "UTF-8").useDelimiter("\\A").next();

Хлопці, не використовуйте сторонні речі, якщо вам це дуже не потрібно. У JDK вже багато функціональних можливостей.


41
Уникнення третьої сторони - розумний принцип. На жаль, основна бібліотека здається алергічною на моделювання справ у реальному житті. Подивіться на файли Java 7 і скажіть, чому читання всього цього ресурсу не було включено? Або принаймні з використанням стандартизованої 'файлової системи'.
Dilum Ranatunga

3
Чи потрібно - чи це не так - потрібно також закривати потік? Гуава внутрішньо закриває потік.
virgo47

Працювали красиво і для мене! Я погоджуюсь і з стороннім ділом: у багатьох відповідях за замовчуванням завжди, як видається, використовується використання бібліотеки третьої сторони - будь то від Apache чи когось іншого.
Terje Dahl

1
змінити, CartApplication.class.getResourceAsStreamщоб CartApplication.class.getClassLoader().getResourceAsStreamзавантажити ресурси в поточній банці. як srm / test / ресурси
Chris DaMour

5
Хоча я цим користувався, я абсолютно не згоден у тому, щоб уникати сторонніх пакетів. Те, що в Java єдиний спосіб легко прочитати файл у рядок - це трюк сканера, є досить сумним. Альтернативою для використання сторонніх ліфтів є те, що кожен просто створить власні обгортки. Гуава для IO руки вниз виграє, якщо у вас дуже багато потреб у подібних операціях. Де я погоджусь, це те, що ви не повинні імпортувати сторонній пакет, якщо у вашому коді є лише одне місце, де ви хочете це зробити. Це було б надмірно imo.
Кенні Кейсон

90

Для java 7:

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

3
Поясніть, будь ласка, чому це працює, чому це краще, ніж інші альтернативи, та будь-які необхідні міркування щодо продуктивності / кодування.
нанофарад

5
Це nio 2 у java 1.7. Це рідна плід яви. Для кодування використовуйте новий рядок (байти, StandardCharsets.UTF_8)
Ковальський Дмитро

5
в моєму випадку мені було потрібно, getClass().getClassLoader()але в іншому випадку чудове рішення!
Еммануель Тузері

3
Це не спрацює, як тільки додаток буде упаковано в банку.
Даніель Бо

65

Чисте і просте, зручне для банку рішення Java 8+

Цей простий метод нижче буде добре, якщо ви використовуєте Java 8 або новіші версії:

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

А також він працює з ресурсами в jar-файлах .

Про кодування тексту: InputStreamReaderбуде використано системну схему за замовчуванням у випадку, якщо ви її не вказали. Ви можете вказати його самостійно, щоб уникнути проблем із розшифровкою, наприклад:

new InputStreamReader(isr, StandardCharsets.UTF_8);

Уникайте зайвих залежностей

Завжди віддайте перевагу не залежно від великих, жирних бібліотек. Якщо ви вже не використовуєте IO Guava або Apache Commons для інших завдань, додавання цих бібліотек до вашого проекту просто для того, щоб мати можливість читати з файлу, здається трохи занадто.

«Простий» метод? Ти, мабуть, жартуєш мене

Я розумію, що чиста Java не робить гарної роботи, коли справа стосується виконання таких простих завдань. Наприклад, ось так ми читаємо з файлу в Node.js:

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

Простий і легкий для читання (хоча люди все одно люблять покладатися на багато залежностей, в основному через незнання). Або в Python:

with open('some-file.txt', 'r') as f:
    content = f.read()

Це сумно, але для стандартів Java це все ще просто, і все, що вам потрібно зробити, - скопіювати вищевказаний метод у свій проект і використовувати його. Я навіть не прошу вас зрозуміти, що там відбувається, бо це нікому не важливо. Це просто працює, період :-)


4
@zakmck, будь ласка, спробуйте зберегти ваші коментарі конструктивними. Зростаючи як зрілий розробник, ви дізнаєтесь, що іноді вам хочеться «винаходити колесо». Наприклад, вам може знадобитися тримати ваш двійковий файл нижче чогось порогового розміру. Бібліотеки часто збільшують розмір вашої програми на порядки. Можна сказати прямо протилежне тому, що ви сказали: "Не потрібно писати код. Так, давайте щоразу імпортувати бібліотеки". Ви дійсно вважаєте за краще імпортувати бібліотеку лише для того, щоб заощадити 3 рядки коду? Б'юсь об заклад, що додавання бібліотеки збільшить ваш LOC більше ніж це. Ключ - баланс.
Лусіо Пайва

3
Ну, не кожен працює над хмарою. Наприклад, є вбудовані системи скрізь, де працює Java, наприклад. Я просто не бачу вашого сенсу критикувати відповіді, що дають цілком справедливі підходи, враховуючи, що ви згадуєте про себе, що збираєтесь приймати пропозицію використовувати JDK безпосередньо у власному коді. У будь-якому разі, давайте, будь ласка, спробуймо суворо коментувати, щоб допомогти покращити відповіді, а не обговорювати думки.
Лусіо Пайва

1
Гарне рішення лише для JDK. Я б додав лише перевірити, чи є InputStreamзмінною чи ні. isnull
scrutari

2
Приємно. Я цим користувався. Ви можете також розглянути можливість закриття потоків / читачів.
dimplex

1
@RobertBain Я відредагував відповідь, щоб додати інформацію про попередження про діаграму. Повідомте мене, якщо ви дізнаєтеся, що пішло не так із завантажувачем класу в AWS, щоб я міг також додати його до відповіді. Дякую!
Лусіо Пайва

57

Guava має метод "toString" для читання файлу в рядку:

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

Цей метод не вимагає, щоб файл знаходився в класі (як у попередній відповіді Джона Скета ).


2
Або якщо це вхідний потік, у гуави є і хороший спосіб для цьогоString stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Еран Медан

1
Це застаріло в Guava 24.1
Андрій

47

yegor256 знайшов хороше рішення за допомогою IO Apache Commons :

import org.apache.commons.io.IOUtils;

String text = IOUtils.toString(this.getClass().getResourceAsStream("foo.xml"),
                               "UTF-8");

Я віддаю перевагу "" цьому випадку, якщо це недоступно
user833970

11
Подібно до того , як компактний, але при належному закриття вхідного потоку: IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8").
Богдан Кальмак

1
Якщо це рішення не працює, спробуйте додати getClassLoader()до ланцюжка методів: String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
Абдул

39

apache-commons-io має назву утиліти 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
Чому треба вказати кодування, я цього не зрозумію. Якщо я читаю файл, я просто хочу те, що є в ньому, він повинен з'ясувати, що таке кодування, як це робить мій редактор. Коли я відкриваю в Блокноті або ++, я не кажу йому, яке кодування воно повинно використовувати. Я використовую цей метод, а потім пишуStringToFile ... але вміст відрізняється. Я отримую дивні лексеми у клонованому файлі .. Я не розумію, чому мені потрібно було б вказати кодування.
ммм

11
@Hamidan, вибір правильного кодування є дуже складним алгоритмом. Він часто реалізується в текстовому редакторі, але іноді не вдається виявити правильне кодування. Я не очікував, що API для читання файлів вбудує такий складний алгоритм, щоб прочитати мій файл.
Вінсент Роберт

1
@SecretService Крім того, ці алгоритми використовують інформацію, таку як мова, локальний запис та інші регіональні параметри операційної системи, що означає, що читання файлу без зазначення кодування може працювати у вашій установці, але не на чужій.
Фейермурмель

Apache FileUtils . readLines (файл) та copyURLToFile (URL, tempFile).
Яш

2
Я не думаю, що це спрацює, якщо ресурс знайдеться всередині баночки. Тоді це не буде файл.
Віль Ойкарінен

16

Я часто сам мав цю проблему. Щоб уникнути залежностей від невеликих проектів, я часто пишу невелику функцію утиліти, коли мені не потрібні загальнодоступні повідомлення тощо. Ось код для завантаження вмісту файлу в буфер рядків:

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

Визначення кодування є важливим у цьому випадку, оскільки ви, можливо, відредагували свій файл в UTF-8, а потім помістили його в банку, а комп'ютер, який відкриває файл, може мати CP-1251 як кодування його рідного файлу (наприклад) ; тому в цьому випадку ви ніколи не знаєте цільове кодування, тому явна інформація про кодування має вирішальне значення. Також цикл для читання файлу char за допомогою char виглядає неефективним, але він використовується на BufferedReader, і так насправді досить швидко.


15

Ви можете використовувати таку форму коду Java

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

Які заяви про імпорт потрібні для класів "Файли" та "Шляхи"?
Стів Шерер

1
обидва є частиною пакету java.nio.file, доступного у JDK 7+
Raghu K Nair

Не працює в файлі jar.
Displee

4

Якщо ви хочете отримати свій String з такого ресурсу проекту, як файл testcase / foo.json у src / main / ресурси вашого проекту, зробіть це:

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

Зауважте, що метод getClassLoader () відсутній у деяких інших прикладах.


2

Використовуйте файлові утиліти Apache Commons. Він має метод readFileToString


Файл працює лише для ресурсів classpath, які є, ну, файли. Не в тому випадку, якщо вони є елементами у .jar-файлі або частиною жирової банки, однією з інших реалізацій завантажувачів.
toolforger

2

Я використовую наступне для читання файлів ресурсів із 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() : "";
        }
    }
}

Ніяких сторонніх залежностей не потрібно.


1

Завдяки набору статичного імпорту, рішення Guava може бути дуже компактним однолінійним:

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

Необхідний наступний імпорт:

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

Принаймні, як Apache commons-io 2.5, метод IOUtils.toString () підтримує аргумент URI і повертає вміст файлів, розташованих всередині банки на classpath:

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

1

Мені подобається відповідь akosicki за допомогою трюку дурного сканера. Це найпростіший, що я бачу без зовнішніх залежностей, який працює в Java 8 (і насправді весь шлях назад до Java 5). Ось ще простіша відповідь, якщо ви можете використовувати Java 9 або новішу версію (оскільки вона InputStream.readAllBytes()була додана в Java 9):

String text = new String(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());

0

Guava також має, Files.readLines()якщо ви хочете повернути значення як List<String>рядкове за рядком:

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

Будь ласка, зверніться сюди, щоб порівняти 3 способи ( BufferedReaderпроти Гуави Filesпроти Гуави Resources), щоб отримати Stringз текстового файлу.


Що таке клас Charsets? не рідний
e-info128

@ e-info128 Charsetsтакож є в Гуаві . Дивіться це: google.github.io/guava/releases/23.0/api/docs
philipjkim

0

Ось мій підхід спрацював чудово

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
Звідки беруться IOUtils? На джерело слід посилатись чітко.
ehecatl

0

Тут я написав методи readResource () , щоб можна було це зробити одним простим викликом. Це залежить від бібліотеки Guava, але мені подобаються лише методи JDK, запропоновані в інших відповідях, і я думаю, що я зміню це таким чином.


0

Якщо ви включите Guava, ви можете використовувати:

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

(Інші рішення згадували інший метод для Guava, але вони застаріли)


0

Для мене працюють такі тріски:

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

Ось рішення за допомогою 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

Я зробив статичний метод NO-залежності таким:

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

Мені подобаються утиліти Apache для цього типу матеріалів і широко використовую цей точний приклад використання (читання файлів з classpath) під час тестування, особливо для читання файлів JSON /src/test/resourcesв рамках тестування одиниці / інтеграції. напр

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

}

З метою тестування може бути приємно зловити IOExceptionта кинути RuntimeException- ваш тестовий клас може виглядати, наприклад,

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

Будь ласка, додайте до своєї відповіді коротке пояснення.
Микола Михайлов
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.