Piped Stream Проблема во Freemarker - PullRequest
       6

Piped Stream Проблема во Freemarker

1 голос
/ 02 сентября 2010

Мне нужно загрузить и обработать шаблон в freemarker. Я использую потоковый канал для считывания сгенерированного результата с помощью freemarker.

Пример кода:

PipedInputStream pi = new PipedInputStream();
PipedOutputStream po = new PipedOutputStream(pi);
Writer writer = new OutputStreamWriter(po);
configuration.getTemplate("xx").process(rootMap, writer);

Проблема в том, что иногда он замерзает внутри метода procsss freemarker. Нет ошибок, нет исключений, но он не возвращается из метода process.

Если я преобразую поток по конвейеру в поток ByteArray, он работает нормально.

Правильно ли я использую конвейерный поток?

Ответы [ 3 ]

3 голосов
/ 02 сентября 2010

Нет, потоковые потоки предназначены для передачи данных между двумя потоками.Между концами трубы есть только небольшой буфер.Если вы запишете в поточный поток вывода, ваш поток будет заблокирован, если буфер заполнен, пока другой поток не прочитает из соответствующего поточного потока ввода.Это не будет работать только с одним потоком.

Из Javadoc:

Обычно данные считываются из объекта PipedInputStream одним потоком, а данные записываются в соответствующий PipedOutputStream другим потоком.

Так что для маленьких шаблонов просто используйте StringWriter, для больших вы можете использовать FileWriter для временного файла, созданного File.createTempFile().

1 голос
/ 13 мая 2013

Вот как я заставил это работать.

final String uploadReportAsCsv = FreeMarkerTemplateUtils.processTemplateIntoString(
                        fileUploadReportTemplate, modelMap);

message.addAttachment("fileUploadProcessedReport.csv",
    new InputStreamSource() {
        //InputStreamResource from Spring is always returning an open stream,
        // thus we need to create this anonymous class.
        @Override
        public InputStream getInputStream() throws IOException {
            return new StringInputStream(uploadReportAsCsv);
        }
    }
);
1 голос
/ 02 сентября 2010

Как пишет Арне, объем буферного пространства в потоке по конвейеру довольно мал. Если вы не можете использовать буфер, который может хранить все данные (будь то в памяти или на диске), то вы можете попробовать посмотреть, можете ли вы запустить обработку шаблона в другом потоке с потоковым потоком, отправляющим результаты обратно. в основной поток, где вы делаете это.

PipedInputStream pi = new PipedInputStream();
final Writer writer = new OutputStreamWriter(new PipedOutputStream(pi));
Thread worker = new Thread(new Runnable() {
    public void run() {
        configuration.getTemplate("xx").process(rootMap, writer);
    }
});
worker.start();

Возможно, вам понадобится добавить final ключевые слова к другим переменным, чтобы это работало в вашем реальном коде. Это зависит от того, являются ли переменная configuration, аргумент getTemplate или переменная rootMap локальными переменными или переменными экземпляра (или класса).

(Я мог бы, конечно, указать подкласс Thread при указании поведения потока, но я предпочитаю создавать экземпляр интерфейса - Runnable в этом случае - для таких вещей.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...