aplicar atributos a archivos y carpetas.

Iniciado por **Aincrad**, 14 Abril 2018, 21:37 PM

0 Miembros y 1 Visitante están viendo este tema.

**Aincrad**

Hola a todos , bueno como dice el titulo estoy necesitando un code que tenga buena recursividad  y que este ligado a un progressbar .

(No estoy pidiendo que me hagan la tarea ni nada por el estilo) , yo mismo lo puedo hacer , pero cuando se trata de leer directorios y archivos soy pesimo.

solo hago este post haber si alguien tiene un buen code que quiera compartirlo.

el code que necesito debe tener:

*buscar archivos y carpetas ocultas de un directorio y volverlos visibles . (o viceversa).
*tener buena recursividad.
*estar ligado a un ProgressBar

Bueno de todos modos yo tambien lo intentare hacer, haber como me sale .  :xD




Eleкtro

#1
Cita de: **Aincrad** en 14 Abril 2018, 21:37 PM
(No estoy pidiendo que me hagan la tarea ni nada por el estilo) , yo mismo lo puedo hacer , pero cuando se trata de leer directorios y archivos soy pesimo.

¿Entonces por que no formulas una duda específica?. En tu comentario estás pidiendo que te hagan la tarea se mire como se mire...

Cita de: **Aincrad** en 14 Abril 2018, 21:37 PM*tener buena recursividad.

No necesitas un método recursivo para esto, de hecho deberías tratar de evitar la recursividad siempre que sea posible, más cuado no tienes ningún control sobre la cantidad de llamadas recursivas que se realizarán (como sería este caso)... de lo contrario solo conseguirás tener un algoritmo inestable que podría llegar a ocasionar un desbordamiento de la pila de llamadas, o call-stack overflow por su nombre en Inglés, vaya.

Cita de: **Aincrad** en 14 Abril 2018, 21:37 PM*estar ligado a un ProgressBar

Con la cantidad de directorios a procesar y archivos en dicho directorio puedes crear un valor máximo para la barra de progeso, y un porcentaje.

Cita de: **Aincrad** en 14 Abril 2018, 21:37 PM*buscar archivos ocultos de un directorio y volverlos visibles . (o viceversa).

Usa la función System.IO.Directory.EnumerateDirectories() y System.IO.Directory.EnumerateFiles() en función de si quieres obtener las rutas absolutas de archivos o carpetas. La colección de strings devuelta puedes transformarla en una colección de tipo System.IO.DirectoryInfo o System.IO.FileInfo para mayor comodidad.

Para el tema de los atributos puedes usar las funciones System.IO.File.GetAttributes() + System.IO.File.SetAttributes(), o bien la propiedad System.IO.FileInfo.Attributes. Para comprobar si el archivo tiene el atributo oculto, debes usar la función [Enum].HasFlag() (System.IO.File.GetAttributes().HasFlag() / System.IO.FileInfo.Attributes.HasFlag()), pasándole el valor FileAttributes.Hidden. Para volver visible un archivo oculto pues simplemente debes eliminar ese valor o flag que ya he mencionado, al asignar las propiedades del archivo.

Con eso lo tienes todo hecho y solucionado. Si necesitas desarrollar un algoritmo más sofisticado que no lance excepción por denegación de permisos de lectura o escritura en carpetas o archivos, la cosa se complica, es algo que necesita más esfuerzo de implementar, claro está, pero por suerte para ti aquí tendrías la solución que implementé para mi librería comercial ElektroKit, la cual permite decidir ignorar carpetas/archivos sin acceso, provee varios parámetros de búsqueda adicionales, y es una implementación asincrónica:


y aquí tienes unos wrappers y con ejemplos de uso escritos en la documentación XML:


...al final a pesar de lo que dije al principio, te he dado la tarea hecha si vas a usar mi código, pero solo por que yo ya tenía esto hecho de hace años y no me importa compartirlo. Por lo general no lo entregaría.

Un saludo








**Aincrad**

Bueno lo he hecho así espero sus criticas constructivas:  :xD

Código (vbnet) [Seleccionar]
Imports System.IO

Public Class Form1
Public Shared MyDrive As String
Private Sub buttonScan_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonScan.Click
        Using folder As New FolderBrowserDialog
            With folder
                If .ShowDialog = 1 Then
                    MyDrive = .SelectedPath.ToString
                    Unhide()
                End If
            End With
        End Using
    End Sub

#Region "unhide"

    Private Function GetFilesRecursive(ByVal initial As String) As List(Of String)

        Dim result As New List(Of String)

        Dim stack As New Stack(Of String)

        stack.Push(initial)

        Do While (stack.Count > 0)
            Dim dir As String = stack.Pop
            Try
                result.AddRange(Directory.GetFiles(dir, "*.*"))

                Dim directoryName As String
                For Each directoryName In Directory.GetDirectories(dir)
                    stack.Push(directoryName)
                Next

            Catch ex As Exception
            End Try
        Loop

        Return result
    End Function

    Private Function GetDirectoriesRecursive(ByVal initial As String) As List(Of String)

        Dim result As New List(Of String)


        Dim stack As New Stack(Of String)


        stack.Push(initial)


        Do While (stack.Count > 0)

            Dim dir As String = stack.Pop
            Try

                result.AddRange(Directory.GetDirectories(dir, "*.*"))


                Dim directoryName As String
                For Each directoryName In Directory.GetDirectories(dir)
                    stack.Push(directoryName)
                Next

            Catch ex As Exception
            End Try
        Loop


        Return result
    End Function

    Public Sub Unhide()
        Dim FileCounter As Integer = 0
        Dim FolderCounter As Integer = 0

        Dim Files As List(Of String) = GetFilesRecursive(MyDrive)
        Dim Directories As List(Of String) = GetDirectoriesRecursive(MyDrive)

        For Each Filename In Files
            If (IO.File.GetAttributes(Filename) And IO.FileAttributes.Hidden) = IO.FileAttributes.Hidden Then

                IO.File.SetAttributes(Filename, IO.FileAttributes.Normal)
                FileCounter = FileCounter + 1
            End If
        Next

        For Each DirectoryName In Directories
            If (IO.File.GetAttributes(DirectoryName) And IO.FileAttributes.Hidden) = IO.FileAttributes.Hidden Then

                IO.File.SetAttributes(DirectoryName, IO.FileAttributes.Normal)
                FolderCounter = FolderCounter + 1
            End If
        Next
    End Sub

#End Region

End Class


lo único que me falta es el ProgressBar. pero estoy pensando en mejor poner unos labels que muestren los numeros de archivos y otro que muestre el directorio.







Eleкtro

#3
Habría ciertas cosas que mencionar sobre el modo de ejecución, pero no quiero sobrepasarme con críticas constructivas. Sin embargo, veo necesario mencionar un fallo de diseño en concreto que considero grave... es aquí:

Código (vbnet) [Seleccionar]
IO.File.SetAttributes(Filename, IO.FileAttributes.Normal)
...
IO.File.SetAttributes(DirectoryName, IO.FileAttributes.Normal)


No si lo haces así intencionadamente o simplemente no te diste cuenta, pero te explico de todas formas: al llamar al método File.SetAttributes() estás reemplazando (o mejor dicho en este caso: eliminando) cualquier atributo anterior que tuviese el archivo o carpeta, como por ejemplo atributo de sistema, de solo lectura, o de archivo indizado. Deberías asegurarte de conservar los atributos anteriores, y añadirle el nuevo atributo o eliminarle el que quieras eliminarle (y solo ese). Ya expliqué como hacerlo en mi anterior comentario, aquí tienes un ejemplo:

Código (vbnet) [Seleccionar]
Dim fi As New FileInfo("C:\file.txt")
Dim flag As FileAttributes = FileAttributes.Hidden

If fi.Attributes.HasFlag(flag) Then
   ' Elimino el atributo de archivo oculto peservando el resto de atributos.
   fi.Attributes = (fi.Attributes And Not flag)
End If

Debug.WriteLine(fi.Attributes.ToString())


Con la función File.GetAttributes() y el método File.SetAttributes() la metodología sería idéntica a la que acabo de demostrar, solo que usando dichos miembros en lugar del tipo FileInfo y su propiedad FileInfo.Attributes.

Saludos!








**Aincrad**

gracias por la por el comentario.




Cita de: Eleкtro en 14 Abril 2018, 22:23 PM
Cita de: **Aincrad** en 14 Abril 2018, 22:23 PM
*estar ligado a un ProgressBar

Con la cantidad de directorios a procesar y archivos en dicho directorio puedes crear un valor máximo para la barra de progeso, y un porcentaje.

bueno quiero poner un progressbar pero no logro como hacerlo . como tu dices la progressbar tiene un valor maximo , en ese caso tendria que hacer una regla de 3 .

numeros de archivos ---------------------------  100%
archivos procesados ----------------------------   x %

pero, no se si tu lo podrías hacer mejor harías mejor, como dije ayer :

lo intentare hacer, haber como me sale .

Pero si puedes ayudarme un poco con un ejemplo de como lo harias tu  XD . disculpa la molestias .  ;D






Eleкtro

#5
Suponiendo que el valor mínimo es cero, y el valor máximo que le quieres asignar debe ser la cantidad total de archivos de todos los directorios y subdirectorios (de lo contrario, acláralo), pues entonces debes hacer dos iteraciones principales, la primera para declarar una colección a la que le irás añadiendo la ruta absoluta de cada archivo encontrado con tu método de recursividad, y entonces el valor máximo (es decir, la cantidad total de archivos) lo puedes obtener de la propiedad IEnumerable.Count de dicha colección. La segunda iteración principal la harías sobre los elementos de la susodicha colección.

Cita de: **Aincrad** en 15 Abril 2018, 20:36 PMsi puedes ayudarme un poco con un ejemplo de como lo harias tu  XD .

Es que hay varias formas de hacer practicamente lo mismo, al final depende de como quieras tú representar la información/progreso en la interfaz de usuario. La forma "estándar" (del mismo modo que lo hace Windows, en el diálogo de progreso que aparece cuando mueves o eliminas directorios por ejemplo) sería la que te he mencionado. En varios de los aportes que he compartido en el foro puedes encontrar un algoritmo de progreso, como por ejemplo aquí: https://foro.elhacker.net/net/source_mastermusik_manager_v20-t426379.0.html;msg1983807#msg1983807

Otra opción de representación de la información de progreso sería mostrar dos barras de progreso, una para el progreso total de archivos, y otra para mostrar el progreso individual por carpeta, es decir la cantidad de archivos a procesar en la carpeta actual, y al terminar se suma a la barra de progreso actual, no se si me explico.

O puedes hacer el progreso solamente por cantidad de carpetas en lugar de cantidad de archivos total, aquí tienes un ejemplo: https://foro.elhacker.net/net/sourcecode_ddmm_dummy_drive_mirror_maker-t479871.0.html

O también puedes ahorrarte mayores esfuerzos y simplemente colocar tu barra de progreso en estado indeterminado.

Un saludo!








Serapis

Cuando no se conoce a prori, lo que ha de hacer una tarea determinada (tarea determinada, con cantidad detrabajo indeterminado), una barra de progreso resulta inútil... si no sabes de antemano si hay 100 ficheros, o 100.000 como vas a indicar el porcentaje total que llevas en un momento dado???.

Cuando es incierto lo que haya de tardar, porque se desconoce el tamaño (y precalcularlo, supone una pérdida de tiempo, que alarga el tiempo de proceso), entonces lo deseables es mostrar solo un indicador de "Trabajando"... esto es, ...una pequeña animación, y para que el usuario no acabe por creer que se ha colgado la aplicación, con cada carpeta, la señalas en un label y como habrá carpetas con muchos ficheros, cada segundo (por ejemplo) actualizas la ruta el nombre del fichero actual en otro label...

Eleкtro

#7
Cita de: NEBIRE en 16 Abril 2018, 04:42 AMy como habrá carpetas con muchos ficheros, cada segundo (por ejemplo) actualizas la ruta el nombre del fichero actual en otro label...

Añado: a menos que estemos trabajando en un escenario asincrónico, donde el sabio consejo o advertencia de retrasar la frecuencia de actualización del texto del control en la UI en realidad no tendría sentido aplicarlo puesto que hacerlo no supondría ningún impacto positivo (tampoco supondría un impacto negativo, claro está, exceptuando la posible sensación de estar visualizando una actualización lenta del texto del control); el retraso intencionado no supondría ningún nebeficio en la respuesta de la UI ni la velocidad del algoritmo en segundo plano que estuviese procesando archivos/carpetas/lo que sea.

Saludos!