Colabora .NET |
Implementando un Splitter en .NET
Fecha: 29/Nov/2006 (29-11-06)
|
PrefacioAntes que nada, agradecerle al Guille (nuevamente) por todas las cosas que aprendido en este sitio y mas que nada por darle la oportunidad a estudiantes como yo de formar parte de esta comunidad .NET, ah y por los artículos de Todo Programación sobre Programación Orientada a Objetos :). IntroducciónComo dice el titulo, en este articulo veremos como implementar un sencillo Splitter, un programa que divide y reagrupa archivos al de estilo Hacha o el mismo Winrar (que también tiene esta opción). El principioEl principio que usaremos es muy sencillo y se resume a esto: Es decir, tomamos los bytes de un archivo y los escribimos en nuevos archivos, manteniendo el orden que tenían en el archivo original de forma tal que cuando queramos reagrupar estos fragmentos lo hagamos de forma correcta. ¿Sencillo verdad?
Las dos primeras permiten la lectura/escritura de caracteres en un Stream (flujo de bytes que representa un archivo) en una codificación determinada. Nos servirán para escribir el manifiesto, un archivo que contiene información para que podamos reagrupar el archivo. FileStream en cambio permite operaciones sincrónicas y asincrónicas de lectura/ escritura de un archivo. Por lo que será la base del proceso de división y posterior reagrupamiento. El algoritmoUtilizando las clases anteriormente descritas, implementaremos dos métodos estáticos contenidos dentro de la clase SplitBoss: SplitFile y JoinFile public static void JoinFile(object JoinInfo) public static void SplitFile(object SplitInfo) Public Shared Sub JoinFile(ByVal JoinInfo As Object) Public Shared Sub SplitFile(ByVal SplitInfo As Object) Estos métodos reciben como parámetro un object, se preguntaran ¿por que? Obviamente estos métodos tienen conocer información acerca del proceso que harán: path del archivo, tamaño de los "pedazos", etc. A esto agregarle que nuestra aplicación debe ser capaz de mostrar el proceso, y seguir siendo capaz de actualizar su interfaz, ya que esta se bloquearía mientras trata con los archivos. La respuesta es la programación concurrente, multihebra o multihilo, y ya en el framework 2.0 podemos pasar parámetros a un hilo de manera "elegante" y no de manera indirecta como sucedia antes. Una aplicación por default esta compuesta por un hilo de ejecución, pudiéndose agregar muchos mas, siendo el sistema operativo el encargado de gestionar su comportamiento en paralelo. Como mencione unas líneas arriba, con al versión 2.0 del framework podemos pasarle parámetros a los hilos, algo que nos estaba vetado en la primera versión. Hablando en términos de framework, en al versión 1.0 los métodos que iniciaban un hilo (o "vivían en el) tenían que corresponder con la firma del delegado ThreadStart: public delegate void ThreadStart () Public Delegate Sub ThreadStart() El cual como ven no recibe ningún parámetro, por lo que debíamos proporcionarle la información indirectamente (o sea que desde el cuerpo del método obtener la información de variables locales, funciones, etc). Ahora esta disponible el delegado ParameterizedThreadStart, que si recibe un parámetro: public delegate void ParameterizedThreadStart(Object obj); Public Delegate Sub ParameterizedThreadStart(ByVal obj As Object) De ahí que los métodos SplitFile y JoinFile reciban un object, para que coincidan con esta firma. Este object que pasaremos será un objeto de las clases JoinInfo y SplitInfo segun sea el proceso, una vez en el cuerpo del método haremos un cast moldeando el Object para que podamos acceder a la información que necesitamos. Ahora bien, con todo esto de la programación concurrente necesitamos saber cuando un hilo ha terminado, la manera mas sencilla es que el mismo nos avise. Rápidamente pensamos en eventos, que es perfectamente posible, pero personalmente me decanto por los delegados (que al final es mas o menos lo mismo ya que los delegados son la base de los eventos) . De manera tal que el hilo que la implementación de SplitBoss será menos dependiente del programa como tal, ya que interactuaran a través de delegados. El hilo que hará el trabajo sucio solo tiene que devolver la llamada y ejecutar un método definido con anterioridad pasándole algunos parámetros. Ahora veamos el código de la clase SplitBoss: using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Windows.Forms; using System.Diagnostics; namespace Spliter { class SplitBoss { //Delegados public delegate void NewLogCallback(string Message,DateTime Time); //Una nueva entrada en log public delegate void ProcessChangesCallback(int Value); //Avance del progreso public delegate void FinishProcessBecauseErrorCallback(); //Terminado el proceso por error public delegate void FinishProcessCallback(); //Terminado correctamente //Definimos las extensiones static string SegmentExtension = ".spt"; static string ManifiestExtension = ".mspt"; //Clases que representan la información para llevar a cabo los procesos public class SplitInfo { string filepath; //Archivo a dividir public string FilePath { get { return filepath; } } int segmentsize; //Tamaño maximo que puede tener un pedazo public int SegmentSize { get { return segmentsize; } } string folderdestiny; //Carpeta donde depositaremos los pedazos de archivo public string FolderDestiny { get { return folderdestiny; } } NewLogCallback logcallback; public NewLogCallback LogCallback { get { return logcallback; } } ProcessChangesCallback processcallback; public ProcessChangesCallback ProcessCallback { get { return processcallback; } } FinishProcessCallback finishcallback; public FinishProcessCallback FinnishCallback { get { return finishcallback; } } FinishProcessBecauseErrorCallback errorcallback; public FinishProcessBecauseErrorCallback ErrorCallback { get { return errorcallback; } } public SplitInfo(string FilePath,string FolderDestiny, int SegmentSize, NewLogCallback LogCallback, ProcessChangesCallback ProcessCallback, FinishProcessCallback FinishCallback, FinishProcessBecauseErrorCallback errorCallback) { filepath=FilePath; folderdestiny=FolderDestiny; segmentsize = SegmentSize; logcallback=LogCallback; processcallback=ProcessCallback; finishcallback = FinishCallback; errorcallback = ErrorCallback; } } public class JoinInfo { string manifiestpath;//Path del archivo manifiesto, // los pedazos tienen que estar en la misma carpeta public string ManifiestPath { get { return manifiestpath; } } string folderdestiny; //Carpeta donde se reagruparan loa archivos public string FolderDestiny { get { return folderdestiny; } } NewLogCallback logcallback; public NewLogCallback LogCallback { get { return logcallback; } } ProcessChangesCallback processcallback; public ProcessChangesCallback ProcessCallback { get { return processcallback; } } FinishProcessCallback finishcallback; public FinishProcessCallback FinnishCallback { get { return finishcallback; } } FinishProcessBecauseErrorCallback errorcallback; public FinishProcessBecauseErrorCallback ErrorCallback { get { return errorcallback; } } public JoinInfo(string ManifiestPath, string FolderDestiny, NewLogCallback LogCallback, ProcessChangesCallback ProcessCallback, FinishProcessCallback FinishCallback, FinishProcessBecauseErrorCallback ErrorCallback) { manifiestpath = ManifiestPath; folderdestiny = FolderDestiny; logcallback = LogCallback; processcallback = ProcessCallback; finishcallback = FinishCallback; errorcallback = ErrorCallback; } } public static void JoinFile(object JoinInfo) { //definimos estas variables para que esten visible en el bloque finally //pudiendo liberar los recursos en caso de error StreamReader ManifiestReader=null; FileStream FileToJoin=null; FileStream Segment=null; //hacemos un cast para poder acceder a las propiedades JoinInfo info = (JoinInfo)JoinInfo; try { //Creamos una entrada en el log info.LogCallback("Obteniendo información del manifiesto", DateTime.Now); //Abrimos el archivo manifiesto ManifiestReader = new StreamReader(info.ManifiestPath); //Leemos los datos incluidos en el manifiesto string Filename = ManifiestReader.ReadLine(); //Nombre del archivo original, int SegmentSize = System.Convert.ToInt32(ManifiestReader.ReadLine()); //Tamaño maximo que pueden tener los pedazos int count = System.Convert.ToInt32(ManifiestReader.ReadLine()); //Numero de pedazos //Liberamos los recursos relaciónados con el archivo manifiesto ManifiestReader.Close(); //Creamos una entrada en el log info.LogCallback("Creando el archivo", DateTime.Now); //Creamos el archivo donde reagruparemos los pedazos, // recreando el archivo original string FilePath = info.FolderDestiny + @"\" + Filename; FileToJoin = new FileStream(FilePath, FileMode.Create, FileAccess.Write); //Creamos el buffer //Un arreglo de bytes byte[] buffer = new byte[SegmentSize-1]; //iteraremos extrayendo los bytes de cada pedazo // y los escribiremos en el nuevo archivo //Teniendo en cuenta que cada proceso de lectura (y escritura) hace avanzar //la posición del puntero en el archivo en cuestion, // este puntero no tiene nada que ver con los //punteros de c++ for (int i = 0; i <= count - 1; i++) { //Abrimos el pedazo string SegmentPath = Path.GetDirectoryName(info.ManifiestPath) + @"\" + Filename + "_" + i + SegmentExtension; Segment = new FileStream(SegmentPath, FileMode.Open, FileAccess.Read); //Leemos en origen y escribimos en destino int n = Segment.Read(buffer, 0, buffer.Length-1); FileToJoin.Write(buffer, 0, n); //Notificamos el avance del proceso info.ProcessCallback(n); //Creamos una entrada en el log info.LogCallback("Añadido segmento " + i, DateTime.Now); //liberamos los recursos relaciónados con el pedazo Segment.Close(); } //liberamos los recursos FileToJoin.Close(); //Creamos una entrada en el log info.LogCallback("El proceso ha finalizado", DateTime.Now); //Notificamos que el proceso ha terminado correctamente info.FinnishCallback(); } catch (Exception ex) { //liberamos todos los recursos //verificando antes que no sean referencias nulas if (FileToJoin != null)FileToJoin.Close(); if (ManifiestReader!= null) ManifiestReader.Close(); if (Segment != null) Segment.Close(); //Creamos una entrada en el log, expecificando el error info.LogCallback("El proceso a terminado por un error: " + ex.Message, DateTime.Now); //Notificamos que el proceso ha terminado debido a un error info.ErrorCallback(); } } public static void SplitFile(object SplitInfo) { //definimos estas variables para que esten visible en el bloque finally //pudiendo liberar los recursos en caso de error FileStream FileToSplit=null; FileStream Segment = null; StreamWriter ManifiestWriter = null; //hacemos un cast para poder acceder a las propiedades SplitInfo info = (SplitInfo)SplitInfo; try { int count = 0; // contador de segmentos string Filename = Path.GetFileName(info.FilePath); //Tomamos el nombre del archivo //Creamos una entrada en el log info.LogCallback("Abriendo el archivo a dividir", DateTime.Now); //Abrimos el archivo a dividir FileToSplit = new FileStream(info.FilePath, FileMode.Open, FileAccess.Read); //Creamos una entrada en el log info.LogCallback("Creando Buffer de lectura/escritura", DateTime.Now); //Creamos un buffer del tamaño en bytes del segmento byte[] buffer = new byte[info.SegmentSize-1]; //Iteraremos hasta haber alcanzado el fin del fichero a dividir //Teniendo en cuenta que cada proceso de lectura (y escritura) // hace avanzar segun el numero de bytes leidos/escritos //la posición del puntero sobre archivo en cuestion , // este puntero no tiene nada que ver con los //punteros de c++ while (FileToSplit.Position != FileToSplit.Length) { //Construimos el path del segmento string SegmentPath = info.FolderDestiny + @"\" + Filename + "_" + count + SegmentExtension; //Creamos el segmento Segment = new FileStream(SegmentPath, FileMode.Create, FileAccess.Write); //Leemos en origen y escribimos en destino int n = FileToSplit.Read(buffer, 0, buffer.Length-1); Segment.Write(buffer, 0, n); //Cerramos el segmento info.LogCallback("Creando segmento " + count, DateTime.Now); Segment.Close(); //Notificamos el avance del proceso info.ProcessCallback(n); //Aumentamos el contador de pedazos count++; } //Creamos el archivo manifiesto info.LogCallback("Creando manifiesto", DateTime.Now); string ManifiestPath = info.FolderDestiny + @"\" + Filename + ManifiestExtension; //escribimos la información necesaria para poder regrupar // los archivos posteriormente ManifiestWriter = new StreamWriter(ManifiestPath, false); ManifiestWriter.Write(Filename); ManifiestWriter.Write(ManifiestWriter.NewLine); ManifiestWriter.Write(info.SegmentSize); ManifiestWriter.Write(ManifiestWriter.NewLine); ManifiestWriter.Write(count); ManifiestWriter.Write(ManifiestWriter.NewLine); ManifiestWriter.Write(FileToSplit.Length); //Creamos una entrada en el log info.LogCallback("El proceso a finalizado, el archivo se ha dividido en " + count + " segmentos", DateTime.Now); //Notificamos que el proceso ha terminado correctamente info.FinnishCallback(); } catch (Exception ex) { //En caso de error, liberamos todos los recursos //verificando antes que no sean referencias nulas if (FileToSplit!=null) FileToSplit.Close(); if (ManifiestWriter != null) ManifiestWriter.Close(); if (Segment != null) Segment.Close(); //Creamos una entrada en el log, expecificando el error info.LogCallback("El proceso a terminado por un error: " + ex.Message, DateTime.Now); //Notificamos que el proceso ha terminado debido a un error info.ErrorCallback(); } } } } Imports System Imports System.Collections.Generic Imports System.Text Imports System.IO Imports System.Windows.Forms Imports System.Diagnostics Namespace Spliter Class SplitBoss 'Delegados Public Delegate Sub NewLogCallback(ByVal Message As String, ByVal Time As DateTime) 'Una nueva entrada en log Public Delegate Sub ProcessChangesCallback(ByVal Value As Integer) 'Avance del progreso Public Delegate Sub FinishProcessBecauseErrorCallback() 'Terminado el proceso por error Public Delegate Sub FinishProcessCallback() 'Terminado correctamente 'Definimos las extensiones Shared SegmentExtension As String = ".spt" Shared ManifiestExtension As String = ".mspt" 'Clases que representan la información para llevar a cabo los procesos Public Class SplitInfo Private m_filepath As String 'Archivo a dividir Public ReadOnly Property FilePath() As String Get Return m_filepath End Get End Property Private m_segmentsize As Integer 'Tamaño maximo que puede tener un pedazo Public ReadOnly Property SegmentSize() As Integer Get Return m_segmentsize End Get End Property Private m_folderdestiny As String 'Carpeta donde depositaremos los pedazos de archivo Public ReadOnly Property FolderDestiny() As String Get Return m_folderdestiny End Get End Property Private m_logcallback As NewLogCallback Public ReadOnly Property LogCallback() As NewLogCallback Get Return m_logcallback End Get End Property Private m_processcallback As ProcessChangesCallback Public ReadOnly Property ProcessCallback() As ProcessChangesCallback Get Return m_processcallback End Get End Property Private finishcallback As FinishProcessCallback Public ReadOnly Property FinnishCallback() As FinishProcessCallback Get Return finishcallback End Get End Property Private m_errorcallback As FinishProcessBecauseErrorCallback Public ReadOnly Property ErrorCallback() As _ FinishProcessBecauseErrorCallback Get Return m_errorcallback End Get End Property Public Sub New(ByVal FilePath As String, _ ByVal FolderDestiny As String, _ ByVal SegmentSize As Integer, _ ByVal LogCallback As NewLogCallback, _ ByVal ProcessCallback As ProcessChangesCallback, _ ByVal FinishCallback As FinishProcessCallback, _ ByVal errorCallback As FinishProcessBecauseErrorCallback) m_filepath = FilePath m_folderdestiny = FolderDestiny m_segmentsize = SegmentSize m_logcallback = LogCallback m_processcallback = ProcessCallback finishcallback = FinishCallback m_errorcallback = ErrorCallback End Sub End Class Public Class JoinInfo Private m_manifiestpath As String 'Path del archivo manifiesto, ' los pedazos tienen que estar en la misma carpeta Public ReadOnly Property ManifiestPath() As String Get Return m_manifiestpath End Get End Property Private m_folderdestiny As String 'Carpeta donde se reagruparan loa archivos Public ReadOnly Property FolderDestiny() As String Get Return m_folderdestiny End Get End Property Private m_logcallback As NewLogCallback Public ReadOnly Property LogCallback() As NewLogCallback Get Return m_logcallback End Get End Property Private m_processcallback As ProcessChangesCallback Public ReadOnly Property ProcessCallback() As ProcessChangesCallback Get Return m_processcallback End Get End Property Private finishcallback As FinishProcessCallback Public ReadOnly Property FinnishCallback() As FinishProcessCallback Get Return finishcallback End Get End Property Private m_errorcallback As FinishProcessBecauseErrorCallback Public ReadOnly Property ErrorCallback() As _ FinishProcessBecauseErrorCallback Get Return m_errorcallback End Get End Property Public Sub New(ByVal ManifiestPath As String, _ ByVal FolderDestiny As String, _ ByVal LogCallback As NewLogCallback, _ ByVal ProcessCallback As ProcessChangesCallback, _ ByVal FinishCallback As FinishProcessCallback, _ ByVal ErrorCallback As FinishProcessBecauseErrorCallback) m_manifiestpath = ManifiestPath m_folderdestiny = FolderDestiny m_logcallback = LogCallback m_processcallback = ProcessCallback finishcallback = FinishCallback m_errorcallback = ErrorCallback End Sub End Class Public Shared Sub JoinFile(ByVal JoinInfo As Object) 'definimos estas variables para que esten visible en el bloque finally 'pudiendo liberar los recursos en caso de error Dim ManifiestReader As StreamReader = Nothing Dim FileToJoin As FileStream = Nothing Dim Segment As FileStream = Nothing 'hacemos un cast para poder acceder a las propiedades Dim info As JoinInfo = DirectCast(JoinInfo, JoinInfo) Try 'Creamos una entrada en el log info.LogCallback("Obteniendo información del manifiesto", _ DateTime.Now) 'Abrimos el archivo manifiesto ManifiestReader = New StreamReader(info.ManifiestPath) 'Leemos los datos incluidos en el manifiesto Dim Filename As String = ManifiestReader.ReadLine() 'Nombre del archivo original, Dim SegmentSize As Integer = _ System.Convert.ToInt32(ManifiestReader.ReadLine()) 'Tamaño maximo que pueden tener los pedazos Dim count As Integer = _ System.Convert.ToInt32(ManifiestReader.ReadLine()) 'Numero de pedazos 'Liberamos los recursos relaciónados con el archivo manifiesto ManifiestReader.Close() 'Creamos una entrada en el log info.LogCallback("Creando el archivo", DateTime.Now) 'Creamos el archivo donde reagruparemos los pedazos, ' recreando el archivo original Dim FilePath As String = info.FolderDestiny + "\" + Filename FileToJoin = New FileStream(FilePath, FileMode.Create, _ FileAccess.Write) 'Creamos el buffer 'Un arreglo de bytes Dim buffer As Byte() = New Byte(SegmentSize - 1) {} For i As Integer = 0 To count - 1 'iteraremos extrayendo los bytes de cada pedazo y ' los escribiremos en el nuevo archivo 'Teniendo en cuenta que cada proceso de lectura (y escritura) ' hace avanzar 'la posición del puntero en el archivo en cuestion, ' este puntero no tiene nada que ver con los 'punteros de c++ 'Abrimos el pedazo Dim SegmentPath As String = _ Path.GetDirectoryName(info.ManifiestPath) + "\" + _ Filename + "_" + i + SegmentExtension Segment = New FileStream(SegmentPath, FileMode.Open, _ FileAccess.Read) 'Leemos en origen y escribimos en destino Dim n As Integer = Segment.Read(buffer, 0, buffer.Length - 1) FileToJoin.Write(buffer, 0, n) 'Notificamos el avance del proceso info.ProcessCallback(n) 'Creamos una entrada en el log info.LogCallback("Añadido segmento " + i, DateTime.Now) 'liberamos los recursos relaciónados con el pedazo Segment.Close() Next 'liberamos los recursos FileToJoin.Close() 'Creamos una entrada en el log info.LogCallback("El proceso ha finalizado", DateTime.Now) 'Notificamos que el proceso ha terminado correctamente info.FinnishCallback() Catch ex As Exception 'liberamos todos los recursos 'verificando antes que no sean referencias nulas If FileToJoin IsNot Nothing Then FileToJoin.Close() End If If ManifiestReader IsNot Nothing Then ManifiestReader.Close() End If If Segment IsNot Nothing Then Segment.Close() End If 'Creamos una entrada en el log, expecificando el error info.LogCallback("El proceso a terminado por un error: " + _ ex.Message, DateTime.Now) 'Notificamos que el proceso ha terminado debido a un error info.ErrorCallback() End Try End Sub Public Shared Sub SplitFile(ByVal SplitInfo As Object) 'definimos estas variables para que esten visible en el bloque finally 'pudiendo liberar los recursos en caso de error Dim FileToSplit As FileStream = Nothing Dim Segment As FileStream = Nothing Dim ManifiestWriter As StreamWriter = Nothing 'hacemos un cast para poder acceder a las propiedades Dim info As SplitInfo = DirectCast(SplitInfo, SplitInfo) Try Dim count As Integer = 0 ' contador de segmentos Dim Filename As String = Path.GetFileName(info.FilePath) 'Tomamo el nombre del archivo 'Creamos una entrada en el log info.LogCallback("Abriendo el archivo a dividir", DateTime.Now) 'Abrimos el archivo a dividir FileToSplit = New FileStream(info.FilePath, FileMode.Open, _ FileAccess.Read) 'Creamos una entrada en el log info.LogCallback("Creando Buffer de lectura/escritura", _ DateTime.Now) 'Creamos un buffer del tamaño en bytes del segmento Dim buffer As Byte() = New Byte(info.SegmentSize - 1) {} 'Iteraremos hasta haber alcanzado el fin del fichero a dividir 'Teniendo en cuenta que cada proceso de lectura (y escritura) ' hace avanzar segun el numero de bytes leidos/escritos 'la posición del puntero sobre archivo en cuestion , ' este puntero no tiene nada que ver con los 'punteros de c++ While FileToSplit.Position <> FileToSplit.Length 'Construimos el path del segmento Dim SegmentPath As String = info.FolderDestiny + "\" + _ Filename + "_" + count + SegmentExtension 'Creamos el segmento Segment = New FileStream(SegmentPath, FileMode.Create, _ FileAccess.Write) 'Leemos en origen y escribimos en destino Dim n As Integer = FileToSplit.Read(buffer, 0, _ buffer.Length - 1) Segment.Write(buffer, 0, n) 'Cerramos el segmento info.LogCallback("Creando segmento " + count, DateTime.Now) Segment.Close() 'Notificamos el avance del proceso info.ProcessCallback(n) 'Aumentamos el contador de pedazos count += 1 End While 'Creamos el archivo manifiesto info.LogCallback("Creando manifiesto", DateTime.Now) Dim ManifiestPath As String = info.FolderDestiny + "\" + _ Filename + ManifiestExtension 'escribimos la información necesaria para poder ' regrupar los archivos posteriormente ManifiestWriter = New StreamWriter(ManifiestPath, False) ManifiestWriter.Write(Filename) ManifiestWriter.Write(ManifiestWriter.NewLine) ManifiestWriter.Write(info.SegmentSize) ManifiestWriter.Write(ManifiestWriter.NewLine) ManifiestWriter.Write(count) ManifiestWriter.Write(ManifiestWriter.NewLine) ManifiestWriter.Write(FileToSplit.Length) 'Creamos una entrada en el log info.LogCallback( _ "El proceso a finalizado, el archivo se ha dividido en " + _ count + " segmentos", DateTime.Now) 'Notificamos que el proceso ha terminado correctamente info.FinnishCallback() Catch ex As Exception 'En caso de error, liberamos todos los recursos 'verificando antes que no sean referencias nulas If FileToSplit IsNot Nothing Then FileToSplit.Close() End If If ManifiestWriter IsNot Nothing Then ManifiestWriter.Close() End If If Segment IsNot Nothing Then Segment.Close() End If 'Creamos una entrada en el log, expecificando el error info.LogCallback("El proceso a terminado por un error: " + _ ex.Message, DateTime.Now) 'Notificamos que el proceso ha terminado debido a un error info.ErrorCallback() End Try End Sub End Class End Namespace Bueno, esta un poco largo, pero solo viéndolo completo podemos entender la otra parte, que es ya la interfaz de la aplicación. Para no extendernos veamos solamente el formulario para Segmentar:
El código del botón comenzar es el siguiente, obsérvese como se crea un hilo, y al ejecutar el método Start le pasamos un objeto de tipo SplitInfo: private void btnComenzar_Click(object sender, EventArgs e) { this.gpbOpciónes.SendToBack(); this.gpbProceso.BringToFront(); this.pgbProceso.Maximum = (int)tamañoArchivo; this.btnComenzar.Visible = false; if (unHilo == null) unHilo = new Thread(SplitBoss.SplitFile); unHilo.Start(new SplitBoss.SplitInfo(this.txtOrigen.Text, txtDestino.Text, (int)this.nudTamañoSegmento.Value, new SplitBoss.NewLogCallback(EscribirLog), new SplitBoss.ProcessChangesCallback(AumentarProceso), new SplitBoss.FinishProcessCallback(EmitirFinDeProcesoExitoso), new SplitBoss.FinishProcessBecauseErrorCallback(EmitirFinConError))); this.btnComenzar.Enabled = false; } Private Sub btnComenzar_Click(ByVal sender As Object, ByVal e As EventArgs) Me.gpbOpciónes.SendToBack() Me.gpbProceso.BringToFront() Me.pgbProceso.Maximum = DirectCast(tamañoArchivo, Integer) Me.btnComenzar.Visible = False If unHilo Is Nothing Then unHilo = New Thread(SplitBoss.SplitFile) End If unHilo.Start(New SplitBoss.SplitInfo(Me.txtOrigen.Text, txtDestino.Text, _ DirectCast(Me.nudTamañoSegmento.Value, Integer), _ New SplitBoss.NewLogCallback(EscribirLog), _ New SplitBoss.ProcessChangesCallback(AumentarProceso), _ New SplitBoss.FinishProcessCallback(EmitirFinDeProcesoExitoso), _ New SplitBoss.FinishProcessBecauseErrorCallback(EmitirFinConError))) Me.btnComenzar.Enabled = False End Sub TerminandoBueno, espero que este articulo les haya sido de utilidad, y cualquier critica o sugerencia me la pueden hacer al correo, un salu2 a todos Espacios de nombres usados en el código de este artículo:System.Windows.Forms
|
Código de ejemplo (ZIP): |
Fichero con el código de ejemplo: horacio_splitter_cs.zip -
97.5 KB
|