我有一个文本文件。它的设计如下:
#1{1,12,345,867} #2{123, 3243534, 2132131231} #3{234, 35345} #4{}
... (在每个条目的末尾代表“\ n”)
这是一个例子。实际上我的字符串#number {number,number,...,number}可能真的很长......
以下是使用此文件的类的构造函数的模板:
public Submatrix(String matrixFilePath, int startPos, int endPos) throws FileNotFoundException{
}
如您所见,子矩阵由startPos和endPos矩阵的字符串数决定。
我的问题是:“我如何计算字符串以达到合适的字符串?” 我的文件可以包含数十亿个字符串。我应该使用LineNumberReader-> readLine()数十亿次?????
答案 0 :(得分:5)
我很想顺序读取每一行,直到我到达所需的行。但是,由于这些行在文件中编号并用换行符分隔,因此您可以将该文件视为随机访问并采用各种策略。例如,您可以使用二进制搜索的变体来快速查找起始行。您可以估算前N行的平均线长,然后尝试对起始位置进行更准确的猜测,依此类推。
答案 1 :(得分:2)
我认为答案是肯定的,你使用readLine
阅读了数十亿行,除非你认为使用其中任何一行都是值得的
您使用单独的索引,无论是在文件的开头还是在一个非常可预测的单独文件中,就像
0000001 000000001024
0000002 000000001064
0000003 000000002010
也就是说,该行的行号和起始位置以字节为单位,以严格定义的方式使得可以通过以下方式确定索引的位置:
我想阅读第3行,所以通过转到位置(3-1)* 20找到第3行的位置,
并阅读0000003 000000002010
,解析并知道第3行位于字节位置2010,寻找该位置并开始阅读。
如果它位于主数据文件中,则计算或维护索引可能并不容易,因为这意味着您在实际编写文件之前预先计算了位置。我想我会使用一个单独的索引文件,并在写入期间计算索引,或者有一个单独的实用程序来创建给定数据文件的索引文件。
编辑添加了示例代码以演示我的提案
我制作了一个小的Python脚本,它读取数据文件并创建索引文件。索引文件包含数据文件中一行的位置,可以轻松搜索。
此示例脚本的索引格式为06d,这对于999.999行数据文件来说已经足够了,因为它可能需要进行调整(不要忘记INDEX_LENGTH)。它创建一个索引文件,并使用该索引文件从数据文件中读取给定的行(出于演示目的;您将使用java作为该部分:)
脚本调用如:
python create_index.py data.txt data.idx 3
我的示例数据文件是:
#1{1,12,345,867}
#2{123, 3243534, 2132131231}
#3{234, 35345}
#4{}
并且脚本本身是:
import sys
# Usage: python this_script.py datafile indexfile lineno
# indexfile will be overwritten
# lineno is the data line which will be printed using the
# index file, as a demonstration
datafilename= sys.argv[1]
indexfilename = sys.argv[2]
lineno = int(sys.argv[3])
# max 999999 lines in this format
format = "%06d\n"
INDEX_LENGTH = 6+1 # +1 for newline
def create_indexfile():
indexfile = open(indexfilename, "wB")
# Print index of first line
indexfile.write(format % 0)
f = open(datafilename, "rB")
line = f.readline()
while len(line) > 0:
indexfile.write( format % f.tell() )
line = f.readline()
f.close()
indexfile.close()
# Retrieve the data of 1 line in the data file
# using the index file
def get_line():
linepos = INDEX_LENGTH * (lineno - 1)
indexfile = open(indexfilename, "rB")
indexfile.seek(linepos)
datapos = int(indexfile.readline())
indexfile.close()
datafile = open(datafilename, "rB")
datafile.seek(datapos)
print datafile.readline()
datafile.close()
if __name__ == '__main__':
create_indexfile()
get_line()
在更改数据文件后,需要重建索引文件。您可以通过将读取的数据(#3 {...})中的行号与输入行号进行比较来验证您是否读取了正确的数据,因此它非常安全。
无论您是否选择使用它,我认为这个例子非常简单明了。
答案 2 :(得分:1)
@extraneon
这是我想用来表示字符串#number {number,number,...}
的类package logic;
public class DenominatedBinaryRow{
private int sn;
private BinaryRow row;
public DenominatedBinaryRow(int sn, BinaryRow row){
this.sn = sn;
this.row = row;
}
public DenominatedBinaryRow plus(int sn, DenominatedBinaryRow addend){
return new DenominatedBinaryRow(sn, this.row.plus(addend.row));
}
public int getSn(){
return this.sn;
}
public BinaryRow getRow(){
return this.row;
}
public boolean equals(Object obj){
DenominatedBinaryRow res = (DenominatedBinaryRow) obj;
if (this.getSn() == res.getSn() && this.getRow().equals(res.getRow())){
return true;
}
return false;
}
}
将序列化它可能是有效的,而不是将BinaryRow(它的实现如下)转换为字符串? 如果我将它的许多实例序列化为文件,我将如何反序列化必要的字符串(必要的实例)? (希望,我理解你的问题)
package logic;
import java.util.*;
public class BinaryRow {
private List<Integer> row;
public BinaryRow(){
this.row = new ArrayList<Integer>();
}
public List<Integer> getRow(){
return this.row;
}
public void add(Integer arg){
this.getRow().add(arg);
}
public Integer get(int index){
return this.getRow().get(index);
}
public int size(){
return this.getRow().size();
}
public BinaryRow plus(BinaryRow addend){
BinaryRow result = new BinaryRow();
//suppose, rows are already sorted (ascending order)
int i = this.size();
int j = addend.size();
while (i > 0 && j > 0)
if (this.get(this.size() - i) < addend.get(addend.size() - j)){
result.add(this.get(this.size() - i));
i--;
}
else if (this.get(this.size() - i) > addend.get(addend.size() - j)){
result.add(addend.get(addend.size() - j));
j--;
}
else{
result.add(this.get(this.size() - i));
i--;
j--;
}
if (i > 0){
for (int k = this.size() - i; k < this.size(); k++)
result.add(this.get(k));
}
if (j > 0){
for (int k = addend.size() - j; k < addend.size(); k++)
result.add(addend.get(k));
}
return result;
}
public boolean equals(Object obj){
BinaryRow binRow = (BinaryRow) obj;
if (this.size() == binRow.size()){
for (int i = 0; i < this.size(); i++){
if (this.getRow().get(i) != binRow.getRow().get(i)) return false;
}
return true;
}
return false;
}
public long convertToDec(){
long result = 0;
for (Integer next : this.getRow()) {
result += Math.pow(2, next);
}
return result;
}
}
答案 3 :(得分:-1)
我很害怕你必须到第x行,你必须调用readLine()x次。 这意味着在您到达此行之前读取所有数据。每个字符都可以是一个行结束,所以如果不读取该行之前的每个字符,就无法进入第x行。