2010-07-29 4 views
8

J'ai un fichier journal que je voudrais analyser et j'ai quelques problèmes. Au début, il semblait que ce serait simple. Je vais aller de l'avant et afficher la source que j'ai inventée, puis expliquer ce que j'essaie de faire.Fichier texte d'analyse Groovy

Le fichier que je suis en train d'analyser contient ces données:

HDD Device 0 : /dev/sda 
HDD Model ID : ST3160815A 
HDD Serial No : 5RA020QY 
HDD Revision : 3.AAA 
HDD Size  : 152628 MB 
Interface : IDE/ATA 
Temperature   : 33 C 
Health : 100% 
Performance : 70% 
Power on Time : 27 days, 13 hours 
Est. Lifetime : more than 1000 days 

HDD Device 1 : /dev/sdb 
HDD Model ID : TOSHIBA MK1237GSX 
HDD Serial No : 97LVF9MHS 
HDD Revision : DL130M 
HDD Size  : 114473 MB 
Interface : S-ATA 
Temperature : 30 C 
Health : 100% 
Performance : 100% 
Power on Time : 38 days, 11 hours 
Est. Lifetime : more than 1000 days 

Mon code source (ci-dessous) casse essentiellement la ligne de fichiers en ligne et divise ensuite la ligne en deux (clé: valeur).

Source:

def dataList = [:] 
def theInfoName = "C:\\testdata.txt" 

File theInfoFile = new File(theInfoName) 

def words 
def key 
def value 

if (!theInfoFile.exists()) { 
    println "File does not exist" 

} else { 

theInfoFile.eachLine { line -> 

if (line.trim().size() == 0) { 
    return null 

} else { 

    words = line.split("\t: ") 
    key=words[0] 
    value=words[1] 
    dataList[key]=value 

    println "${words[0]}=${words[1]}" 
    } 

} 
println "$dataList.Performance" //test if Performance has over-written the previous Performance value 
} 

Le problème avec ma source est que lorsque j'utilise mes getters (comme dataList.Performance $), il montre que le dernier dans le fichier au lieu de deux.

Alors je me demande, comment puis-je analyser le fichier afin qu'il conserve les informations pour les deux disques durs? Existe-t-il un moyen de compresser l'information dans un «objet de disque dur»?

Toute aide est appréciée

Quelques notes secondaires:

Le fichier se trouve sur une machine Windows (même si l'information est saisi d'un système nix)

Le fichier texte est divisé par un onglet, deux points, et l'espace (comme montré dans mon code source) juste pensé que je dirais que parce que cela ne ressemble pas à cela sur cette page.

Répondre

14

Cela lire les données dans des blocs (avec des lignes vides séparant les blocs)

def dataList = [] 
def theInfoName = 'testdata.txt' 

File theInfoFile = new File(theInfoName) 

if(!theInfoFile.exists()) { 
    println "File does not exist" 
} else { 
    def driveInfo = [:] 
    // Step through each line in the file 
    theInfoFile.eachLine { line -> 
    // If the line isn't blank 
    if(line.trim()) { 
     // Split into a key and value 
     def (key,value) = line.split('\t: ').collect { it.trim() } 
     // and store them in the driveInfo Map 
     driveInfo."$key" = value 
    } 
    else { 
     // If the line is blank, and we have some info 
     if(driveInfo) { 
     // store it in the list 
     dataList << driveInfo 
     // and clear it 
     driveInfo = [:] 
     } 
    } 
    } 
    // when we've finished the file, store any remaining data 
    if(driveInfo) { 
    dataList << driveInfo 
    } 
} 

dataList.eachWithIndex { it, index -> 
    println "Drive $index" 
    it.each { k, v -> 
    println "\t$k = $v" 
    } 
} 

les doigts croisés que vous avez des lignes vides entre vos sections d'information du disque dur (vous montriez un dans vos données de test) :-)

BTW: Je reçois la sortie suivante:

Drive 0 
    HDD Device 0 = /dev/sda 
    HDD Model ID = ST3160815A 
    HDD Serial No = 5RA020QY 
    HDD Revision = 3.AAA 
    HDD Size = 152628 MB 
    Interface = IDE/ATA 
    Temperature = 33 C 
    Health = 100% 
    Performance = 70% 
    Power on Time = 27 days, 13 hours 
    Est. Lifetime = more than 1000 days 
Drive 1 
    HDD Device 1 = /dev/sdb 
    HDD Model ID = TOSHIBA MK1237GSX 
    HDD Serial No = 97LVF9MHS 
    HDD Revision = DL130M 
    HDD Size = 114473 MB 
    Interface = S-ATA 
    Temperature = 30 C 
    Health = 100% 
    Performance = 100% 
    Power on Time = 38 days, 11 hours 
    Est. Lifetime = more than 1000 days 

Messing Arou nd, j'ai aussi obtenu le code jusqu'à:

def dataList = [] 
def theInfoFile = new File('testdata.txt') 

if(!theInfoFile.exists()) { 
    println "File does not exist" 
} else { 
    // Split the text of the file into blocks separated by \n\n 
    // Then, starting with an empty list go through each block of text in turn 
    dataList = theInfoFile.text.split('\n\n').inject([]) { list, block -> 
    // Split the current block into lines (based on the newline char) 
    // Then starting with an empty map, go through each line in turn 
    // when done, add this map to the list we created in the line above 
    list << block.split('\n').inject([:]) { map, line -> 
     // Split the line up into a key and a value (trimming each element) 
     def (key,value) = line.split('\t: ').collect { it.trim() } 
     // Then, add this key:value mapping to the map we created 2 lines above 
     map << [ (key): value ] // The leftShift operator also returns the map 
           // the inject closure has to return the accumulated 
           // state each time the closure is called 
    } 
    } 
} 

dataList.eachWithIndex { it, index -> 
    println "Drive $index" 
    it.each { k, v -> 
    println "\t$k = $v" 
    } 
} 

Mais cela doit charger le fichier entier en mémoire à la fois (et repose sur \n comme la terminaison EOL char)

+0

Ahh, le pouvoir d'injecter. ;) – Blacktiger

+1

Tout le monde aime injecter ;-) –

+0

Wow, merci bud. Je ne veux pas vous déranger, mais êtes-vous capable de commenter le second, comme vous l'avez fait avec le premier? Ou si c'est trop de travail, peut-être expliquer comment cela fonctionne. Merci encore, testé et fonctionne très bien. En ce qui concerne le chargement en mémoire, ça devrait aller puisque ce n'est pas une grande quantité de texte. – JohnStamos

5

Voici ma solution:

File file = new File('testdata.txt') 
if(file.exists()) { 
    def drives = [[:]] 
    // Split each line using whitespace:whitespace as the delimeter. 
    file.splitEachLine(/\s:\s/) { items -> 
     // Lines that did not have the delimeter will have 1 item. 
     // Add a new map to the end of the drives list. 
     if(items.size() == 1 && drives[-1] != [:]) drives << [:] 
     else { 
      // Multiple assignment, items[0] => key and items[1] => value 
      def (key, value) = items 
      drives[-1][key] = value 
     } 
    } 

    drives.eachWithIndex { drive, index -> 
     println "Drive $index" 
     drive.each {key, value -> 
      println "\t$key: $value" 
     } 
    } 
} 
+0

Celui-ci fonctionne très bien aussi ! Merci bud. Voulez-vous commenter votre code? Maintenant que vous avez tous deux posté des exemples de travail, je voudrais savoir comment tout fonctionne avant de l'utiliser:] – JohnStamos