用Java反转大量文本文件

时间:2010-04-27 23:35:04

标签: java file file-io

将以异步方式上传到以可扩展且高效的方式反转此文件的servlet的大型文本文件的最佳方法是什么?

  • 文本文件可能很大(千兆字节)
  • 可以假定多个服务器/集群环境以分布式方式执行此操作。
  • 鼓励开源图书馆考虑

我在考虑使用Java NIO将文件视为磁盘上的数组(因此我不必将该文件视为内存中的字符串缓冲区)。另外,我正在考虑使用MapReduce来分解文件并在不同的机器上处理它。

4 个答案:

答案 0 :(得分:4)

如果它被上传到你并且你可以在开头获得长度,你可以在前面创建一个空的完整大小的文件并从后面开始写入它并使用{{3前进到前面}}

你可能想要定义一个块大小(比如1K?)并在将其写入文件之前在内存中反转那么多。

答案 1 :(得分:2)

这是一项非常艰巨的任务。如果您可以确保上传请求中存在HTTP Content-LengthContent-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

更新:它实际上比它看起来更难。输入的字符编码是否始终保证相同?如果是这样,它会是什么?另外,您想要做什么,例如代理字符和换行符?上面的示例没有正确考虑到这一点。但它至少给出了基本的想法。

答案 2 :(得分:0)

在进入磁盘时将其保存在可管理的块中,然后在需要时向后读取块并向后显示内容。

鉴于目前正常的Java应用程序可用的数量,1 Mb是否合理?

答案 3 :(得分:0)

在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 
 }