| 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
|