2010-07-29 20 views
8

Tengo un archivo de registro que me gustaría analizar y estoy teniendo algunos problemas. Al principio parecía que sería simple. Continuaré y publicaré la fuente que se me ocurrió y luego explicaré lo que trato de hacer.Groovy archivo de texto de análisis

El archivo que estoy tratando de analizar estos datos contiene:

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 

Mi código fuente (abajo) básicamente rompe el archivo línea por línea y luego se divide la línea en dos (clave: valor).

Fuente:

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 
} 

El problema con mi fuente es que cuando uso mis captadores (como $ dataList.Performance) sólo muestra la última en el archivo en lugar de dos.

Así que me pregunto, ¿cómo puedo analizar el archivo para que conserve la información de ambos discos duros? ¿Hay alguna manera de empaquetar la información en un 'objeto de disco duro'?

Cualquier y toda ayuda es apreciada

Unas pocas notas secundarios:

El archivo está en una máquina Windows (a pesar de que la información se tomó de un sistema nix)

El archivo de texto es dividido por una pestaña, dos puntos y un espacio (como se muestra en mi código fuente) pensé que lo expresaría porque no se ve así en esta página.

Respuesta

14

Esto permitirá la lectura de los datos en bloques (con líneas en blanco que separa los bloques)

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

dedos cruzados que tiene líneas en blanco entre sus secciones de información (HDD que mostró una de sus datos de prueba) :-)

por cierto: me sale el siguiente resultado:

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, también tiene el código de abajo a:

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

Pero eso tiene que cargar todo el archivo en la memoria a la vez (y se basa en \n como el carbón terminación EOL)

+0

Ahh, el poder de inyectar. ;) – Blacktiger

+1

Todo el mundo ama inyectar ;-) –

+0

Wow, gracias bud. No quiero molestarte, pero ¿puedes comentar el segundo, como hiciste con el primero? O si eso es demasiado trabajo, quizás explique cómo funciona. Gracias de nuevo, lo probé y funciona muy bien. En cuanto a cargarlo en la memoria, debería estar bien ya que no es una gran cantidad de texto. – JohnStamos

5

Aquí está mi solución:

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

Este funciona muy bien también Gracias, amigo. ¿Te importaría comentar tu código? Ahora que ustedes dos han publicado ejemplos de trabajo, me gustaría saber cómo funciona todo antes de usarlo:] – JohnStamos