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

215

Есть ли какая-либо утилита, которая помогает читать текстовый файл из ресурса в строку. Я предполагаю, что это популярное требование, но я не смог найти никакой полезности после Google.

Лок Фан
источник
1
уточните, что вы подразумеваете под «текстовым файлом ресурса» против «текстового файла в ресурсе» - непросто понять, чего вы пытаетесь достичь.
Мат
Это просто текстовый файл в classpath, например "classpath *: mytext / text.txt"
Loc Phan

Ответы:

301

Да, Гуава предоставляет это в 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изменил реализацию. Для гуавы 23 реализация нравится следующее. ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
xxy
172

Вы можете использовать старый трюк Oneliner для Stupid Scanner, чтобы сделать это без каких-либо дополнительных зависимостей, таких как guava:

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

Ребята, не используйте сторонние материалы, если вам это действительно не нужно. В JDK уже много функциональности.

akosicki
источник
41
Уклонение от третьей стороны - разумный принцип. К сожалению, основная библиотека, кажется, имеет аллергию на моделирование реальных случаев использования. Посмотрите на Файлы Java 7 и скажите мне, почему чтение всего из ресурса classpath не было там включено? Или, по крайней мере, используя стандартизированную «файловую систему».
Дилум Ранатунга
3
Нужно ли - или нет - необходимо также закрыть поток? Гуава внутренне закрывает поток.
virgo47
Работал красиво для меня тоже! Я также согласен со сторонней вещью: во многих ответах ответом по умолчанию всегда кажется использование какой-либо сторонней библиотеки - будь то от Apache или кого-то еще.
Терье Дал
1
перейти CartApplication.class.getResourceAsStreamна CartApplication.class.getClassLoader().getResourceAsStreamзагрузку ресурсов в текущем jar .. как srm / test / resources
Крис Дамур
5
Хотя я использовал это, я совершенно не согласен избегать сторонних пакетов. Тот факт, что в Java единственный способ легко прочитать файл в строку с помощью трюка со сканером, довольно печален. Альтернатива использованию сторонних библиотек заключается в том, что каждый будет создавать свои собственные оболочки. Guava для ввода-вывода выигрывает, если у вас много потребностей для такого рода операций. Я согласен с тем, что вам не следует импортировать сторонние пакеты, если в вашем коде есть только одно место, где вы хотите это сделать. Это было бы излишним ИМО.
Кенни Кейсон
90

Для Java 7:

new String(Files.readAllBytes(Paths.get(getClass().getResource("foo.txt").toURI())));
Ковальский Дмитрий
источник
3
Объясните, пожалуйста, почему это работает, почему это лучше, чем другие альтернативы, и какие соображения производительности / кодирования необходимы.
нанофарад
5
Это nio 2 в Java 1.7. Это родной плод Явы. Для кодирования используйте новую String (bytes, 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);

Избегайте ненужных зависимостей

Всегда предпочитайте не зависеть от больших, толстых библиотек. Если вы уже не используете Guava или Apache Commons IO для других задач, добавление этих библиотек в ваш проект просто для возможности чтения из файла кажется слишком сложным.

«Простой» метод? Ты, должно быть, Прикалываешься

Я понимаю, что чистая 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переменная isявляется nullили нет.
scrutari
2
Ницца. Я использовал это. Вы можете рассмотреть закрытие потоков / читателей тоже.
димплекс
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
Это устарело в Гуаве 24.1
Андрей
47

yegor256 нашел хорошее решение, используя Apache Commons IO :

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);
Abdull
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
Почему нужно указывать кодировку, я не понимаю. Если я читаю файл, я просто хочу узнать, что в нем, он должен выяснить, в какой кодировке он работает, как в моем редакторе. Когда я открываю в Notepad или ++, я не говорю ему, какую кодировку он должен использовать. Я использую этот метод, а затем writeStringToFile ... но содержание отличается. Я получаю странные токены в клонированном файле ... я не понимаю, почему мне нужно указать кодировку.
ммм
11
@Hamidan, выбор правильной кодировки - очень сложный алгоритм. Это часто реализуется в текстовом редакторе, но иногда они не могут определить правильную кодировку. Я не ожидал бы, что API чтения файлов внедрит такой сложный алгоритм для чтения моего файла.
Винсент Роберт
1
@SecretService Кроме того, эти алгоритмы используют информацию, такую ​​как язык операционной системы, языковой стандарт и другие региональные настройки, что означает, что чтение файла без указания кодировки может работать в ваших настройках, но не в чьих-либо других.
Feuermurmel
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 / resources вашего проекта, сделайте это:

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

Обратите внимание, что метод getClassLoader () отсутствует в некоторых других примерах.

Witbrock
источник
2

Используйте Apache FileUtils. У него есть метод 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() : "";
        }
    }
}

Никаких сторонних зависимостей не требуется.

BullyWiiPlaza
источник
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;
    }
}
sklimkovitch
источник
1

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

IOUtils.toString(SomeClass.class.getResource(...).toURI(), ...)
user1050755
источник
1

Мне нравится ответ Акосицки с помощью глупого трюка со сканером. Это самое простое из всех, что я вижу, без внешних зависимостей, которое работает в 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из текстового файла.

philipjkim
источник
Что такое класс 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
    }
}
Java_Fire_Within
источник
2
Откуда берутся IOUtils? На источник следует ссылаться четко.
ehecatl
0

Я написал здесь методы readResource () , чтобы сделать это одним простым вызовом. Это зависит от библиотеки Guava, но мне нравятся методы только для JDK, предложенные в других ответах, и я думаю, что я изменю их таким образом.

zakmck
источник
0

Если вы включите Guava, то вы можете использовать:

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

(Другие решения упоминали другой метод для Guava, но они устарели)

jolumg
источник
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");
Vicky
источник
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 commons для такого типа вещей, и я очень часто использую этот точный вариант использования (чтение файлов из 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 ...
    }
bobmarksie
источник
-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ừ
источник
Пожалуйста, добавьте краткое объяснение к вашему ответу.
Николай Михайлов