【问题标题】:changing big file with memory limit 20mb更改内存限制为 20mb 的大文件
【发布时间】:2019-01-30 05:32:00
【问题描述】:

我想从大 txt 文件中删除重复数字,其中第一行是行中排序数字的数量,但有内存限制 - 20 mb。我阅读了How to Read a Large File 的文章并尝试使用BufferedWriter,但该过程需要超过20 mb。 请帮帮我。

    import java.io.*;
import java.util.Scanner;

public class DeleteRepeatingNumbers {

    public static void main(String[] args) throws IOException {
        try (Scanner sc = new Scanner(
                new FileInputStream("input.txt"), "UTF-8");
             Writer writer = new BufferedWriter(
                     new OutputStreamWriter(
                             new FileOutputStream("output.txt"), "utf-8"))) {
            int n = sc.nextInt();
            int prevInt = 0;

            if (n != 0) {
                prevInt = sc.nextInt();
                writer.write(String.valueOf(prevInt));
            }
            for (int i = 0; i < n - 1; i++) {
                int next = sc.nextInt();
                if (next != prevInt) {
                    writer.write(System.getProperty("line.separator"));
                    writer.write(String.valueOf(next));
                    prevInt = next;
                }
            }
        }
    }
}

例子:

21
2
4
8
8
8
9
11
11
11
11
11
11
13
14
15
16
222
222
222
222
222

【问题讨论】:

  • 整个 jvm 需要 20mb 吗?这将是困难的。 jvm怎么启动,出现哪个错误?
  • 它只用于缓冲区
  • 你在哪里看到超过 20mb 被使用了?我不明白你的问题
  • 你在哪里看到超过 20mb 被使用了?我不明白你的问题

标签: java memory io nio large-files


【解决方案1】:

我不确定 20mb 是否足以启动 JVM,但从程序的角度来看,我们可以使用这些方法来减少内存占用。

这个问题可以有两种解决方案:

  1. 您需要知道数字,以便检查是否重复。 逐行读取文件,并将数字压入HashMap。如果 hashmap.containsKey 返回一个 true,你可以假设它被复制了。 这样做的好处是一次迭代足以解决用例,但如果数字非常独特,则可能会突破 20MB 内存限制。
  2. 您可以从文件中读取第一个数字,然后逐行再次遍历文件中的所有行并删除重复的出现。然后你从文件中读取下一条记录并再次迭代。 好一点:20mb 内存限制不是问题,不利的一面是迭代次数会增加,这将等于唯一编号的数量。

希望这会有所帮助。

【讨论】:

  • 非常感谢。我用示例更新了问题。如果我知道排序数字的数量,是否可以读取前 200 行,排序和写入,清理内存 System.gc(),然后读取接下来的 200 行,排序和写入等。但是如何实现它。
【解决方案2】:

如果你能告诉我你的资源,我可以更有效地帮助你。不过我觉得你可以先试试这个。

public class DeleteRepeatingNumbers {

	public static void deleteRepeatingNumber() {
		StringBuilder sb = new StringBuilder();
		try (Scanner sc = new Scanner(new FileInputStream("resources\\RepeatingNumberTest.txt"), "UTF-8")) {
			Set<Integer> dontRepeatedNumbers = new HashSet<>();
			while (sc.hasNext()) {
				dontRepeatedNumbers.add(sc.nextInt());
			}
			dontRepeatedNumbers.stream().forEach((Integer number) -> {
				sb.append(String.valueOf(number));
				sb.append(System.getProperty("line.separator"));
			});
		} catch (IOException e){
			System.out.println(e);
		}
		
		try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("resources\\RepeatingNumberTest_Output.txt"), "utf-8"))) {
			writer.write(sb.toString());
		} catch (IOException e){
			System.out.println(e);
		}
	}
}

我希望这会有用。

【讨论】:

  • 感谢您的宝贵时间。我添加了第一行删除 if(sc.hasNext()) sc.nextInt() 而没有在第一行添加分隔符: Iterator iter = dontRepeatedNumbers.iterator(); if(iter.hasNext()) { sb.append(iter.next()); iter.remove(); }
  • 但这也需要超过 20 mb。
  • 另外我忘了写第一行是排序数字的数量。例如:
  • 21 2 4 8 8 8 9 11 11 11 11 11 11 13 14 15 16 222 222 222 222 222
  • 在我看来,您可以通过分成两部分来减小缓冲区大小。首先,您阅读文件,执行您的逻辑并将结果放入 Strung Builder。然后将 String Builder 中的所有数据写入输出文件。我认为它会减少很多缓冲区大小。但是关于限制(20 Mb),这取决于您的输入。
猜你喜欢
  • 1970-01-01
  • 2018-12-12
  • 1970-01-01
  • 2019-02-08
  • 2012-03-12
  • 1970-01-01
  • 2012-02-17
  • 1970-01-01
  • 2017-05-19
相关资源
最近更新 更多