昨天完成了dfs批量上传文件的服务器端程序,再第一时间就拿出来共享了。当然了,程序比较乱,那是因为我调试的一些信息都留在里面了,是原汁原味的东西,包括一些注释什么的都没有删除,我认为这些东西应该能起到让人更快理解程序的作用,所以就全部放出来了。当然了也有可能注释的错的,大家见谅啊。
今天完成了客户端程序,因为我主要是做net开发的,所以在dfs没有net客户端的情况下就自己按照我们的业务自己写了一个客户端,今天先把net的批上传文件代码拿出来,也是原汁原味的,没有经过调试的时候任何更改的。
/// <summary> /// 批量上传文件. /// </summary> /// <param name="groupName">Name of the group.</param> /// <param name="filesCount">The files count.</param> /// <param name="localFileName">Name of the local file.</param> /// <param name="buffer">The buffer.</param> /// <param name="extension">The extension.</param> /// <returns></returns> protected static string[] DoBatchUpload(string groupName, IList<byte[]> filesBuffer, string[] filesExtension) { int filesCount = filesBuffer.Count; if (255 < filesCount) { if (null != _logger) { _logger.ErrorFormat("批量上传文件的数量为:{0},超出了限定批上传文件数(限定批上传文件数为),请分多次上传.", filesCount); throw new Exception("上传文件数超出批处理限制范围!"); } } if (null != _logger) { _logger.InfoFormat("开始批量上传文件,批量上传文件的总数为:{0}.", filesCount); } TcpConnection storageConnection = GetStorageConnection(groupName); if (null != _logger) _logger.InfoFormat("Storage服务器的IP是:{0}.端口为{1}", storageConnection.IpAddress, storageConnection.Port); if (filesBuffer.Count != filesExtension.Length) { if (null != _logger) _logger.ErrorFormat("上传文件数组与上传文件扩展名,上传文件数组长度为{0},文件扩展名数组长度为{1}。", filesBuffer.Count, filesExtension.Length); throw new Exception("上传文件数不匹配。"); } //构建扩展名传输流 byte[] filesExtensionBuffer = new byte[Protocol.FDFS_FILE_EXT_NAME_MAX_LEN * filesCount]; byte[] fileExtensionBuffer = new byte[Protocol.FDFS_FILE_EXT_NAME_MAX_LEN]; byte[] fileTempExtensionBuffer; for (int i = 0; i < filesExtension.Length; i++) { if (string.IsNullOrEmpty(filesExtension[i])) { if (null != _logger) _logger.Error("文件扩展名为空,终止文件上传。"); throw new Exception("未获得文件扩展名。"); } fileTempExtensionBuffer = Encoding.GetEncoding(FastDFSService.Charset).GetBytes(filesExtension[i]); int fileExtBufferLength = fileTempExtensionBuffer.Length; if (fileExtBufferLength > Protocol.FDFS_FILE_EXT_NAME_MAX_LEN) fileExtBufferLength = Protocol.FDFS_FILE_EXT_NAME_MAX_LEN; //协议归整 Array.Copy(fileTempExtensionBuffer, 0, fileExtensionBuffer, 0, fileExtBufferLength); //加入网络传输 Array.Copy(fileExtensionBuffer, 0, filesExtensionBuffer, i * Protocol.FDFS_FILE_EXT_NAME_MAX_LEN, fileExtBufferLength); } //构建文件传输流 long filesBufferLength = 0L; foreach (byte[] fileBuffer in filesBuffer) { filesBufferLength += fileBuffer.LongLength; } //构建文件数量字节流 byte[] filesCountBuffer = Util.LongToBuffer(filesCount); //构建头部协议块 // Protocol.TRACKER_PROTO_PKG_LEN_SIZE * (filesCount + 2) 各个文件的长度+扩展名字节流的长度+文件字节流总共的长度 byte[] headerBuffer = new byte[1 + Protocol.TRACKER_PROTO_PKG_LEN_SIZE * (filesCount + 2)]; headerBuffer[0] = (byte)storageConnection.Index;//第一位为storage的index byte[] temp; //每位表示每个文件的字节流长度 for (int i = 0; i < filesBuffer.Count; i++) { temp = Util.LongToBuffer(filesBuffer[i].LongLength); Array.Copy(temp, 0, headerBuffer, 1 + i * Protocol.TRACKER_PROTO_PKG_LEN_SIZE, temp.LongLength); } temp = Util.LongToBuffer(filesExtensionBuffer.LongLength);//扩展名总共的长度 Array.Copy(temp, 0, headerBuffer, 1 + filesBuffer.Count * Protocol.TRACKER_PROTO_PKG_LEN_SIZE, temp.LongLength); temp = Util.LongToBuffer(filesBufferLength);//文件字节流长度 Array.Copy(temp, 0, headerBuffer, 1 + (filesBuffer.Count + 1) * Protocol.TRACKER_PROTO_PKG_LEN_SIZE, temp.LongLength); //构建协议传输流 byte[] protocalBuffer = Util.PackHeader(Protocol.STORAGE_PROTO_CMD_Batch_UPLOAD, //长度构成:一位storage的index+每个文件的字节长度+文件扩展名的总长度+文件字节的总长度 headerBuffer.Length + filesCountBuffer.Length + filesExtensionBuffer.Length + filesBufferLength, 0); _logger.InfoFormat("上传字节数为:{0}", headerBuffer.Length + filesCountBuffer.Length + filesExtensionBuffer.Length + filesBufferLength); Stream outStream = storageConnection.GetStream(); outStream.Write(protocalBuffer, 0, protocalBuffer.Length); outStream.Write(filesCountBuffer, 0, filesCountBuffer.Length); outStream.Write(headerBuffer, 0, headerBuffer.Length); outStream.Write(filesExtensionBuffer, 0, filesExtensionBuffer.Length); foreach (byte[] buffer in filesBuffer) { outStream.Write(buffer,0,buffer.Length); } Stream readStream; int fileNameBufferLength = Protocol.TRACKER_PROTO_PKG_LEN_SIZE + 128;//文件名长度+文件名内容 byte[] tempBuffer; int tempReadSize = 0; int fileNameSize; byte[] tempFileNameBytes; char[] chars; int error; string[] filesName = new string[filesCount]; for(int i = 0;i<filesCount;i++) { readStream = storageConnection.GetStream(); tempBuffer = new byte[Protocol.TRACKER_PROTO_PKG_LEN_SIZE + 128]; tempReadSize = readStream.Read(tempBuffer, 0, fileNameBufferLength); if(tempReadSize != fileNameBufferLength) { if(tempReadSize == 10)//文件未传输完成出现错误 { error = tempBuffer[Protocol.PROTO_HEADER_STATUS_INDEX]; if (null != _logger) _logger.ErrorFormat("上传文件中间发生异常,文件位置为:{0}.错误号为:{1}", i + 1, error); throw new Exception("上传文件错误!"); } if (null != _logger) _logger.ErrorFormat("上传文件中间发生异常,文件位置为:{0}.未能返回错误号,错误header长度为:{1}", i + 1, tempReadSize); throw new Exception("上传文件错误!"); } fileNameSize = (int)Util.BufferToLong(tempBuffer, 0); tempFileNameBytes = new byte[fileNameSize]; Array.Copy(tempBuffer, Protocol.TRACKER_PROTO_PKG_LEN_SIZE, tempFileNameBytes, 0, fileNameSize); chars = Util.ToCharArray(tempFileNameBytes); filesName[i] = new string(chars, 0, fileNameSize).Trim('\0').Trim(); } readStream = storageConnection.GetStream(); tempBuffer = new byte[10]; tempReadSize = readStream.Read(tempBuffer, 0, 10); if (10 != tempReadSize) { if (null != _logger) _logger.ErrorFormat("文件上传完毕,并且文件路径已经全部返回客户端。但是发生服务器传输信息头错误。错误header长度为:{0}", tempReadSize); } error = tempBuffer[Protocol.PROTO_HEADER_STATUS_INDEX]; if (0 != error) { if (null != _logger) _logger.ErrorFormat("文件上传完毕,并且文件路径已经全部返回客户端。但是服务器发生错误。错误号:{0}",error); } return filesName; }
写这个程序的时候呢,因为是和服务器端程序一并调试用的,所以主要考虑了程序的完成功能程度,没有考虑性能,clr-gc等等这些东西。但是性能应该不会太差,clr的gc可能会忙一点。大家有兴趣的话,可以自己优化一下,其实这种东西不难的。