我需要阅读巨大平面文件,而不将整个文件保留在内存中。 它是具有多个段的平面文件,每个记录以由' H'标识的标题记录开头。在开始之后是多行,然后是Header记录,这种模式重复 例如,
HXYZ CORP 12/12/2016
R1 234 qweewwqewewq wqewe
R1 234 qweewwqewewq wqewe
R1 234 qweewwqewewq wqewe
R2 344 dfgdfgdf gfd df g
HABC LTD 12/12/2016
R1 234 qweewwqewewq wqewe
R2 344 dfgdfgdf gfd df g
HDRE CORP 12/12/2016
R1 234 qweewwqewewq wqewe
R2 344 dfgdfgdf gfd df g
R2 344 dfgdfgdf gfd df g
我想一次读取一个记录集,例如
HDRE CORP 12/12/2016
R1 234 qweewwqewewq wqewe
R2 344 dfgdfgdf gfd df g
R2 344 dfgdfgdf gfd df g
如何实现这一点请记住,我不想将整个文件保存在内存中 我可以用于此目的的标准库吗? 我尝试过使用一些实现而没有太大的成功,我使用了Apache的Line Iterator,但是它逐行读取。
非常感谢任何帮助或建议。
答案 0 :(得分:2)
在Java 8中使用nio Files.lines()
方法,Stream.map()
和scala> val res: C = cc + "17"
<console>:18: error: type mismatch;
found : <refinement>.type (with underlying type Of[Serializable,CC])
required: ?{def +(x$1: ? >: String("17")): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method XC of type (v: Of[Serializable,CC])XC
and method untagit of type (x: Of[Serializable,CC])Of[C,CC]
are possible conversion functions from <refinement>.type to ?{def +(x$1: ? >: String("17")): ?}
val res: C = cc + "17"
^
<console>:18: error: value + is not a member of Of[Serializable,CC]
val res: C = cc + "17"
^
。
我更新了代码,以便能够逐行写入新文件,将当前日期添加到标题中。
PrintWriter
答案 1 :(得分:1)
数据按行存储,在您读取下一条记录的标题行之前,您不知道记录已结束。你需要逐行阅读。这样的事情应该有效:
BufferedReader br = new BufferedReader( new FileReader( file ) );
Vector<String> record = new Vector<>();
String line;
// loop is explicitly broken when file ends
for ( ;; )
{
line = br.readline();
// no more lines - process what's in record and break the loop
if ( null == line )
{
ProcessRecord( record );
break;
}
// new header line, process what's in record and clear it
// for the new record
if ( line.startsWith( "H" ) )
{
ProcessRecord( record );
record.clear()
}
// add the current line to the current record
record.add( line );
}
答案 2 :(得分:1)
您应该使用逐行阅读(例如您使用的Apache或Java8 Files.lines()
)来实现目标。
使用两个循环:外部进行处理,直到达到EOF。用于一次读取记录集的内循环。处理完整条记录后 - 您可以将已读取的行丢弃到垃圾收集器。然后(外循环)处理下一条记录。
如果使用Lambdas和Java 8 F iles.lines(...)
- 您可能想要分组(收集)与同一记录相关的行。然后处理这些分组的对象。
答案 3 :(得分:0)
我会选择内置的BufferedReader
并逐行阅读。
我不知道你对固定宽度文件的意思,因为在你的评论中你提到了
R1,R2,R3都是可选的,可重复的,宽度各不相同。
在任何情况下,根据您的描述,您的格式都是如此
1. Read the first character to get the TOKEN
2. Check if TOKEN equals "H" or "R"
3. Split the line and parse it based on what type of TOKEN it is.
如果R1
,R2
和R3
是单独的令牌,那么您需要检查它是否为R条目,然后检查下一个字符是否为需要的。
对于步骤3,如果行中的每个字段用空格分隔,您可以考虑拆分空格。或者,如果每条记录都有固定宽度,则可以使用substring
来提取每个段。
我不确定你的意思
我的用例需要一次读取整个记录集。
答案 4 :(得分:0)
根据@ firephil的建议,我已经使用Java 8 Stream API来满足此要求。我使用了StringBuilder
形式的缓冲区来存储Header和另一个Header记录之间的行。最后从Stream中获取一个迭代器,一次从文件中获取一个完整记录(H + R1 + R2 + R3)。获取最后一条记录时出现问题,我处理最后一条记录的方式正在丢失,所以我不得不将假记录连接到原始流。
这将是这个时间,但我相信会有更好的方法来处理。
public static StringBuilder sbTemp;
public static Iterator<String> process(String in) throws IOException
{
Iterator<String> recordIterator = null;
sbTemp = new StringBuilder();
List<String> fakeRecordList = new ArrayList<String>();
fakeRecordList.add("H Fake Line");
Stream<String> fakeRecordStream = fakeRecordList.stream(); //For getting last Record Set
Stream<String> stream = Files.lines(Paths.get(in)).sequential();
Stream<String> finalStream = Stream.concat(stream,fakeRecordStream);
// PrintWriter output = new PrintWriter(out, "UTF-8"))
{
recordIterator = finalStream.map(x -> {
if(x.startsWith("H")) {
String s = sbTemp.toString();
//System.out.println("Header: "+x);
sbTemp = new StringBuilder();
sbTemp.append(x);
return s;
}
else {
sbTemp.append("\n").append(x);
return "";
}
}
).filter(line -> (line.startsWith("H")) ).iterator();
System.out.println(recordIterator.next());
}
return recordIterator;
}
答案 5 :(得分:-1)