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:33] fmt.Println(ToHexBytes(transactionId)) var tranId = ToHexBytes(transactionId) if commandId == 0 { InfoTransaction(info, msg, tranId) } else if commandId == 1 { err := InfoTransactionSplit(info, msg, tranId) fmt.Println(err) } //1. 接收基本元数据(事务id(32),len文件名(4+?),文件大小(8),相对路径(4+?),分片数量(按特定大小进行分片)(4),创建时间(8),修改时间(8),访问时间(8)=> 返回事务id,如果重复则返回错误 76+? //2. 接收包含事务id的分片内容 } // InfoTransaction 获取的事务数据内容 func InfoTransaction(info *ConnInfo, msg []byte, transactionId string) 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 fileNameLength = binary.BigEndian.Uint32(msg[33:37]) var filename = string(msg[37 : 37+fileNameLength]) var fileSize = int64(binary.BigEndian.Uint64(msg[37+fileNameLength : 45+fileNameLength])) var pathLength = binary.BigEndian.Uint32(msg[45+fileNameLength : 49+fileNameLength]) var path = string(msg[49+fileNameLength : 49+fileNameLength+pathLength]) path = fmt.Sprint(config.Conf.File.Upload.Path, "/", fileUser.UserId, "/", transactionId, "/", path) var splitCount = binary.BigEndian.Uint32(msg[49+fileNameLength+pathLength : 53+fileNameLength+pathLength]) var createTime = binary.BigEndian.Uint64(msg[53+fileNameLength+pathLength : 61+fileNameLength+pathLength]) var modifyTime = binary.BigEndian.Uint64(msg[61+fileNameLength+pathLength : 69+fileNameLength+pathLength]) var accessTime = binary.BigEndian.Uint64(msg[69+fileNameLength+pathLength : 77+fileNameLength+pathLength]) Type := "" if fileSize == -1 { Type = "folder" } else { Type = "file" } ExtensionName := "" index := strings.Index(filename, ".") if index != -1 { ExtensionName = filename[index+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) 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 splitNum = binary.BigEndian.Uint32(msg[33:37]) var pathLength = binary.BigEndian.Uint32(msg[37:41]) var path = string(msg[41 : 41+pathLength]) path = fmt.Sprint(config.Conf.File.Upload.Path, "/", fileUser.UserId, "/", transactionId, "/", path) var content = msg[41+pathLength:] 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) }