【问题标题】:dividing input file into multiple files based on one of the column根据列之一将输入文件划分为多个文件
【发布时间】:2012-09-17 21:06:13
【问题描述】:

我有一个分号分隔的输入文件,其中第一列是 3 个字符的固定宽度代码,而其余列是一些字符串数据。

001;first_data_str;second_data_str;third_data_str;fourth_data_str
001;first_data_str;second_data_str;third_data_str;fourth_data_str
002;first_data_str;second_data_str;third_data_str;fourth_data_str
003;first_data_str;second_data_str;third_data_str;fourth_data_str
001;first_data_str;second_data_str;third_data_str;fourth_data_str
003;first_data_str;second_data_str;third_data_str;fourth_data_str
001;first_data_str;second_data_str;third_data_str;fourth_data_str
002;first_data_str;second_data_str;third_data_str;fourth_data_str
002;first_data_str;second_data_str;third_data_str;fourth_data_str
003;first_data_str;second_data_str;third_data_str;fourth_data_str
003;first_data_str;second_data_str;third_data_str;fourth_data_str
003;first_data_str;second_data_str;third_data_str;fourth_data_str
002;first_data_str;second_data_str;third_data_str;fourth_data_str
001;first_data_str;second_data_str;third_data_str;fourth_data_str

我想根据第一列的不同值将上述文件划分为多个文件。

例如在上面的例子中,第一列有三个不同的值,所以我将文件分成三个文件,即。 001.txt、002.txt、003.txt

输出文件应包含作为第一行的项目计数和作为剩余行的数据。

所以有 5 001 行,所以 001.txt 将是:

5
first_data_str;second_data_str;third_data_str;fourth_data_str
first_data_str;second_data_str;third_data_str;fourth_data_str
first_data_str;second_data_str;third_data_str;fourth_data_str
first_data_str;second_data_str;third_data_str;fourth_data_str
first_data_str;second_data_str;third_data_str;fourth_data_str

同样,002 文件的第一行为 4,然后是 4 行数据,003 文件的第一行为 5,然后是 5 行数据。

考虑到具有超过 100,000 行的非常大的输入文件,实现此目标的最有效方法是什么?

我写了下面的代码来读取文件中的行:

try{
          FileInputStream fstream = new FileInputStream(this.inputFilePath);
          DataInputStream in = new DataInputStream(fstream);
          BufferedReader br = new BufferedReader(new InputStreamReader(in));
          String strLine;

          while ((strLine = br.readLine()) != null)   {
              String[] tokens = strLine.split(";");
         }

          in.close();
    }catch(IOException e){
        e.printStackTrace();
    }

【问题讨论】:

  • 您是否考虑过让一个阅读器和三个编写器,在一行中读取并将其写入适当的编写器?亲en.wikipedia.org/wiki/KISS_principle
  • @AnthonyGrist,10 万或 10 万是 10 万。
  • @JohnB:您假设只有 3 个作者。但是只有在我阅读了整个文件后才能回答“有多少作者”的问题,这会给我一组标记[0],即我必须制作的输出文件的数量。
  • 似乎是一个足够小的文件来读取整个数据并根据标签将其拆分为多个列表。这是正确的,还是您一次只需要在内存中保留少量文件?
  • 001.txt 文件可以包含“000005”而不是“5”作为其第一(计数)行吗?数据线的典型长度是多少,以了解所需内存的总量?

标签: java string file


【解决方案1】:
  • 每一行
  • 提取块名称,例如 001
  • 查找名为“001-tmp.txt”的文件
  • 如果存在,读取第一行 - 它会给你行数,然后增加值并使用带有参数 0 的 seek 函数写入同一个文件,然后使用 writeUTF 覆盖字符串。也许这里必须应用一些字符串长度计算,例如留 10 个空格的占位符。
  • 如果不存在,则创建一个并写 1 作为第一行,用 10 个空格填充
  • 将当前行追加到文件中
  • 关闭当前文件
  • 继续下一行源文件

【讨论】:

【解决方案2】:

想到的解决方案之一是保留“地图”,并且每个文件只打开一次。但是你不能这样做,因为你有大约 1 lac 行,所以没有操作系统会允许你打开那么多文件描述符。

因此,一种方法是以附加模式打开文件并继续写入并关闭它。但是由于大量文件的打开关闭调用,该过程可能会变慢。不过你可以自己测试一下。

如果上述方法没有提供令人满意的结果,您可以尝试方法 1 和方法 2 的混合,即您在任何时候只打开 100 个打开的文件,并且只在尚未打开的新文件需要时关闭文件写给....

【讨论】:

  • 如果使用机制2,如何解决文件开头的行数?
  • 您阅读每一行并检查第一列并使用 FileWriter(name, append) 打开相应的文件并写入它。希望它回答,或者我错过了什么......
  • 您指的是保持文件打开。如何更新打开的文件的第一行?请参阅 jdevelop 的答案。
  • 如果您以附加模式打开文件,则无需自己进行这些计算。例如,如果使用以下代码片段 PrintWriter fw = new PrintWriter(new FileWriter(new File("append"), true)); fw.println("ABC"); fw.close(); fw = new PrintWriter(new FileWriter(new File("append"), true)); fw.println("PQR"); fw.close();你会得到像“ABC”+“\n”+“PQR”这样的文件
【解决方案3】:

首先,创建HashMap<String, ArrayList<String>> map 以收集文件中的所有数据。 其次,使用strLine.split(";",2) 而不是strLine.split(";")。结果将是长度为 2 的数组,第一个元素是代码,第二个元素是数据。 然后,将解码后的字符串添加到地图中:

ArrayList<String> list=map.get(tokens[0]);
if (list==null) {
   map.put(tokens[0], list=new ArrayList<String>();
}
list.add(tokens[1]);

最后,扫描map.keySet() 并为每个键创建一个名为该键的文件并将列表的大小和列表的内容写入其中。

【讨论】:

  • 在大文件的情况下 - 很容易观察到OOE
【解决方案4】:

对于每三个字符的代码,您将获得一个输入行列表。对我来说,显而易见的解决方案是使用 MapString 键(您的三个字符代码)指向包含所有行的相应 List

对于这些键中的每一个,您将创建一个具有相关名称的文件,第一行将是列表的大小,然后您将对其进行迭代以写入剩余的行。

【讨论】:

  • 仅供参考,Guava 有一个实现 Map> 的 MultiMap 集合
【解决方案5】:

我猜你并没有固定到三个文件,所以我建议你创建一个写入器的映射,用你的三个字符代码作为键,写入器作为值。

对于您阅读的每一行,您选择或创建所需的阅读器并将这些行写入。您还需要第二张地图来维护所有文件的行计数值。

读完源文件后,刷新并关闭所有写入器,然后一个接一个地读取文件。这次您只需在文件前面添加行数。据我所知,除了重写整个文件之外别无他法,因为在不缓冲和重写整个文件的情况下,不可能直接将任何内容添加到文件的开头。我建议您为此使用一个临时文件。

此答案仅适用于您的文件太大而无法完全存储在内存中的情况。如果可以存储,则有更快的解决方案。就像在写入文件之前将文件的内容完全存储在 StringBuffer 对象中一样。

【讨论】:

  • 这假设可以保持打开文件句柄的数量。此算法可能会导致 1001 个同时打开的文件。
  • 如果你也达到了这个限制,每次你需要添加一行时,你总是可以选择打开和关闭文件。那么你只有两个活动的文件句柄。在这种情况下,您只需要维护一个您已经访问过的文件列表,以便之后写入行号。
猜你喜欢
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
  • 2011-12-25
  • 2022-01-16
  • 1970-01-01
  • 2019-09-23
  • 1970-01-01
相关资源
最近更新 更多