Java 基于列之一将输入文件划分为多个文件

Java 基于列之一将输入文件划分为多个文件,java,string,file,Java,String,File,我有一个分号分隔的输入文件,其中第一列是一个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;f

我有一个分号分隔的输入文件,其中第一列是一个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

输出文件应包含第1行的项目计数和剩余行的数据

所以有5001行,所以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行数据

考虑到大于100000行的非常大的输入文件,实现这一点的最有效方法是什么

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

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();
    }

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


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

我猜您没有固定到三个文件,因此我建议您创建一个以三个字符的代码作为键、以编写器作为值的编写器映射

对于您读取的每一行,您可以选择或创建所需的读取器,并将这些行写入。此外,还需要第二个映射来维护所有文件的行计数值

读取源文件后,将刷新并关闭所有写入程序,然后逐个读取文件。这次只需在文件前面添加行数。据我所知,除了重写整个文件外,没有其他方法,因为如果不缓冲和重写整个文件,就不可能直接在文件开头添加任何内容。我建议你用一个临时文件来处理这个问题

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

  • 每行
  • 提取区块名称,例如001
  • 查找名为“001 tmp.txt”的文件
  • 如果存在,请读取第一行-它将给出行数,然后递增该值并使用参数为0的函数写入同一文件,然后使用重写该字符串。也许这里必须应用一些字符串长度计算,例如为10个空格留一个占位符
  • 如果一个不存在,那么创建一个,并将1作为第一行,用10个空格填充
  • 将当前行追加到文件
  • 关闭当前文件
  • 继续源文件的下一行

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

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


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

      首先,创建
      HashMap
      以收集文件中的所有数据。 第二,使用
      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]);
      
      ArrayList list=map.get(令牌[0]);
      if(list==null){
      put(标记[0],list=newarraylist();
      }
      列表。添加(令牌[1]);
      

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

      您是否考虑过让一个读卡器和三个写卡器,一行读取并将其写入相应的写卡器?KIS@AnthonyGrist,10万或10万是10万。@JohnB:您假设只有3个写卡器。但是问题“有多少作者”的答案只有在我阅读了整个文件后才会得到回答,该文件将为我提供一组令牌[0]也就是说,我必须生成的输出文件的数量。似乎是一个足够小的文件,可以读取整个数据并根据标记将其拆分为多个列表。这是正确的,还是您一次只需要在内存中保留一小部分文件?001.txt文件能否包含“000005”而不是第一个(计数)的“5”行?要知道所需内存的总量,数据行的典型长度是多少?这假设可以保持打开的文件句柄数。此alg可能会导致1001个并发打开的文件。如果您也达到此限制,则每次需要添加时,您都可以选择打开和关闭文件一行。那么您只有两个活动的文件句柄。在这种情况下,您只需要维护一个已访问文件的列表,以便在以后写入行号。仅供参考,Guava有一个多地图集合,它实现了MAPI。可以在一个打开的编写器中进行查找,并按照@shara的建议维护一个打开的文件集合dendu?不,seek不适用于编写器AFAIK。请查看详细信息。如果使用机制2,您是否解决文件开头的行数问题?您读取每行并检查第一列,然后使用FileWriter(名称,追加)打开相应的文件