[转]smbclient 使用方法

SMBClient命令详解
本文介绍了如何使用SMBClient命令来访问远程主机上的共享资源。包括列出共享文件夹、使用类似FTP的方式进行文件操作、直接执行命令以及通过挂载方式访问远程共享文件夹的方法。
1,列出某个IP地址所提供的共享文件夹
smbclient -L 198.168.0.1 -U username%password

2,像FTP客户端一样使用smbclient
smbclient //192.168.0.1/tmp -U username%password

执行smbclient命令成功后,进入smbclient环境,出现提示符: smb:\>
这里有许多命令和ftp命令相似,如cd 、lcd、get、megt、put、mput等。通过这些命令,我们可以访问远程主机的共享资源。

3,直接一次性使用smbclient命令
smbclient -c "ls" //192.168.0.1/tmp -U username%password

smbclient //192.168.0.1/tmp -U username%password
smb:\>ls
功能一样的

例,创建一个共享文件夹
smbclient -c "mkdir share1" //192.168.0.1/tmp -U username%password
如果用户共享//192.168.0.1/tmp的方式是只读的,会提示
NT_STATUS_ACCESS_DENIED making remote directory \share1
4,除了使用smbclient,还可以通过mount和smbcount挂载远程共享文件夹
mount -t smbfs -o username=administrator,password=123456 //192.168.0.1/tmp /mnt/tmp
smbmount //192.168.0.1/tmp /mnt/tmp -o username=administrator
@RestController @RequestMapping("/upload") public class FileUploadController { @Autowired private FileUploadService fileUploadService; // 接收分片 @PostMapping("/chunk") public ResponseEntity<?> uploadChunk(@RequestParam("file") MultipartFile file, @RequestParam("fileHash") String fileHash, @RequestParam("chunkIndex") int chunkIndex, @RequestParam("totalChunks") int totalChunks) { fileUploadService.saveChunk(file, fileHash, chunkIndex, totalChunks); return ResponseEntity.ok("Chunk uploaded"); } // 查詢已上傳分片(支持斷點續傳) @GetMapping("/check") public ResponseEntity<List<Integer>> checkUploadedChunks(@RequestParam("fileHash") String fileHash) { List<Integer> uploadedChunks = fileUploadService.getUploadedChunks(fileHash); return ResponseEntity.ok(uploadedChunks); } // 合併分片 @PostMapping("/merge") public ResponseEntity<?> mergeChunks(@RequestParam("fileHash") String fileHash, @RequestParam("fileName") String fileName) { fileUploadService.mergeChunks(fileHash, fileName); return ResponseEntity.ok("File merged"); } // 斷點下載(支援 Range) @GetMapping("/download") public void download(@RequestParam String fileName, HttpServletRequest req, HttpServletResponse resp) throws IOException { fileUploadService.download(fileName, req, resp); } @Service public class FileUploadService { private static final Logger log = LoggerFactory.getLogger(FileUploadService.class); private final SimpMessagingTemplate messagingTemplate; private final NasFileInfoMapper fileInfoMapper; private final NasDownloadLogMapper nasDownloadLogMapper; private static final String HOSTNAME = "10.32.5.80"; // NAS服务器地址 private static final String SHARE_NAME = "AnyshareBAK"; // 共享文件夹名称 private static final String USERNAME = "anyshare"; // 用户名 private static final String PASSWORD = "anybakup$*5.46"; private static final String NAS_UPLOAD_PATH = "/upload"; // NAS 目标路径,可根据需要修改 private static final String BASE_PATH = "/data/uploads/temp"; // 本地临时目录 private final SMBClient client; private Connection connection; private static Session session; public FileUploadService(SimpMessagingTemplate messagingTemplate,NasFileInfoMapper fileInfoMapper,NasDownloadLogMapper nasDownloadLogMapper) { this.messagingTemplate = messagingTemplate; this.fileInfoMapper = fileInfoMapper; this.nasDownloadLogMapper = nasDownloadLogMapper; this.client = new SMBClient(SmbConfig.builder() .withMultiProtocolNegotiate(true) .build()); } private void init() throws IOException { if (connection == null || !connection.isConnected()) { connection = client.connect(HOSTNAME); session = connection.authenticate(new AuthenticationContext(USERNAME, PASSWORD.toCharArray(), null)); } } public void saveChunk(MultipartFile chunk, String fileHash, int chunkIndex, int totalChunks) { File dir = new File(BASE_PATH, fileHash); if (!dir.exists()) dir.mkdirs(); File chunkFile = new File(dir, chunkIndex + ".part"); try (InputStream in = chunk.getInputStream(); OutputStream out = new FileOutputStream(chunkFile)) { in.transferTo(out); // ✅ 上傳完成一個分片後推送進度 notifyProgress(fileHash, getUploadedChunks(fileHash).size(), totalChunks); } catch (IOException e) { throw new RuntimeException("Failed to save chunk", e); } } public List<Integer> getUploadedChunks(String fileHash) { File dir = new File(BASE_PATH, fileHash); if (!dir.exists()) return List.of(); return Arrays.stream(Objects.requireNonNull(dir.listFiles())) .map(file -> Integer.parseInt(file.getName().replace(".part", ""))) .collect(Collectors.toList()); } public void mergeChunks(String fileHash, String fileName) { File dir = new File(BASE_PATH, fileHash); File mergedFile = new File(BASE_PATH + "/complete", fileName); mergedFile.getParentFile().mkdirs(); try (OutputStream out = new FileOutputStream(mergedFile)) { List<File> parts = Arrays.stream(Objects.requireNonNull(dir.listFiles())) .sorted(Comparator.comparingInt(f -> Integer.parseInt(f.getName().replace(".part", "")))) .collect(Collectors.toList()); for (File part : parts) { try (InputStream in = new FileInputStream(part)) { in.transferTo(out); } } log.info("File merged successfully: {}", mergedFile.getAbsolutePath()); // 上传合并后的文件到 NAS try (InputStream inputStream = new FileInputStream(mergedFile)) { uploadToNas(inputStream, NAS_UPLOAD_PATH + "/" + fileName); log.info("Upload to NAS complete: {}", fileName); } // 清理临时文件 for (File part : parts) part.delete(); dir.delete(); mergedFile.delete(); // 可选:也清理合并文件 // 合并和上传成功后保存信息到数据库 NasFileInfo info = new NasFileInfo(); info.setFileHash(fileHash); info.setFileName(fileName); info.setFileSize(mergedFile.length()); info.setUploadTime(LocalDateTime.now()); info.setUsername(SecurityUtils.getUsername()); info.setDeptId(SecurityUtils.getDeptId()); info.setNasPath(NAS_UPLOAD_PATH + "/" + fileName); fileInfoMapper.insert(info); } catch (IOException e) { throw new RuntimeException("Merge or upload failed", e); } } private void uploadToNas(InputStream inputStream, String nasPath) throws IOException { } private void createDirectoryIfNotExists(DiskShare share, String path) { String[] folders = path.split("/"); String currentPath = ""; for (String folder : folders) { if (folder.isEmpty()) continue; currentPath += "/" + folder; if (!share.folderExists(currentPath)) { share.mkdir(currentPath); } } } public void download(String fileName, HttpServletRequest req, HttpServletResponse resp) throws IOException { init(); // 初始化 SMB 连接 try (DiskShare share = (DiskShare) session.connectShare(SHARE_NAME)) { String nasPath = NAS_UPLOAD_PATH + "/" + fileName; if (!share.fileExists(nasPath)) { resp.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } //获取到目标文件夹 com.hierynomus.smbj.share.File remoteFile; try { remoteFile = share.openFile(nasPath, EnumSet.of(AccessMask.GENERIC_WRITE), null, SMB2ShareAccess.ALL, SMB2CreateDisposition.FILE_OVERWRITE_IF, null); } catch (Exception e) { log.error("Error opening remote file for writing: {}", nasPath, e); throw new IOException("Failed to open file for writing: " + nasPath); } long fileLength = remoteFile.getFileInformation().getStandardInformation().getEndOfFile(); String range = req.getHeader("Range"); long start = 0, end = fileLength - 1; if (range != null && range.startsWith("bytes=")) { String[] parts = range.replace("bytes=", "").split("-"); start = Long.parseLong(parts[0]); if (parts.length > 1 && !parts[1].isEmpty()) end = Long.parseLong(parts[1]); resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); } else { resp.setStatus(HttpServletResponse.SC_OK); } long contentLength = end - start + 1; resp.setHeader("Content-Type", "application/octet-stream"); resp.setHeader("Content-Length", String.valueOf(contentLength)); resp.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileLength); resp.setHeader("Accept-Ranges", "bytes"); try (InputStream smbIn = remoteFile.getInputStream(); ServletOutputStream out = resp.getOutputStream()) { smbIn.skip(start); // 跳过开始位置 byte[] buffer = new byte[8192]; long remaining = contentLength; int len; while ((len = smbIn.read(buffer, 0, (int) Math.min(buffer.length, remaining))) > 0) { out.write(buffer, 0, len); remaining -= len; } out.flush(); } NasFileInfo fileInfo = fileInfoMapper.selectOne( new LambdaQueryWrapper<NasFileInfo>().eq(NasFileInfo::getFileName, fileName) ); if (fileInfo != null) { NasDownloadLog log = new NasDownloadLog(); log.setFileId(fileInfo.getId()); log.setFileName(fileName); log.setUsername(SecurityUtils.getUsername()); // 自行實作獲取使用者名稱 log.setIpAddress(req.getRemoteAddr()); log.setUserAgent(req.getHeader("User-Agent")); log.setDownloadTime(LocalDateTime.now()); nasDownloadLogMapper.insert(log); } } } // 講進度丟該websocket public void notifyProgress(String fileHash, int currentChunk, int total) { messagingTemplate.convertAndSend("/progress/" + fileHash, Map.of("current", currentChunk, "total", total)); } 这是一个关于使用断点续传到nas的文件上传与下载功能,请阅读分析以上代码,帮我补齐uploadToNas方法的具体实现
最新发布
07-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值