Обратный массивный текстовый файл в Java - PullRequest
10 голосов
/ 28 апреля 2010

Каков наилучший подход для обращения большого текстового файла, который асинхронно загружается в сервлет, который обращает этот файл в масштабируемом и эффективном виде?

  • текстовый файл может быть массивным (гигабайт)
  • может предполагать, что несколько серверов / кластерная среда делают это распределенным образом.
  • библиотекам с открытым исходным кодом рекомендуется учитывать

Я думал об использовании Java NIO для обработки файла как массива на диске (чтобы мне не приходилось рассматривать файл как строковый буфер в памяти). Кроме того, я думаю об использовании MapReduce для разбиения файла и его обработки на отдельных компьютерах.

Ответы [ 4 ]

4 голосов
/ 28 апреля 2010

Если он загружен вам, и вы можете получить длину в начале, вы можете просто создать пустой полноразмерный файл и записать в него, начиная со спины и двигаясь вперед, используя искать

Возможно, вы захотите определить размер блока (например, 1 КБ?) И полностью изменить его в памяти, прежде чем записывать его в файл.

2 голосов
/ 28 апреля 2010

Это довольно сложная задача. Если вы можете убедиться, что заголовки HTTP Content-Length и Content-Type присутствуют в запросе на загрузку (или в составном теле, когда это запрос multipart/form-data), тогда он было бы легко с помощью RandomAccessFile. Длина содержимого является обязательной, чтобы RandomAccessFile знал, как долго будет длиться файл, и запишите символ в нужной позиции. Кодировка символов (которая обычно присутствует в качестве атрибута заголовка типа контента) обязательна, чтобы знать, сколько байтов будет учитывать символ (поскольку RandomAccessFile основано на байтах и, например, кодировка UTF-8 является переменной-байтовой длина).

Вот пример запуска (оставляя в стороне очевидную обработку исключений):

package com.stackoverflow.q2725897;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;

public class Test {

    public static void main(String... args) throws Exception {

        // Stub input. You need to gather it yourself from your sources.
        File file = new File("/file.txt");
        long length = file.length(); // Get it from HTTP request header using file upload API in question (Commons FileUpload?).
        String encoding = "UTF-8"; // Get it from HTTP request header using file upload API in question (Commons FileUpload?).
        InputStream content = new FileInputStream(file); // Get it from HTTP request body using file upload API in question (Commons FileUpload?).

        // Now the real job.
        Reader input = new InputStreamReader(content, encoding);
        RandomAccessFile output = new RandomAccessFile(new File("/filereversed.txt"), "rwd");
        CharsetEncoder encoder = Charset.forName(encoding).newEncoder();

        for (int data; (data = input.read()) != -1;) {
            ByteBuffer bytes = encoder.encode(CharBuffer.wrap(new char[] { (char) data }));
            length -= bytes.limit();
            output.seek(length);
            output.write(bytes.array());
        }

        // Should actually be done in finally.
        input.close();
        output.close();
    }

}

Если эти заголовки отсутствуют (особенно важно Content-length), вам действительно нужно сначала сохранить его на диске до конца потока, а затем перечитать и перевернуть его таким же образом с помощью RandomAccessFile.

Обновление : на самом деле это будет сложнее, чем кажется. Всегда ли гарантируется одинаковая кодировка символов ввода? Если так, что это будет? Кроме того, что бы вы хотели сделать, например, суррогатные символы и символы новой строки? Приведенный выше пример не учитывает это правильно. Но это, по крайней мере, дает основную идею.

0 голосов
/ 04 марта 2016

В файле парадигмы Map-Reduce можно разбить на небольшие разделы, и каждый раздел можно сохранить в объекте коллекции, который можно легко перевернуть, а в фазе сокращения каждый обратный вывод можно снова объединить вместе. например, в коде spark-scala должно быть что-то вроде этого.

val content = sc.textFile(textfile,numpartitioner)
val op = content.mapPartitions(partitioner, true)

def partitioner(content: Iterator[String]): Iterator[String] = {

    val reverse = content.map { x => x.reverse }
    val reverseContent = reverse.toList.reverse
    reverseContent.toIterator 
 }
0 голосов
/ 28 апреля 2010

Сохраняйте его в управляемых чанках на диск по мере их поступления, а затем при необходимости читайте чанки в обратном направлении и представляйте содержимое в обратном порядке.

Был бы разумным размер 1 Мб, учитывая объем, доступный для обычного Java-приложения в наши дни?

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