使用的是设计模式有:
行为型:观察者,状态。 暂且这么多
后期有进行了通用分割方便的重构。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace FileSplitter
{
public class Splitter
{
public SplitterState CurSplitState { get; set; }
public string ModelName { get; set; }
public Action<float> NotifyProgress { get; set; }
public Action<float> NotifyCombinePro { get; set; }
public Dictionary<SplitterType, SplitterState> SplitterStateDic { get; set; }
public float MaxFileSize { get; set; }
public SaveParam SaveInfo { get; protected set; }
/// <summary>
/// 方法参数信息
/// </summary>
public List<object> StartSpliteFileParam { get; private set; }
public Splitter()
{
InitStateDic();
this.MaxFileSize = 5;
this.ModelName = string.Empty;
CurSplitState = SplitterStateDic[SplitterType.FilePathState];
}
private void InitStateDic()
{
this.SplitterStateDic = new Dictionary<SplitterType, SplitterState>();
SplitterStateDic.Add(SplitterType.FilePathState, new SplitterStatePath());
SplitterStateDic.Add(SplitterType.MomoryState, new SplitterStateMemory());
StartSpliteFileParam = new List<object>();
}
public void AddNotifyProgress(Action<float> actionNotify)
{
this.NotifyProgress += actionNotify;
}
/// <summary>
/// 设置成功保存信息,然后在分割文件
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public bool SetSaveInfo(SaveParam param)
{
if (!Directory.Exists(param.FloderDir) || !param.FileSuffix.StartsWith(".") || string.IsNullOrEmpty(param.FileName))
{
return false;
}
param.VaildFlag = true;
this.SaveInfo = param;
return true;
}
#region 分割文件
public bool StartSpliteFile(string filePath, uint spliteNu)
{
if (!SaveInfo.VaildFlag || !File.Exists(filePath))
{
return false;
}
bool spliteReslut = false;
lock (ModelName)
{
CheckCurSate(SplitterType.FilePathState);
StartSpliteFileParam.Clear();
StartSpliteFileParam.Add(filePath);
StartSpliteFileParam.Add((int)spliteNu);
try
{
spliteReslut = CurSplitState.SplitFile(this);
}
catch (Exception)
{}
}
return spliteReslut;
}
public bool StartSpliteFile(byte[] buffer, uint spliteNu)
{
if (!SaveInfo.VaildFlag || !OverLoadMaxFileSize(buffer.Length))
{
return false;
}
bool spliteReslut = false;
lock (ModelName)
{
var curType = SplitterType.MomoryState;
if (CurSplitState.CurType != curType)
{
CurSplitState = this.SplitterStateDic[curType];
}
StartSpliteFileParam.Clear();
StartSpliteFileParam.Add(buffer);
StartSpliteFileParam.Add((int)spliteNu);
try
{
spliteReslut = CurSplitState.SplitFile(this);
}
catch (Exception)
{ }
}
return spliteReslut;
}
internal bool OverLoadMaxFileSize(float bytesNumber)
{
float fileSizeM = bytesNumber / 1024 / 1024;
return fileSizeM > MaxFileSize;
}
#endregion
#region 合并文件
public bool CombineFiles(List<string> pathList)
{
if (!SaveInfo.VaildFlag)
{
return false;
}
bool ret = false;
lock (ModelName)
{
CheckCurSate(SplitterType.FilePathState);
StartSpliteFileParam.Clear();
StartSpliteFileParam.Add(pathList);
ret = CurSplitState.CombineFile(this);
}
return ret;
}
public bool CombineFiles(List<byte[]> bytesLs)
{
if (!SaveInfo.VaildFlag)
{
return false;
}
bool ret = false;
lock (ModelName)
{
CheckCurSate(SplitterType.MomoryState);
StartSpliteFileParam.Clear();
StartSpliteFileParam.Add(bytesLs);
ret = CurSplitState.CombineFile(this);
}
return ret;
}
#endregion
internal bool SaveFile(byte[] buf, int length, int index)
{
string saveFilePath = this.SaveInfo.CompoundPath(index.ToString());
if (string.IsNullOrEmpty(saveFilePath) || length > buf.Length)
{
return false;
}
try
{
if (buf.Length == length)
{
File.WriteAllBytes(saveFilePath, buf);
}
else
{
byte[] bts = new byte[length];
Array.Copy(buf, 0, bts, 0, bts.Length);
File.WriteAllBytes(saveFilePath, bts);
}
}
catch (Exception)
{
return false;
}
return true;
}
//追加到已经存在数据后边
internal bool SaveFile(byte[] buf)
{
string saveFilePath = this.SaveInfo.CompoundPath(string.Empty);
if (string.IsNullOrEmpty(saveFilePath))
{
return false;
}
if (!File.Exists(saveFilePath))
{
using (File.Create(saveFilePath))
{
}
}
using (FileStream fs = new FileStream(saveFilePath, FileMode.Append, FileAccess.Write))
{
try
{
fs.Write(buf, 0, buf.Length);
}
catch (Exception)
{
return false;
}
}
return true;
}
void CheckCurSate(SplitterType type)
{
if (type != CurSplitState.CurType && this.SplitterStateDic.ContainsKey(type))
{
CurSplitState = SplitterStateDic[type];
}
}
/// <summary>
/// 通知订阅对象当前进度
/// </summary>
/// <param name="f">当前进度</param>
/// <param name="notityType">1通知分割进度,2通知合并进度</param>
public void NotifyEvent(float f, int notityType)
{
if (notityType == 1)
{
if (this.NotifyProgress != null)
{
NotifyProgress(f);
}
}
else if (notityType == 2)
{
if (NotifyCombinePro != null)
{
NotifyCombinePro(f);
}
}
}
}
public abstract class SplitterState
{
public virtual SplitterType CurType { get; }
public float CurrentProgress { get; protected set; }
public abstract bool SplitFile(Splitter splitter);
public abstract bool CombineFile(Splitter splitter);
protected virtual bool CommonSpliteRAS(int loopNu, Stream fs, Splitter sp)
{
if (fs == null || !sp.OverLoadMaxFileSize(fs.Length))
{
return false;
}
CurrentProgress = 0f;
sp.NotifyEvent(CurrentProgress, 1);
//1.计算每个文件大小
int singleSizeBytes = (int)fs.Length / loopNu;
int lastFileSizeBytes = (int)fs.Length % loopNu;
byte[] tempBts = new byte[singleSizeBytes];
if (lastFileSizeBytes > 0)
{
loopNu++;
}
for (int idx = 0; idx < loopNu; idx++)
{
int readNu = fs.Read(tempBts, 0, tempBts.Length);
sp.SaveFile(tempBts, readNu, idx);
; //通知完整进度
CurrentProgress = (float)((idx + 1) * 1.0 / loopNu);
sp.NotifyEvent(CurrentProgress, 1);
}
return true;
}
}
//内存文件分割器
public class SplitterStateMemory : SplitterState
{
public override bool SplitFile(Splitter splitter)
{
//0.获取参数信息
byte[] buffer = (byte[])splitter.StartSpliteFileParam[0];
int loopNu = (int)splitter.StartSpliteFileParam[1];
#region 第一种计算方式
1.计算每个文件大小
//int singleSizeBytes = buffer.Length / loopNu;
//int lastFileSizeBytes = buffer.Length % loopNu;
//byte[] tempBts = new byte[singleSizeBytes];
//if (lastFileSizeBytes > 0)
//{
// loopNu++;
//}
//for (int idx = 0; idx < loopNu; idx++)
//{
// int startPos = idx * tempBts.Length;
// //2. 判断数据长度是否够array copy
// if (startPos + tempBts.Length > buffer.Length)
// {
// Array.Copy(buffer, startPos, tempBts, 0, lastFileSizeBytes);
// splitter.SaveFile(tempBts, lastFileSizeBytes, idx);
// }
// else
// {
// Array.Copy(buffer, startPos, tempBts, 0, tempBts.Length);
// splitter.SaveFile(tempBts, tempBts.Length, idx);
// }
// //通知完整进度
// CurrentProgress = (float)((idx + 1) * 1.0 / loopNu);
// splitter.NotifyEvent(CurrentProgress, 1);
//}
//return true;
#endregion
MemoryStream ms = new MemoryStream(buffer);
bool operal = CommonSpliteRAS(loopNu, ms, splitter);
ms.Close();
ms.Dispose();
return operal;
}
public override bool CombineFile(Splitter splitter)
{
this.CurrentProgress = 0f;
splitter.NotifyEvent(CurrentProgress, 2);
//1.获取参数信息
List<byte[]> splitFiles = (List<byte[]>)splitter.StartSpliteFileParam[0];
string savePath = splitter.SaveInfo.CompoundPath(string.Empty);
int curIdx = 1;
foreach (byte[] itemBuf in splitFiles)
{
bool ret = splitter.SaveFile(itemBuf);
if (!ret)
{
return false;
}
this.CurrentProgress = (float)(curIdx * 1.0 / splitFiles.Count);
splitter.NotifyEvent(CurrentProgress, 2);
curIdx++;
}
return true;
}
public override SplitterType CurType => SplitterType.MomoryState;
}
//文件路径分割器
public class SplitterStatePath : SplitterState
{
public override SplitterType CurType => SplitterType.FilePathState;
public override bool CombineFile(Splitter splitter)
{
this.CurrentProgress = 0f;
splitter.NotifyEvent(CurrentProgress, 2);
//1.获取参数信息
List<string> splitPath = (List<string>)splitter.StartSpliteFileParam[0];
string savePath = splitter.SaveInfo.CompoundPath(string.Empty);
int curIdx = 1;
foreach (string itemStr in splitPath)
{
bool ret = splitter.SaveFile(File.ReadAllBytes(itemStr));
if (!ret)
{
return false;
}
this.CurrentProgress = (float)(curIdx * 1.0 / splitPath.Count);
splitter.NotifyEvent(CurrentProgress, 2);
curIdx++;
}
return true;
}
public override bool SplitFile(Splitter splitter)
{
//1.获取参数信息
string path = (string)splitter.StartSpliteFileParam[0];
int loopNu = (int)splitter.StartSpliteFileParam[1];
FileStream fs = File.OpenRead(path);
bool ret = this.CommonSpliteRAS(loopNu, fs, splitter);
fs.Close();
fs.Dispose();
return ret;
}
}
public enum SplitterType
{
MomoryState,
FilePathState,
}
public struct SaveParam
{
public string FloderDir { get; set; }
public string FileName { get; set; }
public string FileSuffix { get; set; }
public bool VaildFlag { get; set; }
public string CompoundPath(string id)
{
if (VaildFlag)
{
return Path.Combine(FloderDir, string.Format("{0}{1}{2}", FileName, id, FileSuffix));
}
else
{
return string.Empty;
}
}
}
}
可能还有很多不完善的地方,不足之处,请加指教。