2010-02-27 9 views
3

J'ai un fichier texte. Il est conçu comme suit:Comment marquer une chaîne dans un fichier?

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

... (à la fin d'un se tient "\ n" chaque entrée)

C'est un exemple. En fait mes chaînes #number {nombre, nombre, ..., numéro} pourrait être très long ...

Voici un modèle d'un constructeur d'une classe qui fonctionne avec ce fichier:

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

} 

Comme vous pouvez le voir, la sous-matrice est déterminée par les nombres startPos et endPos des chaînes d'une matrice.

Ma question est: "Comment pourrais-je compter les chaînes pour atteindre la bonne?" Mon fichier peut contenir des milliards de chaînes. Devrais-je utiliser LineNumberReader-> readLine() des milliards de fois ?????

Répondre

2

Je pense que la réponse est oui, vous avez bien lu des milliards de lignes en utilisant readLine, à moins que vous pensez que ça vaut la peine utilisant

  • la stratégie définie par GREGS, qui est l'estimation de la longueur de la ligne et l'utilisation que pour commencer à lire quelque part près de la ligne correcte, ou
  • vous utilisez un index séparé, soit au début du fichier ou dans un fichier séparé qui est très prévisible et est quelque chose comme

    0000001 000000001024 
    0000002 000000001064 
    0000003 000000002010 
    

    C'est le numéro de ligne et la position de départ de cette ligne en octets d'une manière strictement définie qui permet de déterminer la position de l'index par quelque chose comme:

    Je veux lire la ligne 3, donc je trouve la position de la ligne 3 en allant à la position (3-1) * 20, et lire 0000003 000000002010, analyser cela et savoir que la ligne 3 est à la position d'octet 2010, chercher cette position et commencer à lire.

    Il peut être difficile de calculer ou de conserver l'index s'il se trouve dans le fichier de données principal, car cela signifie que vous précalculerez les positions avant d'écrire le fichier. Je pense que j'utiliserais un fichier d'index séparé et calculerais des index pendant l'écriture, ou aurais un utilitaire séparé pour créer un fichier d'index donné à un fichier de données.

EDIT exemple de code Ajouté à démontrer ma proposition

J'ai fait un script Python plutôt petit qui lit un fichier de données et crée un fichier d'index. Le fichier d'index contient la position d'une ligne dans le fichier de données et est conçu pour être facilement consultable.

Cet exemple de script a un formatage d'index de 06d, ce qui est assez bon pour 999.999 fichiers de données de ligne, pour vous, il pourrait avoir à être ajusté (ne pas oublier INDEX_LENGTH). Il crée un fichier d'index, et utilise ce fichier d'index pour lire une ligne donnée sur le fichier de données (à des fins de démonstration, vous devez utiliser java pour cette partie :)

Le script est appelé comme:

python create_index.py data.txt data.idx 3 

mon exemple fichier de données est:

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

et le script lui-même est:

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

Le fichier d'index doit être reconstruit après une modification dans le fichier de données. Vous pouvez vérifier si vous avez lu les bonnes données en comparant votre numéro de ligne à partir des données lues (# 3 {...}) avec le numéro de ligne d'entrée, donc c'est assez sûr.

Que vous choisissiez de l'utiliser ou non, je pense que l'exemple est assez clair et facile.

+0

Je ne suis pas sûr si je pourrais utiliser cette stratégie avec un tel fichier d'information. La fonction seek (arg) fonctionne avec l'argument "long", de sorte que je ne peux utiliser que 2^63-1 symboles.Mais si je dois lire la dernière corde et qu'il y a des milliards de grosses cordes, je pense qu'il y aurait beaucoup plus de symboles ... Que faire? – Dmitry

+0

Eh bien, peut-être que j'ai pris la mauvaise stratégie. Ma tâche est la suivante: je dois programmer l'algorithme de quatre Russes pour multiplier 2 matrice booléenne. Ces matrices sont vraiment énormes (comme je le disais, des milliards de grosses cordes)! J'ai choisi la représentation. où les nombres entre {} indiquent les endroits où les 1 restent. Selon cet algorithme, j'ai besoin d'ajouter deux chaînes de ce type (ces chaînes localisent dans un fichier). Je veux rechercher deux chaînes puis enregistrer une partie de chacune d'entre elles dans un tampon (ArrayList ), puis ajouter ces parties selon une certaine règle, puis enregistrer le résultat dans un fichier résultat spécial. Donc, j'ai besoin de rechercher ces deux chaînes – Dmitry

+0

Mon être là est une autre façon de représenter une matrice, ce qui aidera à rechercher les chaînes nécessaires ??? – Dmitry

5

Je serais tenté de lire chaque ligne de manière séquentielle jusqu'à ce que j'atteigne la ligne désirée. Cependant, étant donné que les lignes sont numérotées dans le fichier et délimitées par des retours à la ligne, vous pouvez traiter le fichier comme un accès aléatoire et utiliser diverses stratégies. Par exemple, vous utilisez une variante de recherche binaire pour trouver rapidement la ligne de départ. Vous pouvez estimer la longueur de ligne moyenne à partir des N premières lignes, puis essayer de faire une estimation plus précise de l'emplacement de départ, et ainsi de suite.

+1

ne savais pas que les lignes ont été numérotées ... Si tel est le cas, cela ressemble à une bonne solution en effet. Cependant, si lire chaque ligne ne donne pas de gros problèmes de performances, je ne m'en soucierai pas ... – Fortega

+0

C'est une approche intelligente –

+1

Une chose à noter est que tout ce qui contient des informations redondantes devient très fragile et difficile à travailler - si vous ajoutez une ligne supplémentaire dans le fichier n'importe où mais la fin, vous devez renuméroter le reste. Ce n'est peut-être pas un problème dans ce cas particulier, mais cela vaut la peine d'être considéré. –

-1

Je crains que vous ayez à atteindre la ligne x, vous devrez appeler readLine() x fois. Cela signifie lire toutes les données jusqu'à ce que vous atteigniez cette ligne. Chaque personnage peut être une fin de ligne, donc il n'y a aucun moyen d'aller à la ligne X sans lire tous les caractères avant cette ligne.

+0

N'a pas vu les lignes ont été numérotées, donc d'autres solutions pourraient être mieux pour vous ... – Fortega

1

@extraneon

Ceci est la classe que je veux utiliser pour représenter une #number chaîne {numéro, numéro, ...}

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

} 

Peut être qu'il serait efficace de sérialiser, au lieu de convertir le BinaryRow (sa mise en œuvre va ci-dessous) à une chaîne? Si j'en série plusieurs instances dans un fichier, comment vais-je désérialiser la chaîne nécessaire (instance nécessaire)? (Hope, je compris votre question)

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

@Dmitry vous semblez déjà avoir une sérialisation assez lourde avec la méthode pow(). Une optimisation facile de la taille consisterait à écrire les numéros de chaîne radix 36 (voir Long.toString (long i, int radix) et Long.valueOf (String s, int radix) pour rendre les nombres un peu plus courts. :) En guise de remarque, égal vérifie généralement le type (instanceof) avant la diffusion pour éviter de lancer des exceptions, et vous créez généralement un hashCode si vous implémentez des égales. J'adore votre choix pour la composition avec List au lieu de simplement hériter. – extraneon

+0

Ok, mais comment vais-je travailler avec de telles données? Je veux dire comment vais-je compter les octets nécessaires pour les utiliser dans un fichier d'index? Ou est-ce une variante différente de la réalisation? – Dmitry

+0

Vous écrivez maintenant un nombre comme 12345, alors ce même nombre serait 9ix. Le format de données serait alors {9ix, ...}.Le fichier d'index aurait exactement le même format (des valeurs différentes bien sûr), mais l'écriture et la lecture du fichier de données devraient utiliser Long.toString (number, _radix_) et Long.valueOf (string, _radix_) au lieu de toString par défaut (nombre) et valueOf (chaîne) avec la racine par défaut 10. – extraneon

Questions connexes