Как пометить строку в файле? - PullRequest
3 голосов
/ 27 февраля 2010

У меня есть текстовый файл. Он разработан следующим образом:

#1{1,12,345,867}
#2{123, 3243534, 2132131231} 
#3{234, 35345}
#4{}

... (в конце каждой записи стоит "\ n")

Это пример. На самом деле мои строки #number {число, число, ..., число} могут быть очень длинными ...

Вот шаблон конструктора класса, который работает с этим файлом:

public Submatrix(String matrixFilePath, int startPos, int endPos) throws FileNotFoundException{

}

Как видите, подматрица определяется номерами строк матрицы startPos и ​​endPos.

Мой вопрос: "Как я могу считать строки, чтобы достичь правильной?" Мой файл может содержать миллиарды строк. Должен ли я использовать LineNumberReader-> readLine () миллиарды раз ?????

Ответы [ 4 ]

5 голосов
/ 27 февраля 2010

Я хотел бы прочитать каждую строку последовательно, пока не достигну желаемой строки. Однако, поскольку строки пронумерованы в файле и разделены символами новой строки, вы можете рассматривать файл как произвольный доступ и использовать различные стратегии. Например, вы можете использовать вариант бинарного поиска, чтобы быстро найти начальную строку. Вы можете оценить среднюю длину линии по первым N строкам, а затем попытаться сделать более точное предположение относительно начального местоположения и т. Д.

2 голосов
/ 27 февраля 2010

Я думаю, что ответом будет "да", вы читаете миллиарды строк, используя readLine, если только вы не считаете, что стоит использовать либо

  • стратегия, изложенная GregS, то есть оценка длины строки и использование ее для начала чтения где-то рядом с правильной строкой, или
  • вы используете отдельный индекс, либо в начале файла, либо в отдельном файле, который очень предсказуем и что-то вроде

    0000001 000000001024
    0000002 000000001064
    0000003 000000002010
    

    То есть номер строки и начальная позиция этой строки в байтах строго определенным образом, что позволяет определить положение индекса по чему-то вроде:

    Я хочу прочитать строку 3, чтобы найти положение строки 3, перейдя в положение (3-1) * 20, и прочитайте 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 {...}) с номером строки ввода, так что это довольно безопасно.

Независимо от того, выберете ли вы его или нет, я думаю, что пример довольно прост и легок.

1 голос
/ 28 февраля 2010

@ 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;
}

}

0 голосов
/ 27 февраля 2010

Боюсь, вам нужно перейти к x-й строке, вам придется вызывать readLine () x раз. Это означает чтение всех данных, пока вы не достигнете этой строки. Каждый символ может быть концом строки, поэтому невозможно перейти на x-ю строку, не прочитав каждый символ перед этой строкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...