Leer nombre de carpetas

Iniciado por elqueteconte, 9 Noviembre 2015, 14:50 PM

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

elqueteconte

Saludos amigos,

Tengo una función que lee el nombre de carpetas tomando en cuenta la selección de un mes, y las mueve a una carpeta principal.

Esta función fue desarrollada por Elektro y aquí se las comparto.

Código (vbnet) [Seleccionar]

        Public Sub MoveDateDirectories(ByVal year As Integer,
                                       ByVal month As Integer,
                                       ByVal dateFormat As String,
                                       ByVal sourceDir As String,
                                       ByVal targetDir As String)
            If (CStr(year).Length <> 4I) Then
                Throw New ArgumentOutOfRangeException(paramName:="year", message:="A value of 4 digits' is required.")
                'ElseIf (month < 1I) OrElse (month > 12I) Then
                '    Throw New ArgumentOutOfRangeException(paramName:="month", message:="A value from range '1' to '12' is required.")
                'ElseIf (dateFormat.Replace("y", "").Replace("M", "").Replace("d", "").Length <> 0) Then
                '    Throw New NotImplementedException(message:="Specified date format is not implemented, only 'yyyy', 'MM' and 'dd' are interchangeable.")
                'ElseIf Not Directory.Exists(sourceDir) Then
                '    Throw New DirectoryNotFoundException(message:=String.Format("Source directory not found: '{0}'", targetDir))
                'ElseIf Not Directory.Exists(targetDir) Then
                '    Throw New DirectoryNotFoundException(message:=String.Format("Target directory not found: '{0}'", targetDir))
            Else
                Dim sourceDirInfo As New DirectoryInfo(sourceDir)
                Dim targetDirInfo As New DirectoryInfo(targetDir)
                ' Obtengo una colección con los nombres de directorio con el formato de fecha especificado. (ej. de Octubre 2015:  20151001 ... 20151031)
                Dim dateDirNames As IEnumerable(Of String) =
                    From day As Integer In Enumerable.Range(1, DateTime.DaysInMonth(year, month))
                    Select dateFormat.Replace("yyyy", CStr(year)).
                                                  Replace("MM", CStr(month).PadLeft(2, "0"c)).
                                                  Replace("dd", CStr(day).PadLeft(2, "0"c))
                ' Obtengo una colección con las rutas absolutas de los directorios que cumplen los requisitos.
                Dim directories As IEnumerable(Of DirectoryInfo) =
                    From dirInfo As DirectoryInfo In sourceDirInfo.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
                    Where dateDirNames.Contains(dirInfo.Name)
                ' Un simple mensaje de información o aviso cuando no se encuentra ningún directorio el cual mover.
                If (Not directories.Any) Then
                    Dim msg As String = String.Format("No ha sido encontrado ningún directorio en '{0}' que cumpla las condiciones de formato de fecha.", sourceDirInfo.FullName)
                    MessageBox.Show(msg, " ", MessageBoxButtons.OK, MessageBoxIcon.Information)
                Else
                    ' Por último, muevo los directorios que cumplieron las condiciones de formato de fecha.
                    For Each dirInfo As DirectoryInfo In directories
                        Debug.WriteLine(String.Format("Moviendo: {0}", dirInfo.FullName))
                        Try
                            dirInfo.MoveTo(Path.Combine(targetDirInfo.FullName, dirInfo.Name))
                        Catch ex As Exception
#If DEBUG Then
                            Throw
#Else
                        MessageBox.Show(ex.Message & Environment.NewLine & ex.StackTrace, "By Elektro", MessageBoxButtons.OK, MessageBoxIcon.Error)
#End If
                        End Try
                    Next dirInfo
                    '                MessageBox.Show("Operación finalizada.", "By Elektro", MessageBoxButtons.OK, MessageBoxIcon.Information)
                End If ' Not directories.Any
            End If ' dateFormat...
        End Sub


Esta trabaja perfecto sin problemas; salvo que ahora necesito adecuarla de manera que sea posible mover días, es decir, si el usuario selecciona desde el 01-12-2015 hasta el 15-12-2015 (ambos inclusive); el proceso solo mueva esos días.

Alguien podría orientarme de como adecuar esta función para que haga lo que necesito?

Desde ya mil gracias...

Eleкtro

#1
Cita de: elqueteconte en  9 Noviembre 2015, 14:50 PMEsta función fue desarrollada por Elektro y aquí se las comparto.

Que conste que agradezco cualquier mención hacia mi persona como autor de algo, sin embargo, no quiero que se me asocie con malos hábitos de programación, en el código hay una gran ausencia de indentación, ya que lo has modificado bastante, los comentarios abusivos (y en español, cosa que lo hice para el caso) y el desorden en general que hay montado en ese bloque de código xD.




Ese método está quedando excesivamente grande. Cuanto más grande o complejo sea un método más complejo será también para el compiler/intérprete (complejidad ciclomática).

Vamos a separar el trabajo en varios métodos, primero una función para obtener los directorios, segundo un overload de esa función para poder especificar un rango de días, y por último un método para mover los directorios obtenidos.

y... voilà:

Código (vbnet) [Seleccionar]
   <DebuggerStepThrough>
   Public Iterator Function SelectDirectories(ByVal sourceDir As String,
                                              ByVal year As Integer,
                                              ByVal month As Integer,
                                              ByVal days As IEnumerable(Of Integer),
                                              ByVal dateFormat As String) As IEnumerable(Of DirectoryInfo)

       If (CStr(year).Length <> 4) Then
           Throw New ArgumentOutOfRangeException(paramName:="year",
                                                 actualvalue:=year,
                                                 message:="A value of 4 digits is required.")

       ElseIf (month < 1) OrElse (month > 12) Then
           Throw New ArgumentOutOfRangeException(paramName:="month",
                                                 actualvalue:=month,
                                                 message:="A value from range '1' to '12' is required.")

       ElseIf (dateFormat.Replace("y", "").
                          Replace("M", "").
                          Replace("d", "").Length <> 0) Then

           Throw New NotImplementedException(
               message:="Specified date format is not implemented, only 'yyyy', 'MM' and 'dd' are interchangeable.")

       ElseIf Not Directory.Exists(sourceDir) Then
           Throw New DirectoryNotFoundException(
               message:=String.Format("Source directory not found: '{0}'", sourceDir))

       End If

       Dim sourceDirInfo As New DirectoryInfo(sourceDir)

       ' Obtengo una colección con los nombres de directorio con el formato de fecha especificado.
       ' (ej. de Octubre 2015:  20151001 ... 20151031)
       Dim dateDirNames As IEnumerable(Of String) =
           From day As Integer In days
           Select dateFormat.Replace("yyyy", CStr(year)).
                             Replace("MM", CStr(month).PadLeft(2, "0"c)).
                             Replace("dd", CStr(day).PadLeft(2, "0"c))

       ' Itero y devuelvo una colección con las rutas absolutas de los directorios que cumplen los requisitos.
       For Each dirInfo As DirectoryInfo In sourceDirInfo.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)

           If dateDirNames.Contains(dirInfo.Name) Then
               Yield dirInfo
           End If

       Next

   End Function

   <DebuggerStepThrough>
   Public Function SelectDirectories(ByVal sourceDir As String,
                                     ByVal year As Integer,
                                     ByVal month As Integer,
                                     ByVal dateFormat As String) As IEnumerable(Of DirectoryInfo)

       Dim days As IEnumerable(Of Integer) = Enumerable.Range(1, DateTime.DaysInMonth(year, month))

       Return SelectDirectories(sourceDir, year, month, days, dateFormat)

   End Function

   <DebuggerStepThrough>
   Public Sub MoveDirectories(ByVal directories As IEnumerable(Of DirectoryInfo),
                              ByVal targetDir As String)

       If Not Directory.Exists(targetDir) Then
           Throw New DirectoryNotFoundException(
               message:=String.Format("Target directory not found: '{0}'", targetDir))

       Else
           Dim trgDirInfo As New DirectoryInfo(targetDir)

           For Each srcDirInfo As DirectoryInfo In directories

               If Not Directory.Exists(srcDirInfo.FullName) Then
                   Throw New DirectoryNotFoundException(
                       message:=String.Format("Source directory not found: '{0}'", srcDirInfo.FullName))
               Else
                   Debug.WriteLine(String.Format("Moviendo: {0}", srcDirInfo.FullName))
                   srcDirInfo.MoveTo(Path.Combine(trgDirInfo.FullName, srcDirInfo.Name))

               End If

           Next

       End If

   End Sub


PD: Lo he escrito al vuelo, no lo he testeado, ya no conservo la estructura de carpetas para testearlo, pero creo que no hay ninguna fisura en el código.




Ejemplo de uso:

Seleccionar las carpetas del mes entero:
Código (vbnet) [Seleccionar]
Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories("C:\Directorio\", 2015, 11, "formato de fecha")

o de un rango de días (del día 1 al 15):
Código (vbnet) [Seleccionar]
Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories("C:\Directorio\", 2015, 11, Enumerable.Range(1, 15), "formato de fecha")

o de ciertos dias:
Código (vbnet) [Seleccionar]
Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories("C:\Directorio\", 2015, 11, {5, 3, 9, 12}, "formato de fecha")

y por último, mover los directorios:
Código (vbnet) [Seleccionar]
MoveDirectories(directories, "C:\Destino\")

Saludos








elqueteconte

Hola Elektro buen día;

Gracias mil por el apoyo, tendré muy presente tus recomendaciones.

Te envié por MP el avance que he adelantado con respecto a esto, con el fin de que (dentro de tus posibilidades) le direas un vistazo y me orientaras al respecto.

Estoy totalmente de acuerdo contigo, no se puede hacer un solo método que haga multiples funciones lo ideal es uno por mes y otro por semana.

Quiero tambien disculparme si he cometido alguna falta al mencionar que la función la habias hecho tu, pero me pareció poco etico y profesional que yo me atribuyera algo que no me pertenece, sería un plagio.

Desde ya mil gracias por tu constante y valioso apoyo....

Seguiremos en contacto.


Eleкtro

Cita de: elqueteconte en  9 Noviembre 2015, 17:17 PMQuiero tambien disculparme si he cometido alguna falta al mencionar que la función la habias hecho tu, pero me pareció poco etico y profesional que yo me atribuyera algo que no me pertenece, sería un plagio.

No xD, para nada, todo lo contrario, solo que el código estaba un poco ""feo"" y yo soy muy "tiquismiquis" para ciertas cosas.

Sobre lo demás, te comentaré en privado.

Saludos!








elqueteconte

Cita de: Eleкtro en  9 Noviembre 2015, 17:29 PM
No xD, para nada, todo lo contrario, solo que el código estaba un poco ""feo"" y yo soy muy "tiquismiquis" para ciertas cosas.

Sobre lo demás, te comentaré en privado.

Saludos!

Limpiando el código como me comentas, tenemos entonces:
Código (vbnet) [Seleccionar]

       Public Sub MoveDateDirectories(ByVal year As Integer,
                                       ByVal month As Integer,
                                       ByVal dateFormat As String,
                                       ByVal sourceDir As String,
                                       ByVal targetDir As String)
            If (CStr(year).Length <> 4I) Then
                Throw New ArgumentOutOfRangeException(paramName:="year", message:="A value of 4 digits' is required.")
            Else
                Dim sourceDirInfo As New DirectoryInfo(sourceDir)
                Dim targetDirInfo As New DirectoryInfo(targetDir)
                Dim dateDirNames As IEnumerable(Of String) =
                    From day As Integer In Enumerable.Range(1, DateTime.DaysInMonth(year, month))
                    Select dateFormat.Replace("yyyy", CStr(year)).
                                                  Replace("MM", CStr(month).PadLeft(2, "0"c)).
                                                  Replace("dd", CStr(day).PadLeft(2, "0"c))
                Dim directories As IEnumerable(Of DirectoryInfo) =
                    From dirInfo As DirectoryInfo In sourceDirInfo.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
                    Where dateDirNames.Contains(dirInfo.Name)
                If (Not directories.Any) Then
                    Dim msg As String = String.Format("No ha sido encontrado ningún directorio en '{0}' que cumpla las condiciones de formato de fecha.", sourceDirInfo.FullName)
                    MessageBox.Show(msg, " ", MessageBoxButtons.OK, MessageBoxIcon.Information)
                Else
                    For Each dirInfo As DirectoryInfo In directories
                        Debug.WriteLine(String.Format("Moviendo: {0}", dirInfo.FullName))
                        Try
                            dirInfo.MoveTo(Path.Combine(targetDirInfo.FullName, dirInfo.Name))
                        Catch ex As Exception
                            Throw
                            MessageBox.Show(ex.Message & Environment.NewLine & ex.StackTrace, "By Elektro", MessageBoxButtons.OK, MessageBoxIcon.Error)
                        End Try
                    Next dirInfo
                    MessageBox.Show("Operación finalizada.", "By Elektro", MessageBoxButtons.OK, MessageBoxIcon.Information)
                End If
            End If
        End Sub


Esta es la que en la actualizadad hace el movimiento de los directorios; ahora bien en mi evento Click del botón aceptar tengo:

Código (vbnet) [Seleccionar]

    Private Sub BtAccept_Click(ByVal sender As Object, ByVal e As EventArgs) _
    Handles BtAccept.Click
        Dim monthNumber As Integer = Me.DTPMonth.Value.Month
        Dim dateDir As String = DateUtil.GetDateDirPath("es-ES", Me.fdg.SelectedPath, Me.year, monthNumber)
        ' Creo el directorio con fecha (si no existe).
        DateUtil.CreateDirectory(dateDir)
        If RBMonth.Checked Then
            DateUtil.MoveDateDirectories(Me.year, monthNumber, DateUtil.DirNameFormat, Me.fdg.SelectedPath, dateDir)
        Else [b]
'El usuario a seleccionado empaquetar solo una semana en particular aqui iria el codigo que corresponde al movimiento de las carpetas que esten dentro del rango de las indicadas por el usuario.[/b]
        End If
        ' Merge text files.
        DateUtil.FindAndMergeFiles(Me.fdg.SelectedPath, Me.CMBComp)
    End Sub


De acuerdo a lo que me estas indicando yo debería:
1.- Quitar la función MoveDateDirectories
2.- Copiar y pegar las funciones que haz desarrollado
3.- En el If si el usuario ha solicitado hacerlo mensual colocar:
Código (vbnet) [Seleccionar]

    Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories(dateDir, Me.year, monthNumber)
MoveDirectories(directories, Path.Combine(targetDirInfo.FullName, dirInfo.Name))

En caso de haber seleccionado una semana sería:
Código (vbnet) [Seleccionar]

Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories(dateDir, Me.year, monthNumber,Enumerable.Range(1, 15))
MoveDirectories(directories, Path.Combine(targetDirInfo.FullName, dirInfo.Name))


Es así como lo entiendo.

Desde ya gracias....!

Eleкtro

#5
Lo has entendido todo a la perfección y lo has sabido adaptar al código sin aydua :).

Solo que, aquí, no se si lo has entendido del todo, yo creo que deberías averiguar el día/semana que haya seleccionado en tu control DateTimePicker, y usarlo en el rango, por que esta función lo que hace es devolver un rango de valores desde X hasta Y: Enumerable.Range(desde_primer_dia_X, hasta_último_dia_Y):

Código (vbnet) [Seleccionar]
Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories(dateDir, Me.year, monthNumber, Enumerable.Range(1, semana))

Si solo quieres seleccionar la primera semana, deberías utilizarlo así Enumerable.Range(1, 7)

Auqnue bueno, eso es como tú lo quieras hacer.

Saludos!








elqueteconte

#6
Cita de: Eleкtro en  9 Noviembre 2015, 21:27 PM
Lo has entendido todo a la perfección y lo has sabido adaptar al código sin aydua :).

Solo que, aquí, no se si lo has entendido del todo, yo creo que deberías averiguar el día/semana que haya seleccionado en tu control DateTimePicker, y usarlo en el rango, por que esta función lo que hace es devolver un rango de valores desde X hasta Y: Enumerable.Range(desde_primer_dia_X, hasta_último_dia_Y):

Código (vbnet) [Seleccionar]
Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories(dateDir, Me.year, monthNumber, Enumerable.Range(1, semana))



Aunque bueno, eso es como tú lo quieras hacer.

Saludos!

Gracias, gracias, gracias jejejejeje

No entendí lo ultimo, acerca de la función de los días; la idea es que el usuario coloque al menos 2 días, es decir, desde el 01 al 02, pero no va a poder seleccionar varios días salteado por ejemplo, 01, 03, 05 y 09. En este caso sería como seleccionar entre el 01 y el 09.

So, siempre habrá un rango que será igual o mayor a dos días y menor al ultimo día del mes. La fecha desde no puede ser posterior a la fecha hasta y la fecha hasta no puede ser inferior a la fecha desde, estas son reglas que se colocarán en la validación del campo con el evento onChange.

En este caso te pregunto como sería la función Enumerable.Range ?

Otra cosa:
Al función SelectDirectories espera 4 parámetros y en el llamaddo yo le estoy colocando solo 3, me falta el dateFormat, de donde lo saco?

Código (vbnet) [Seleccionar]

Dim directories As IEnumerable(Of DirectoryInfo) = DateUtil.SelectDirectories(dateDir, Me.year, monthNumber, ME FALTA ESTE PARÁMETRO)


De nuevo gracias mil.

Eleкtro

#7
Cita de: elqueteconte en  9 Noviembre 2015, 21:48 PMdesde el 01 al 02

entre el 01 y el 09.

siempre habrá un rango

En este caso te pregunto como sería la función Enumerable.Range ?

Código (vbnet) [Seleccionar]
Enumerable.Range(inicio, fin)
Código (vbnet) [Seleccionar]
Enumerable.Range(1, 2)
Código (vbnet) [Seleccionar]
Enumerable.Range(1, 9)




Cita de: elqueteconte en  9 Noviembre 2015, 21:48 PMOtra cosa:
Al función SelectDirectories espera 4 parámetros y en el llamaddo yo le estoy colocando solo 3, me falta el dateFormat, de donde lo saco?

Código (vbnet) [Seleccionar]

Dim directories As IEnumerable(Of DirectoryInfo) = DateUtil.SelectDirectories(dateDir, Me.year, monthNumber, ME FALTA ESTE PARÁMETRO)



El método original que estaba sutilizando era este:
Código (vbnet) [Seleccionar]
Public Sub MoveDateDirectories(ByVal year As Integer,
                                      ByVal month As Integer,
                                      ByVal dateFormat As String,
                                      ByVal sourceDir As String,
                                      ByVal targetDir As String)


Revisa en el código fuente que valor le estabas enviando al parámetro dateFormat de ese método. Usa el mismo valor al llamar a esta nueva función. No recuerdo el formato, está escrito en tu código fuente y también en alguna de las páginas de tus preguntas anteriores, era un string más o menos así "MM-dd-YYYY".

Saludos








elqueteconte

#8
Saludos;

1.-  
Código (vbnet) [Seleccionar]
Enumerable.Range(inicio, fin)
Donde inicio y fin son el valor del DateTmePiker que seleccionó el usuario.

Sería algo como:
Código (vbnet) [Seleccionar]

Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories(dateDir, Me.year, monthNumber, Enumerable.Range(Me.DTPSince.Value, Me.DTPUntil.Value))


Pero dado que el valor que espera el método Enumerable es un entero y el valor que tiene el objeto DTPSince es un string hay que hacer la conversión, que inicialmente sería con esto:

Código (vbnet) [Seleccionar]
Convert.ToInt32(DTPUntil.Value.ToString("yyyyMMdd"))

Es esto correcto?

Así quedaría la definición de la variable:
Código (vbnet) [Seleccionar]

Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories(dateDir, Me.year, monthNumber, Enumerable.Range(Convert.ToInt32(DTPSince.Value.ToString("yyyyMMdd")), Convert.ToInt32(DTPUntil.Value.ToString("yyyyMMdd"))))


2.- La definición de la variable sería entonces asi:
Código (vbnet) [Seleccionar]
Dim directories As IEnumerable(Of DirectoryInfo) = DateUtil.SelectDirectories(dateDir, Me.year, monthNumber, DateUtil.DirNameFormat)

Como quedaría el llamado al metodo?

Pues he intentado con la variable targetDirInfo y dirInfo pero  me está dando error de no declarado o inaccesible.

Gracias!

elqueteconte

Saludos,

Me puse a estudiar el metodo Enumerable.Range y me día cuenta que lo que decía antes era un soberano disparate pues el range utiliza el valor del día de la fecha inicial (para mi caso especíifico) y el segundo valor es la cantida de días; es decir; que si la fecha de inicio es 01-11-2015 y la fecha fin es 12-11-2015; entonces el primero valor será el 1 y el segundo valor será el 11.

Esto significa que debo sacar una operación matematica pra calcular la diferencia.

Código (vbnet) [Seleccionar]

Dim InitialDate As Date = DTPSince.Value
Dim FinalDate As Date = DTPUntil.Value
Dim tspan As TimeSpan
Dim differenceInDays As Integer
tspan = InitialDate - FinalDate
differenceInDays = tspan.Days


Una vez obtenido esto la definición de la variable directories sería:
Código (vbnet) [Seleccionar]

Dim directories As IEnumerable(Of DirectoryInfo) = SelectDirectories(dateDir, Me.year, monthNumber, Enumerable.Range(InitialDate.Day, differenceInDays))


Pero me sigue dando error de IEnumerable (Of Integer) to String.

Que estoy haciendo mal? :-\