Archivo por meses: febrero 2021

Cambiar nombres ficheros (utilidad)

Pues eso… aquí tienes una utilidad para cambiar los nombres de los ficheros. No solo cambiar un texto existente en el nombre, si no que también se puede añadir (o quitar) un texto al principio o al final del nombre del fichero.

Ver el P.S. 3 con los cambios del 1-mar-2021

Los ficheros a procesar los puedes indicar según la extensión de los mismos (o usando un filtro con * y/o ?. En total se pueden procesar 4 directorios/filtros.

En la figura puedes ver la aplicación en modo de ejecución.

Figura 1. La aplicación en funcionamiento

Funcionamiento de la aplicación

Como puedes ver en la figura, tiene 4 grupos de directorios/ficheros con idea de que puedas indicar varias extensiones o bien 4 directorios diferentes.

Cada directorio se puede o no procesar (el primero siempre se tendrá en cuenta), por supuesto, si no indicas el path ni la extensión no se procesarán (o así debería ser, pero en realidad no hago ningana comprobación al respecto, así que… para salir de dudas… ¡pruébalo!).

En la parte inferior tienes las opciones de qué hará la aplciación, teniendo estas opciones:

  • Añadir el texto indicado en Text 1 al principio.
  • Añadir el texto indicado en Text 1 al final.
  • Quitar el texto indicado en Text 1 del principio.
  • Quitar el texto indicado en Text 1 del final.
  • Cambiar lo que haya en Text 1 por lo que hay en Texto 2

Y para las dos opciones de añadir texto puedes indicar si no se hace el cambio en el caso de que dicho texto (el de Texto 1) ya está.

Cuando se selecciona alguna de las dos opciones de añadir, se habilita ese control. En el resto de opciones está deshabilitado.

Lo mismo ocurre con el texto de Texto 2, que se habilitará solo si se selecciona la opción de cambiar, en las otras 4 opciones estará deshabilitado, y por tanto no se tendrá en cuenta lo que se escriba.

En las cajas de textos (Texto 1 y Texto 2) se pueden indicar espacios al final (y se tendrán en cuenta en la búsqueda y/o reeemplazo) y como visiblemente es difícil de ver si hay uno o más espacios, en caso de que haya más de un espacio al final, el programa los quitará y dejará solo uno. Si no hay espacios al final del texto no se añadirá ninguno.

Nota:

Hay que tener en cuenta, sobre todo al reemplazar texto (opción Cambiar) que el texto indicado en Texto 1 se reemplazará por el que haya en Texto 2 en todo el nombre del fichero (sin tener en cuenta ni el path ni la extensión).
Por tanto, si buscas el y el nombre original es Inclemencias del tiempo y quieres cambiar ese el por la el rtexto resultandte será (en mayúsculas los cambios realizados): IncLAmencias dLA tiempo.

El que avisa…

Controles usados en la utilidad

Esta utilidad (o aplciación) usa 4 controles del tipo BackgroundWorker con idea de usar de forma fácil la operación asíncrona.

El que está enlazado con el primer grupo (el que siempre está activo) siempre se ejecuta. Pero los otros 3 solo si se marca la opción que está arriba de cada grupo.

La barra de progreso tendrá en cuenta todos los ficheros que se vayan a procesar.

Y para saber el total de ficheros a procesar, en cada evento DoWork de cada control BackgroundWorker se añade a una colección definida a nivel del formulario en la que se almacenará los nombres de los ficheros a procesar (teniendo en cuenta el directorio en el que se buscarán los ficheros con el filtro indicado.

Ese filtro se hace usando lo indicado en cada caja de texto etiquetada tras Filtro. Como se pueden usar los comodines * y ? podrás usar cosas como estas:

  1. *.txt para indicar todos los ficheros con la extensión .txt
  2. algo?.xls* esto buscará los ficheros que empiecen con algo y cualquier carácter a continuación y que tengan una extensión que empiece por .xls

Como el código está compilado con .NET Framewwork 4.8 en realidad esto se puede hacer sin indicar el asterisco final, es decir, se puede indicar de esta forma: algo?.xls para que acepte todas las extensiones que empiecen por xls (.xls y .xlsx).

En .NET 5.0 habría que hacerlo como he comentado en el segundo punto, pero no es este el caso de esta aplicación.

Algo de código fuente

El código fuente está publicado en GitHub Cambiar-Nombres-Ficheros-v1

Aquí te muestro el código del evento Click del botón Procesar:

Private Sub btnProcesar_Click(sender As Object, e As EventArgs) Handles btnProcesar.Click
    ficheros.Clear()

    ' Si al final del texto a buscar/poner
    ' hay más de un espacio, cambiarlo por solo 1
    If txtTexto1.Text.EndsWith(" ") Then
        txtTexto1.Text = txtTexto1.Text.TrimEnd(" "c) & " "
    End If
    If txtTexto2.Text.EndsWith(" ") Then
        txtTexto2.Text = txtTexto2.Text.TrimEnd(" "c) & " "
    End If

    If chkProces1.Checked Then
        bgwProc1.RunWorkerAsync()
    End If
    If chkProces2.Checked Then
        bgwProc2.RunWorkerAsync()
    End If
    If chkProces3.Checked Then
        bgwProc3.RunWorkerAsync()
    End If

    ' Este siempre se procesa
    ' Hacer esta llamada al final para que se restauren los valores
    ' al terminar el trabajo.
    bgwProc.RunWorkerAsync()
End Sub

En los eventos DoWork de cada BackgroundWorker se hace la llamada al método … con el siguiente código:

backgroundWorker_DoWork(txtDir, txtExtensiones.Text)

Donde txtDir y txtExtensiones se usarán los nombres correwspondientes a cada grupo, por ejemplo, en el grupo 1 (el cero es el que siempre se ejecuta) se hará la siguiente llamada:

backgroundWorker_DoWork(txtDir1, txtExtensiones1.Text)

El código de backgroundWorker_DoWork es el siguiente, en donde solo se obtienen los ficheros que corresponden a cada directorio y con el filtro indicado.

''' <summary>
''' Método usado por el método DoWork de los BackgroundWorkers.
''' </summary>
''' <param name="txtDir">El directorio a usar.</param>
''' <param name="filtro">El filtro de los ficheros a usar.</param>
Private Sub backgroundWorker_DoWork(txtDir As TextBox,
                                    filtro As String)
    ' Aquí se acumulan los ficheros en la colección
    ' y se procesarán todos al final.
    ' De esta forma sabemos cuántos ficheros se procesan en total.
    Dim fileEnum = System.IO.Directory.EnumerateFiles(txtDir.Text, filtro)
    ficheros.AddRange(fileEnum)

End Sub

Una vez que finaliza el trabajo de bgwProc se procesan los ficheros.
Esto último se hace en el evento RunWorkerCompleted de ese control BackgroundWorker (en un momento verás el código).
Ahí se harán los cambios de todos los ficheros (que estarán en la colección ficheros), llamando al método cambiarNombres al que le pasamos como argumento el nombre del fichero a procesar.
Una vez finalizado los cambios, (y para que de tiempo a ver el mensaje), lanzo un temporizador después de tres segundos en el que se limpiarán los mensajes y se ocultará la barra de progreso.

Cabe decir que si alguno de los otros procesos dura má que este último puede que no se procesen bien todos los ficheros, pero… eso es algo que podemos arreglar en una futura revisión de este programa.
Y que a mí se me ocurre que se puede hacer comprobando cuando terminan todos los procesos asíncronos (comprobando cada uno de los eventos RunWorkerCompleted de cada tarea).
Pero por ahora te lo dejo como tarea que debes hacer y que podrás comprobar el día que yo lo publique.

Este es el código del método que hace todo esto (y como tip decirte que ese código tendrá que estar en otro sitio diferente si quieres tener en cuenta lo que he comentado en la nota anterior).

Private Sub bgwProc_RunWorkerCompleted(sender As Object,
                                       e As System.ComponentModel.RunWorkerCompletedEventArgs) _
                                       Handles bgwProc.RunWorkerCompleted
    ' Procesar los ficheros acumulados en la colección
    ProgressBar1.Visible = True
    ProgressBar1.Maximum = ficheros.Count
    ProgressBar1.Value = 0

    For i = 0 To ficheros.Count - 1
        cambiarNombres(ficheros(i))
        ProgressBar1.Value = i + 1
    Next

    Dim s As String
    If ficheros.Count = 1 Then
        s = "el nombre al fichero."
    Else
        s = $"los {ficheros.Count} nombres."
    End If
    LabelStatus.Text = $"Finalizado el proceso de cambiar {s}"
    Application.DoEvents()

    ' Mostrar ese mensaje por 3 segundos
    Timer1.Interval = 3000
    Timer1.Enabled = True

End Sub

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    Timer1.Enabled = False

    ProgressBar1.Visible = False
    LabelStatus.Text = LabelStatus.Tag.ToString()
    Application.DoEvents()

End Sub

Por último te muestro el código del método cambiarNombres.

Private Sub cambiarNombres(file As String)
    Dim fi As New System.IO.FileInfo(file)
    Dim s As String = file ' fi.FullName

    LabelStatus.Text = $"{fi.Name}"
    Application.DoEvents()

    If optCambiar.Checked Then
        s = fi.Name.Replace(txtTexto1.Text, txtTexto2.Text)
        If s <> fi.Name Then
            My.Computer.FileSystem.RenameFile(file, s)
        End If
    ElseIf optAñadirPrincipio.Checked Then
        If chkNoDuplicar.Checked Then
            If fi.Name.StartsWith(txtTexto1.Text) = False Then
                s = txtTexto1.Text & fi.Name
                My.Computer.FileSystem.RenameFile(file, s)
            End If
        Else
            s = txtTexto1.Text & fi.Name
            My.Computer.FileSystem.RenameFile(file, s)
        End If
    ElseIf optAñadirFinal.Checked Then
        If chkNoDuplicar.Checked Then
            If fi.Name.EndsWith(txtTexto1.Text) = False Then
                s = fi.Name & txtTexto1.Text
                My.Computer.FileSystem.RenameFile(file, s)
            End If
        Else
            s = fi.Name & txtTexto1.Text
            My.Computer.FileSystem.RenameFile(file, s)
        End If
    ElseIf optQuitarPrincipio.Checked Then
        If fi.Name.StartsWith(txtTexto1.Text) Then
            s = fi.Name.Replace(txtTexto1.Text, "")
            My.Computer.FileSystem.RenameFile(file, s)
        End If
    ElseIf optQuitarFinal.Checked Then
        If fi.Name.EndsWith(txtTexto1.Text) Then
            s = fi.Name.Replace(txtTexto1.Text, "")
            My.Computer.FileSystem.RenameFile(file, s)
        End If
    End If

    LabelStatus.Text &= $" --> {s}"
    Application.DoEvents()
End Sub

Y esto es todo por ahora… espero que te sea de utilidad, y si quieres indicar alguna mejora o algún fallo, eres libre de hacerlo en los comentarios de este post.

Muchas gracias.

Nos vemos.
Guillermo

P.S.
Crearé la versión de C# de esta utilidad (por ahora solo la tengo en Visual Basic) y cuando la tenga finalizada, la publicaré también en GitHub.
Aunque esa versión de CSharp la haré con los cambios que antes te he indicado: para asegurar que todos los procesos asíncronos han finalizado.

P.S.2 (28-feb-2021 02:21)
Ya está el código modificado teniendo en cuenta que se finalicen todos los procesos de los BackgroundWorker y además con el código para C#.
Puedes ver el código fuente en GitHub.

Para hacer lo que comentaba más arriba: comprobar que todos los BackgroundWorkers han finalizado he modificado el código de forma que se hacen estas comprobaciones:

  1. Defino dos variables a nivel de formulario para saber cuántos grupos se van a procesar (cada grupo se corresponde con un BackgroundWorker) y cuántos han finalizado.
  2. En el evento RunWorkerCompleted se usa el siguiente código (te muestro el de C#):
private void bgwProc_RunWorkerCompleted(object sender, 
                                        System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    cuantosFinalizados += 1;
    // Cuando estén todos los procesos finalizados, hacer los cambios.
    if (cuantosFinalizados == cuantosProcesos)
        finalizarCopia();
}
  1. El código que había antes en ese método de evento ahora está en el método finalizaCopia, tal como puedes ver en el siguiente código que es para C#.
private void finalizarCopia()
{
    // Procesar los ficheros acumulados en la colección
    ProgressBar1.Visible = true;
    ProgressBar1.Maximum = ficheros.Count;
    ProgressBar1.Value = 0;

    for (var i = 0; i <= ficheros.Count - 1; i++)
    {
        cambiarNombres(ficheros[i]);
        ProgressBar1.Value = i + 1;
    }

    string s;
    if (ficheros.Count == 1)
        s = "el nombre al fichero.";
    else
        s = $"los {ficheros.Count} nombres.";
    LabelStatus.Text = $"Finalizado el proceso de cambiar {s}";
    Application.DoEvents();

    // Mostrar ese mensaje por 3 segundos
    timer1.Interval = 3000;
    timer1.Enabled = true;
}
  1. En el método de evento Click del botón Procesar ahora se tiene en cuenta las dos nuevas variables para saber cuántos grupos hay que tener en cuenta.
private void btnProcesar_Click(object sender, EventArgs e)
{
    ficheros.Clear();
    cuantosFinalizados = 0;
    cuantosProcesos = 1;

    // Si al final del texto a buscar/poner
    // hay más de un espacio, cambiarlo por solo 1
    if (txtTexto1.Text.EndsWith(" "))
        txtTexto1.Text = txtTexto1.Text.TrimEnd(' ') + " ";
    if (txtTexto2.Text.EndsWith(" "))
        txtTexto2.Text = txtTexto2.Text.TrimEnd(' ') + " ";

    if (chkProces1.Checked)
    {
        cuantosProcesos += 1;
        bgwProc1.RunWorkerAsync();
    }
    if (chkProces2.Checked)
    {
        cuantosProcesos += 1;
        bgwProc2.RunWorkerAsync();
    }
    if (chkProces3.Checked)
    {
        cuantosProcesos += 1;
        bgwProc3.RunWorkerAsync();
    }

    // Este siempre se procesa
    // Hacer esta llamada al final para que se restauren los valores
    // al terminar el trabajo.
    bgwProc.RunWorkerAsync();
}

Y esto es todo…
En GitHub está el nuevo código para Visual Basic y el proyecto de C#.

 
 
P.S. 3 (01-mar-2021)
Actualizado el código de VB y C# para que tenga en cuenta un par de fallillos que había:
– al añadir/quitar de los nombres el texto indicado, ya que se usba fi.Name y ahí se incluye la extensión, y la extensión no se debe tener en cuenta al cambiar el nombre.
– al marcar/desmarcar las opciones de los grupos, que se deshabilitaba todo, ahora solo se habilitan/deshabilitan los controles que contiene, salvo el propio CheckBox.

Aguacates, oro verde, proteínas y calorías

Aguacates, oro verde, proteínas y calorías

Nota aclaratoria (por si decides no seguir leyendo):

Esto es una especie de cuento (o historia), es decir, nada tiene que ver con la programación ni el I+D.

Oro verde = aguacates.

De esos frutos, donde vivo, está abarrotao, hay árboles por todos lados, y por el cortijo en el que resido actualmente hay aún más… o al menos más a mano; prácticamente solo tengo que extender el brazo y ya tengo los aguacates que quiera. Eso sí, no son de mi propiedad, aunque el dueño, que es también el dueño del cortijo, me da permiso para que coja los que necesite, pero sin pasarme, solo los necesarios.

Aguactates fresquitos

Ayer precisamente me dio una caja, realmente media, ya que estuvieron recogiendo para venderlos, y antes de que se llevará todos, le pedí unos pocos para mis hijos y hermanos, y para mí amigo Gabrié, el de Chauchina, Graná, compañero de la mili, concretamente de la 5ª CIA de la PM allá por el 1978-79 en Barcelona, tierra de los polacos… O eso nos hicieron recordar durante los días de instrucción en el cuartel del Bruch. Que allí no había barceloneses si no polacos. En fin… Las cosas de los que eran más veteranos (y ninguno de ellos era de Barcelona).

Los aguacates están caros, sobre todo fuera de esta zona… No sé los precios actuales, pero creo que en el norte de paga por un solo aguacate lo que a Pepe, el dueño del cortijo, le dan por un kilo de los de tamaño grande.

Como puedes ver en las fotos, 2 aguacates grandes o 5 de los chicos pesan unos 500 gr, y a este hombre le pagan menos de 2€ por un kilo de ese tamaño grande, y si son de los chicos, no llega ni al euro.

Dos aguacates grandes 500gr
Cinco aguacates chicos 500gr

Pero… así son las cosas del campo y la gente que tiene que distribuirlos,
envasarlos, enviarlos y demás.

Pero los aguacates son buenos.

No a todo el mundo les gusta, pero solo es cuestión de acostumbrarse al sabor.

A mí me pasó eso al principio, antes de vivir en el campo, hasta que me dijeron que, aparte de la grasa que tienen (calorías supongo) tienen muchas proteínas, por tanto son buenos para la alimentación del cuerpo este que tenemos, sobre todo si eres vegetariano.

Yo de calorías y proteínas no entiendo, al menos en lo que respecta en saber cómo se sabe que las tiene. Lo mismo que dicen que las lentejas (si no las quieres las dejas) solo tienen media proteína y debes comerlas o prepararlas con otra legumbre (por ejemplo el arroz) para tener una proteína completa.

Pero supongo que habrá alguna forma de saber estas cosas.

Aunque a mí se he escapan.

Lentejas con aguacates

Lo que sí he probado es a poner aguacates al preparar las lentejas, no sé si de esa forma parte de la proteínas del aguacate se pasarán a las lentejas o no… Ya te digo que no sé cómo narices funciona esto de las medias proteínas y cómo se hacen una entera… pero la verdad es que las lentejas con aguacates están buenas… Y por si quieres probar la próxima vez que prepares unas lentejas,. yo echo el aguacate directamente con las lentejas, el tomate, los pimientos y el ajo (y el chorreoncito de aceite de oliva virgen extra, de eso que no falte), es decir, no hace falta echarlo cuando ya falte menos para que pase el tiempo de cocción, como es el caso de las zanahorias o las patatas.

Todo es empezar

La cuestión es que estuve un tiempo comiendo aguacates casi todos los días, creo que fue por el 2016 o antes… en el desayuno y hasta en la comida, mezclado con tomate, pan y aceite… ¡Qué rico!
En esa época, mi colega Juani (el de Conservas Yoga) era el que me daba los aguacates, ¡y que no faltaran! También me daba mi amiga Carmen; ya que en aquélla época no vivía en el campo… aunque aprovechaba cuando iba a caminar por sitios con aguacates recolectar los que daban al camino… ya sabes lo que se dice: si los frutos dan al camino, no tienen dueño (o algo así) jejeje.

Y en algunas de esas recolectas iba con mis sobrinas postizas (Estrella y Candela), y de tanto hablar de los aguacates, me decían (en plan juego) que no podía decir la palabra agua así que… esto de comentar que quería recoger algunos …cates era complicado, y cada vez que me olvidaba… ¡me tocaba la regañina de las dos! En fin… Juegos de niños, y uno, a pesar de no poder decir la palabra completa, también me lo pasaba bien… eso sí, recibía más regañinas de las que hubiera deseado… 😉

Y como suele pasar, de todo se harta uno… ¡hasta de los ricos aguacates!

Y… continuar

Pero bueno, aprovechando que el otro día estuvieron recogiendo aguacates para llevarlos a la corría pa venderlos, rebusqué los que tenía ya maduros y así llevo unos días desayunando tostadas con aceite, aguacate, tomate aderezados con algo de pimienta negra, ajo y un poco de sal (marina) con aloe vera, cebolla y jengibre que prepara mi amigo y colega Juani (sí, el de Conservas Yoga) que dice que es mejor para los que tenemos la tensión alta ya que se disuelve mejor en la sangre que la sal marina común.

Bueno, ya está bien del tema de los aguacates… que parece que te los quiero vender… jajaja. Esto es porque el otro día (creo que el 23 por la noche) se me pasó por la cabeza contarte algunas cosillas de estas, así en plan distendido y sin querer hacer algo serio con estas cosas… Y así lo he hecho… y ya de paso, esto lo estoy escribiendo usando el formato MarkDown que después se puede convertir en código HTML, más que nada para poder escribirlo tanto en el ordenador, como en el móvil y después pegarlo en el blog.

Herramientas usadas para escribir esta historia

Actualmente estoy usando la aplicación MarkdownPad 2 para Windows y en el móvil Android he instalado SimpleMarkdown porque la anterior que instalé, y eso que tenía más votos, no me permitía abrir ficheros ni de Google Drive ni siquiera de la carpeta de descargas (download) del móvil, y con SimpleMarkdown sí puedo hacer esas dos cosas.

Aunque intento en la medida de lo posible descargar primero el fichero con la extensión .MD desde Google Drive y usarlo desde la carpeta de descargas, y después lo vuelvo a subir, con idea de tenerlo disponible desde el portátil; pero ese envío lo hago por email, ya que algunas veces el android se toma su tiempo en subir el fichero al Drive y prefiero mandarlo a una cuenta de gmail y desde el mensaje recibido almacenarlo en una carpeta de Google Drive. Al menos así siempre funciona, y lo mejor, sin esperas, aunque haya que dar un paso más.

He puesto esas referencias, porque siempre gusta (al menos a mí) qué herramientas usa la gente para hacer estas cosas.

¡Espero que lo aguacatees bien!

Nos vemos.
Guillermo

P.S.
Esto está publicado usando las categorías historias y mis cosas.
La categoría historias la estreno con este post, mientras que mis cosas era la categoría que en un principio ideé para los post con cosas particulares, no técnicas: las correrías, excursiones, etc.

He estado modificando las categorías de los posts anteriores a hoy, y a fecha de hoy 27 de febrero de 2021 a las 15:30, a todos los artículos posteriores a diciembre de 2018 le he quitado mis cosas a los artículos técnicos que no incluyen batallitas mías, así en plan personal, los artículos técnicos están bajo la categoría cosas técnicas.