package server import ( "encoding/binary" "errors" "file-manger-server/config" "file-manger-server/db" "file-manger-server/domain" "fmt" "io" "os" "strings" ) type ReturnCommand interface { Return() []byte } func HandlerReceiveFile(info *ConnInfo, msg []byte) { var commandId = msg[0] //事务id解析 var transactionId = msg[1:17] fmt.Println(ToHexBytes(transactionId)) var tranId = ToHexBytes(transactionId) if commandId == 0 { InfoTransaction(info, msg, tranId, 16) } else if commandId == 1 { err := InfoTransactionSplit(info, msg, tranId, 16) fmt.Println(err) } } // InfoTransaction 获取的事务数据内容 func InfoTransaction(info *ConnInfo, msg []byte, transactionId string, transactionIdLen int) error { // 获取数据,判断事务是否注册 fileUser, err := db.FileUserDao{}.Get(transactionId) if err != nil { return errors.New("FileUser transactionId is not found") } // 判断用户是否存在 if fileUser.UserId == 0 { return errors.New("FileUser userId is not found") } var index = transactionIdLen + 1 // 文件名称长度 var fileNameLength = binary.BigEndian.Uint32(msg[index : index+4]) index += 4 // 文件名 var filename = string(msg[index : uint32(index)+fileNameLength]) index += int(fileNameLength) // 文件大小 var fileSize = int64(binary.BigEndian.Uint64(msg[index : index+8])) index += 8 // 路径长度 var pathLength = binary.BigEndian.Uint32(msg[index : index+4]) index += 4 // 路径 var path = string(msg[index : index+int(pathLength)]) index += int(pathLength) // 添加专属路径 前缀 path = fmt.Sprint(config.Conf.File.Upload.Path, "/", fileUser.UserId, "/", transactionId, "/", path) // 分片数量,文件被拆分了几份 var splitCount = binary.BigEndian.Uint32(msg[index : index+4]) index += 4 // 创建时间,修改时间,访问时间 var createTime = binary.BigEndian.Uint64(msg[index : index+8]) index += 8 var modifyTime = binary.BigEndian.Uint64(msg[index : index+8]) index += 8 var accessTime = binary.BigEndian.Uint64(msg[index : index+8]) index += 8 Type := "" if fileSize == -1 { Type = "folder" } else { Type = "file" } //文件扩展名 ExtensionName := "" suffixIndex := strings.Index(filename, ".") if suffixIndex != -1 { ExtensionName = filename[suffixIndex+1:] } //填充数据 file := domain.File{ Name: filename, Url: path, Size: fileSize, Type: Type, MD5: "", TransactionId: transactionId, Extension: ExtensionName, Access: domain.FileAccess{}, CreateUser: 0, CreateTime: int64(createTime), UpdateTime: int64(modifyTime), } //添加元素 db.FileDao{}.Insert(file) //递归创建前面的文件夹 lastIndex := strings.LastIndex(path, "/") if lastIndex != -1 { err := os.MkdirAll(path[:lastIndex], 0755) if err != nil { return err } } if splitCount == 0 { if fileSize >= 0 { //打开文件 openFile, err := os.Create(path) if err != nil { fmt.Println("err:", err) } defer openFile.Close() var content = msg[77+fileNameLength+pathLength:] openFile.Write(content) } else { err := os.Mkdir(path, 0755) if err != nil { fmt.Println(err) } } } else { // 创建一个空文件 file, err := os.Create(path) if err != nil { fmt.Println("Error creating file:", err) return err } defer file.Close() // 确保在函数结束时关闭文件 fmt.Println("file size :", fileSize) err = file.Truncate(fileSize) if err != nil { fmt.Println("Error setting file size:", err) return err } } // 返回状态信息 //info.conn.Write() fmt.Println(fmt.Sprintf("事务id:%d\n文件名:%s\n文件大小:%d\n相对路径:%s\n分片数量:%d\n创建时间:%d\n修改时间:%d\n访问时间:%d", transactionId, filename, fileSize, path, splitCount, createTime, modifyTime, accessTime)) return nil } // InfoTransactionSplit 获取的事务数据内容 func InfoTransactionSplit(info *ConnInfo, msg []byte, transactionId string, transactionIdLen int) error { fileUser, err := db.FileUserDao{}.Get(transactionId) if err != nil { return errors.New("FileUser transactionId is not found") } if fileUser.UserId == 0 { return errors.New("FileUser userId is not found") } var index = transactionIdLen + 1 var splitNum = binary.BigEndian.Uint32(msg[index : index+4]) index += 4 var pathLength = binary.BigEndian.Uint32(msg[index : index+4]) index += 4 var path = string(msg[index : index+int(pathLength)]) index += int(pathLength) path = fmt.Sprint(config.Conf.File.Upload.Path, "/", fileUser.UserId, "/", transactionId, "/", path) var content = msg[index:] err = insertDataAtPosition(path, int64(splitNum*1024), content) return err // 返回状态信息 //info.conn.Write() //fmt.Println(fmt.Sprintf("事务id:%d\n文件名:%s\n文件大小:%d\n相对路径:%s\n分片数量:%d\n创建时间:%d\n修改时间:%d\n访问时间:%d", transactionId, filename, fileSize, path, splitCount, createTime, modifyTime, accessTime)) } var sign = 0 func insertDataAtPosition(filePath string, position int64, data []byte) error { // 1. 打开文件 file, err := os.OpenFile(filePath, os.O_RDWR, 0644) if err != nil { return fmt.Errorf("error opening file: %v", err) } defer file.Close() // 2. 获取文件元数据 fileInfo, err := file.Stat() if err != nil { return fmt.Errorf("error getting file info: %v", err) } fileSize := fileInfo.Size() // 3. 校验插入位置 if position > fileSize { return fmt.Errorf("position exceeds file size") } // 4. 计算需要移动的数据量 //originalDataLength := fileSize - position insertLength := int64(len(data)) // 5. 分块移动原始数据(从后往前处理) //var offset int64 = position //for offset > 0 { // 定位读取位置 readPos := position // 读取块数据 buffer := make([]byte, insertLength) _, err = file.ReadAt(buffer, readPos) if err != nil && err != io.EOF { return fmt.Errorf("read block error: %v", err) } sign += 1 fmt.Println("buffer len :", len(buffer), " sign => ", sign) // 写入新位置 _, err = file.WriteAt(buffer, readPos) if err != nil { return fmt.Errorf("write block error: %v", err) } fmt.Println("writePos ind :", readPos+int64(len(buffer))) //} // 6. 写入新数据 _, err = file.WriteAt(data, position) if err != nil { return fmt.Errorf("write data error: %v", err) } // 7. 扩展文件大小(如果需要) //newSize := fileSize + insertLength //if newSize > fileSize { // if err := file.Truncate(newSize); err != nil { // return fmt.Errorf("truncate error: %v", err) // } //} return nil } func ToHexBytes(bytes []byte) string { var hexBytes string for b := range bytes { hexBytes = fmt.Sprint(hexBytes, fmt.Sprintf("%02X", bytes[b])) } return strings.TrimSpace(hexBytes) }