Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中读取、比较和合并多个文件_Java_Memory_Io_Cpu - Fatal编程技术网

在Java中读取、比较和合并多个文件

在Java中读取、比较和合并多个文件,java,memory,io,cpu,Java,Memory,Io,Cpu,鉴于存在一些文件Customer-1.txt、Customer-2.txt和Customer-3.txt,这些文件具有以下内容: Customer-1.txt 1|1|MARY|SMITH 2|1|PATRICIA|JOHNSON 4|2|BARBARA|JONES Customer-2.txt 1|1|MARY|SMITH 2|1|PATRICIA|JOHNSON 3|1|LINDA|WILLIAMS 4|2|BARBARA|JONES Customer-3.txt

鉴于存在一些文件Customer-1.txt、Customer-2.txt和Customer-3.txt,这些文件具有以下内容:

Customer-1.txt

1|1|MARY|SMITH  
2|1|PATRICIA|JOHNSON  
4|2|BARBARA|JONES
Customer-2.txt

1|1|MARY|SMITH  
2|1|PATRICIA|JOHNSON   
3|1|LINDA|WILLIAMS  
4|2|BARBARA|JONES
Customer-3.txt

2|1|PATRICIA|JOHNSON   
3|1|LINDA|WILLIAMS  
5|2|ALEXANDER|ANDERSON
这些文件有很多重复的数据,但每个文件都可能包含一些唯一的数据

考虑到实际的文件是经过排序的,很大(每个文件有几GB),而且有很多文件

那么什么是:
a) 内存最便宜
b) cpu最便宜的
c) 最快的
在Java中,从这三个文件中创建一个文件,该文件将包含每个文件的所有唯一数据,并按如下方式排序和连接:

Customer-final.txt

1|1|MARY|SMITH  
2|1|PATRICIA|JOHNSON
3|1|LINDA|WILLIAMS  
4|2|BARBARA|JONES
5|2|ALEXANDER|ANDERSON
我研究了以下解决方案,但我想知道是否可能使用FileInputStream和/或非spring批处理解决方案来实现

由于文件的大小和缺少实际数据库,使用内存或真实数据库连接它们的解决方案对于我的用例不可行。

这可能会有帮助:

public static void main(String[] args) {
    String files[] = {"Customer-1.txt", "Customer-2.txt", "Customer-3.txt"};
    HashMap<Integer, String> customers = new HashMap<Integer, String>();
    try {
        String line;
        for(int i = 0; i < files.length; i++) {
            BufferedReader reader = new BufferedReader(new FileReader("data/" + files[i]));
            while((line = reader.readLine()) != null) {
                Integer uuid = Integer.valueOf(line.split("|")[0]);
                customers.put(uuid, line);
            }
            reader.close();
        }

        BufferedWriter writer = new BufferedWriter(new FileWriter("data/Customer-final.txt"));
        Iterator<String> it = customers.values().iterator();
        while(it.hasNext()) writer.write(it.next() + "\n");

        writer.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
publicstaticvoidmain(字符串[]args){
字符串文件[]={“Customer-1.txt”、“Customer-2.txt”、“Customer-3.txt”};
HashMap客户=新的HashMap();
试一试{
弦线;
对于(int i=0;i

如果您有任何疑问,请询问我。

由于输入文件已经排序,因此对文件进行简单的并行迭代,合并它们的内容,是最节省内存、最节省cpu和最快的方法

这是一种多路合并联接,即不带“sort”的排序合并联接,可消除重复项,类似于SQL
DISTINCT

这是一个可以执行无限数量输入文件的版本(不管怎样,只要有打开的文件就可以)。它使用一个helper类来暂存每个输入文件的下一行,因此每行只需解析一次前导ID值

private static void merge(StringWriter out, BufferedReader ... in) throws IOException {
    CustomerReader[] customerReader = new CustomerReader[in.length];
    for (int i = 0; i < in.length; i++)
        customerReader[i] = new CustomerReader(in[i]);
    merge(out, customerReader);
}

private static void merge(StringWriter out, CustomerReader ... in) throws IOException {
    List<CustomerReader> min = new ArrayList<>(in.length);
    for (;;) {
        min.clear();
        for (CustomerReader reader : in)
            if (reader.hasData()) {
                int cmp = (min.isEmpty() ? 0 : reader.compareTo(min.get(0)));
                if (cmp < 0)
                    min.clear();
                if (cmp <= 0)
                    min.add(reader);
            }
        if (min.isEmpty())
            break; // all done
        // optional: Verify that lines that compared equal by ID are entirely equal
        out.write(min.get(0).getCustomerLine());
        out.write(System.lineSeparator());
        for (CustomerReader reader : min)
            reader.readNext();
    }
}

private static final class CustomerReader implements Comparable<CustomerReader> {
    private BufferedReader in;
    private String         customerLine;
    private int            customerId;
    CustomerReader(BufferedReader in) throws IOException {
        this.in = in;
        readNext();
    }
    void readNext() throws IOException {
        if ((this.customerLine = this.in.readLine()) == null)
            this.customerId = Integer.MAX_VALUE;
        else
            this.customerId = Integer.parseInt(this.customerLine.substring(0, this.customerLine.indexOf('|')));
    }
    boolean hasData() {
        return (this.customerLine != null);
    }
    String getCustomerLine() {
        return this.customerLine;
    }
    @Override
    public int compareTo(CustomerReader that) {
        // Order by customerId only. Inconsistent with equals()
        return Integer.compare(this.customerId, that.customerId);
    }
}
输出

String file1data = "1|1|MARY|SMITH\n" +
                   "2|1|PATRICIA|JOHNSON\n" +
                   "4|2|BARBARA|JONES\n";
String file2data = "1|1|MARY|SMITH\n" +
                   "2|1|PATRICIA|JOHNSON\n" +
                   "3|1|LINDA|WILLIAMS\n" +
                   "4|2|BARBARA|JONES\n";
String file3data = "2|1|PATRICIA|JOHNSON\n" +
                   "3|1|LINDA|WILLIAMS\n" +
                   "5|2|ALEXANDER|ANDERSON\n";
try (
    BufferedReader in1 = new BufferedReader(new StringReader(file1data));
    BufferedReader in2 = new BufferedReader(new StringReader(file2data));
    BufferedReader in3 = new BufferedReader(new StringReader(file3data));
    StringWriter out = new StringWriter();
) {
    merge(out, in1, in2, in3);
    System.out.print(out);
}
1|1|MARY|SMITH
2|1|PATRICIA|JOHNSON
3|1|LINDA|WILLIAMS
4|2|BARBARA|JONES
5|2|ALEXANDER|ANDERSON

代码纯粹通过ID值进行合并,并没有验证行的其余部分是否实际相等。如果需要,在
可选的
注释处插入代码以检查是否存在此问题。

是客户ID的第一个值,并且文件是否已按该第一个值(数字)排序,如您的示例所示?是的,您是正确的,它们已排序。谢谢你的提醒,我会把它添加到问题描述中。我不认为你不阅读文件内容就可以做到这一点。您必须读取每个文件,然后将输出写入一个单独的文件。如果我理解正确,您可以使用类似于合并排序的方法,即从每个文件中读取一行,找出最小的一行,并将其写入一些
输出流
。唯一的区别是你有2个以上的文件,你需要删除重复的文件。这将把所有(唯一的)行加载到内存中,所以它肯定不是“最便宜的内存”。使用
split()。由于您将行存储在一个
哈希集中
,因此输出将不会被排序。非常详细的答案和我要查找的内容。实际上,我的所有文件都有一个经过排序的唯一标识符(客户文件,以及所有其他文件,例如Actor文件)。我是否正确理解了,对于每个“组”文件,我必须调用文件组的合并函数?这是正确的。对于需要合并到单个输出文件的每一组类似文件,您可以调用merge,例如,一次对客户文件的合并调用,另一次对参与者文件的合并调用,等等……仅供参考:由于您的文件很大,并且可能一次写入一个,因此它们可能都存储在硬盘上的连续区域中。当读取3个文件并并行写入一个文件时,硬盘臂可能会移动很多。您可以通过将
BufferedReader
BufferedWriter
对象的缓冲区大小从默认的8k增加到更高的值,例如64k(甚至1M?),将其最小化。将其增加得太高只会浪费内存而不会提高性能。非常有用的注释。当前最大的硬件瓶颈是内存,因此我将尝试使用一些不同的缓冲区大小,看看什么最适合我的场景。谢谢安德烈亚斯的回答。