Java 基于列之一将输入文件划分为多个文件
我有一个分号分隔的输入文件,其中第一列是一个3字符的固定宽度代码,而其余的列是一些字符串数据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
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(名称,追加)打开相应的文件