martes, 7 de agosto de 2018

Copia y renombre masivo de ficheros con apoyo en Excel. Preliminar.

Una noche de insomnio compre en amazón un lector mp3 para Arduino, con el fin de incorporar música a alguno de mis proyectos. Como lo compré sin meditarlo mucho, al empezar, al intentar utilizarlo, me di cuenta de que no era exactamente lo que yo pensaba que era, no se ajustaba exactamente a lo imaginado. Lleva un soporte de tarjeta microsd en donde se supone que tenemos que tener la música.
En concreto los diferentes mp3 ni pueden llamarse de cualquier manera, ni pueden estar donde me apetezca, deben tener como nombre un número y estar en la raíz de la tarjeta microsd.
¿Como hago yo una copia masiva de mis mp3 y, además les pongo otro nombre?:Con el antiguo DOS y con apoyo en Excel.



  • En windows, abriendo un terminal DOS (con CMD en la línea ejecutar) o bien creando un fichero ejecutable .bat
  • Utilizo el comando dir c:\*.mp3 /s /b >mp3.txt
  • Este comando da todos los mp3 que hay en el disco C: y redirecciona la salida a un fichero de texto (mp3.txt)
  • Por supuesto que no es necesario buscar en todo el disco, podemos buscar en varios directorios de uno en uno. Solo hay que incorporar una línea por directorio y redireccionar la salida como >>mp3.txt
  • En mi PC algunos caracteres no se representan correctamente. No importa, al utilizarlos de vuelta, se compensa ese error.
  • Este error parece que se soluciona configurando el DOS a teclado en español (keyb sp o kb16 sp dependiendo del tipo de windows), pero en mi windows no están instalados ninguno de ellos.
  • Con cualquier editor de texto, o abriendo el fichero de texto directamente desde excel, copiamos el contenido de este fichero en una hoja excel (a1)
  • Vamos a preparar un fichero ejecutable .bat de DOS.  En las columnas B y C preparo el ordinal, el nombre de la copia. En B incremento el ordinal (B2=B1+1) y en C pongo los ceros a la izquierda necesarios, con =DERECHA(100000+B1;5).
  • En la columna D preparamos una línea con el comando de DOS copy. El nombre original va precedido y seguido de comillas, de esa manera podemos incluir espacios en blanco en los nombres.
  • El nombre de destino, en este caso, no tiene espacios en blanco, luego no necesitamos incluir las comillas.
  • El comando resultante, uno por línea, es:="copy " & CARACTER(34) & A1 & CARACTER(34) & " c:\temp\mp3\" &C1 & ".mp3".
  • Copiamos toda la columna en un fichero .bat, ejecutable en DOS. Salvamos.
  • Ejecutamos el .bat, podemos o no desviar la salida a un fichero de texto, lo que nos permite controlar los posibles errores de copia. Nos copia todos los ficheros mp3 en un solo directorio y con los nombres adecuados.
  • Ya solo nos queda pasarlos, si no lo hemos hecho directamente, a la tarjeta SD.
Ayer por la mañana escribí la primera parte de este articulo. Por la tarde me estuve documentando sobre el lector de mp3 y parece que si admite que la tarjeta SD tenga directorios aunque con algunas limitaciones.
Preparo una segunda  hoja (hoja2), en el libro CopiarMp3_2.xls, que me separa los mp3 por directorios. En principio tanto las canciones como los directorios toman un nombre numérico, que es lo que recomiendan algunas páginas.
  • Para separar los directorios necesito conocer la última posición del carácter "\". Para ello creo una función, Ultima,  en vbasic para encontrar esa ultima posición.
  • Una vez separado el directorio , con =SI($B4<>$B3;$D3+1;$D3) incrementamos el número de directorio. Esta instrucción se puede leer como "si el directorio actual es distinto del directorio anterior, incrementa uno. Si no déjalo como está"
  • Para numerar las canciones dentro de su directorio utilizo =SI($B4<>$B3;1;$H3+1), que puede leerse como "si el directorio anterior es distinto del actual pon 1, si no incrementa uno".
  • En la columna F preparo unas instrucciones DOS, con = " mkdir " & $H$1  & DERECHA($D3+1000;3), para crear los directorios mediante un fichero ejecutable ".bat". Estas instrucciones se copian en un fichero .bat, que debe ejecutarse antes de la copia de los mp3.
  • Dejo abierta la posibilidad de trabajar con los nombres de directorios o/y ficheros.
Mi propia función, la función Ultima(): Entrando en los módulos VBasic podemos verla. No tiene gran explicación, se basa en la instrucción vbasic InStrRev que nos da la última aparición de un determinado carácter en una cadena alfanumérica


Function Ultima(Cad, Sep)

'Cad=Cadena alfanumérica

'Sep=separador, carácter buscado.

Ultima = InStrRev(Cad, Sep)


End Function

La pregunta es ,Y dado que nos metemos a programar en vbasic ¿porque no lo hacemos todo de una tacada en vbasic?
Código de la función que lee el fichero con los mp3 y crea un ejecutable (.bat). Este ejecutable crea los directorios y copia los ficheros.
Aunque también escribe en el excel, este paso no es necesario. Se puede omitir.
Cuando utilizo un fichero de texto creado con windows 7 me aparecen una serie de caracteres (unicode) que me introducen unos salto de línea incontrolados, que se pueden eliminar copiando a excel la línea para después recuperarlos.

Código de la función:
Sub Proceso()
Dim Carac, Lin, DirT, Datos, Salida, N, Pos1, Pos2, LinA, C(255)
Dim Lat, Lon, V, FH, Fic, Dir2, Dir1, DirAnt, ND, NF
'DirEntr = "C:\Documents and Settings\Fernando y Use\Mis documentos\Mi Garmin\"
'Nom = "fUENCARRAL, tRES cANTOS, aLCOBENDASReal.gpx"
With Sheets("Config")
DirT = .Range("b1").Value
Datos = .Range("b3").Value
Salida = .Range("b2").Value
End With
'Sheets(1).Range("a" & 1 + NF) = DirEntr & Nom
Close #1
Close #2
Open Datos For Input As #1
Open Salida For Output As #2


Lin = ""
N = 1
With Sheets("Datos")
.Select
.Cells.Clear
'MsgBox DirEntr & Nom
Do While Not EOF(1)

Carac = Input(1, #1)
C(Asc(Carac)) = C(Asc(Carac)) + 1
'If Asc(Carac) = 127 Or Asc(Carac) = 129 Or Asc(Carac) = 141 Or Asc(Carac) = 143 Or Asc(Carac) = 144 Or Asc(Carac) = 157 Then MsgBox Asc(Carac)

If (Asc(Carac) = 10 Or Asc(Carac) = 13) And Lin <> "" Then
N = N + 1


Pos1 = Ultima(Lin, "\")
Fic = Mid(Lin, Pos1 + 1)
Dir1 = Left(Lin, Pos1 - 1)
Pos1 = Ultima(Dir1, "\")
Dir2 = Mid(Dir1, Pos1 + 1)
If DirAnt <> Dir2 Then

ND = ND + 1
.Range("f" & ND + 1) = " mkdir " & DirT & Mid(1000 + ND, 2)
'.Range("g" & ND + 1) = " mkdir " & DirT & Dir2
Print #2, " mkdir " & DirT & Mid(1000 + ND, 2)
NF = 1
End If

Sheets("config").Range("d1").Value = Lin
' en Sheets("config").Range("e1")  hay que colocar la fórmula =limpiar(D1)
Lin = Sheets("config").Range("e1").Value
.Range("a" & N) = Lin
.Range("b" & N) = Dir1
.Range("c" & N) = Dir2
.Range("d" & N) = ND
.Range("e" & N) = Fic
DirAnt = Dir2
Print #2, " copy " & Chr(34) & Lin & Chr(34) & " " & DirT & Mid(1000 + ND, 2) & "\" & Mid(1000 + NF, 2) & ".mp3"
Lin = ""
NF = NF + 1
Else

If Asc(Carac) <> 13 And Asc(Carac) <> 10 Then Lin = Lin & Carac

End If
Loop

'.Range("1") = N
For i = 0 To 255
.Range("h" & i + 2) = i
.Range("i" & i + 2) = C(i)
.Range("j" & i + 2) = Chr(i)
Next
End With


Close #1
Close #2

End Sub


Caracteres no imprimibles: En principio son aquellos cuyo código ascii es menor de 32 (espacio). los no imprimibles van de de 0 a 31. En texto unicode hay otros  caracteres no imprimibles (127,129,141,143,144 y 157).