在项目中使用FTPClient上传文件遇到550 Fial to change directoty问题

FTPClient上传文件550错误解决办法
在使用FTPClient进行文件上传时遇到550 Fial to change directory问题,即使changeWorkingDirectory方法返回false,文件仍能上传,但路径不符预期。解决方法包括在vsftpd配置中设置chroot_local_user为YES,或不调用changeWorkingDirectory方法,直接在服务器配置指定存储路径。

前提:使用客户端访软件FTP服务器对文件进行操作是OK的。
问题:在代码中执行FTPClient的changeWorkingDirectory(pathname)方法失败,debug代码的时候报550 Fial to change directoty。

changeWorkingDirectory方法执行返回falsehou 文件依然上传成功了,只不过上传的目录是vsftpd.conflocal_root指定的目录,而不是我们代码中指定的目录。


举个栗子

我的代码: changeWorkingDirectory("/ftpfile/img") //返回false

nginx配置项:
在这里插入图片描述
vsftpd配置项:
在这里插入图片描述

So,这时候文件会上传到/ftpfile,然而我们在浏览器输入"nginx域名+文件名"想要访问上传的文件是访问不到的,因为/ftpfile/img下没有这个文件


解决方法:想要将文件存到我们指定的目录,就需要在配置文件中将chroot_local_user这一项设为YES,设置如下:

配置项说明:
在默认配置下,本地用户登入FTP后可以使用cd命令切换到其他目录,这样会对系统带来安全隐患。可以通过以下三条配置文件来控制用户切换目录

  • chroot_list_enable=YES(NO)
    设置是否启用chroot_list_file配置项指定的用户列表文件。默认值为NO。
  • chroot_list_file=/etc/vsftpd.chroot_list
    用于指定用户列表文件,该文件用于控制哪些用户可以切换到用户家目录的上级目录。
  • chroot_local_user=YES(NO)
    用于指定用户列表文件中的用户是否允许切换到上级目录。默认值为NO。

结论

So,想要访问成功:

  1. 在代码中不调用changeWorkingDirectory方法,就在vsftpd中设置存储文件的目录
  2. 在代码中调用changeWorkingDirectory方法,就要修改vsftpd的配置让登陆的用户能够有切换目录的权限。
### 获取 FTP 文件的创建时间 Java 中的 `FTPClient` 类并未直接提供获取 FTP 文件创建时间的功能。标准的 `FTPFile` 类仅支持获取文件的最后修改时间,其通过 `getTimestamp()` 方法返回一个 `Calendar` 对象,表示文件的最后修改时间。然而,FTP 协议本身并未定义文件的“创建时间”字段,因此大多数 FTP 服务器并不支持此属性[^1]。 如果需要获取文件的创建时间,可以尝试以下方法: #### 1. 使用 `MLSD` 命令解析文件信息 某些 FTP 服务器支持 `MLSD`(Machine-parsable LIST)命令,返回的文件信息中可能包含额外的元数据字段,如 `created`(创建时间)。`MLSD` 返回的响应是结构化的,可以通过解析响应内容提取这些字段。 示例代码: ```java FTPClient ftpClient = new FTPClient(); try { ftpClient.connect("ftp.example.com"); ftpClient.login("user", "password"); FTPFile[] files = ftpClient.mlistDir(); // 获取 MLSD 格式的文件列表 for (FTPFile file : files) { String rawListing = file.getRawListing(); // 获取原始响应字符串 if (rawListing.contains("created=")) { String[] parts = rawListing.split(";"); for (String part : parts) { if (part.trim().startsWith("created=")) { String createdTimestamp = part.trim().substring("created=".length()); // 解析 createdTimestamp 为 Date 对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); Date creationDate = sdf.parse(createdTimestamp); System.out.println("创建时间: " + creationDate); } } } } } catch (IOException | ParseException e) { e.printStackTrace(); } ``` #### 2. 使用 `SITE` 命令或自定义扩展 部分 FTP 服务器支持 `SITE` 命令,允许客户端请求特定格式的文件信息,包括创建时间。例如,某些服务器可能支持 `SITE CUSTOM METADATA` 命令,返回文件的扩展属性。 示例代码: ```java FTPClient ftpClient = new FTPClient(); try { ftpClient.connect("ftp.example.com"); ftpClient.login("user", "password"); boolean success = ftpClient.sendSiteCommand("CUSTOM METADATA"); if (success) { String[] response = ftpClient.getReplyStrings(); for (String line : response) { if (line.contains("creation-time=")) { String createdTimestamp = line.split("creation-time=")[1].split(" ")[0]; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date creationDate = sdf.parse(createdTimestamp); System.out.println("创建时间: " + creationDate); } } } } catch (IOException | ParseException e) { e.printStackTrace(); } ``` #### 3. 服务器端元数据文件 如果 FTP 服务器不支持创建时间字段,可以在上传文件时同时上传一个包含创建时间的元数据文件。例如,在上传 `file.txt` 时,也上传 `file.txt.meta`,其中包含创建时间信息。 示例代码: ```java try (OutputStream metaOutputStream = ftpClient.storeFileStream("file.txt.meta")) { String metadata = "creation-time=" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); metaOutputStream.write(metadata.getBytes()); } ``` #### 4. 使用 SFTP 替代 FTP 如果对文件元数据有更高要求,建议使用 SFTP 协议替代 FTP。SFTP 支持更丰富的文件属性,包括创建时间(通常为 `atime` 和 `ctime`),并且可以通过 `ChannelSftp` 的 `stat()` 方法获取这些属性。 示例代码(使用 JSch 库): ```java JSch jsch = new JSch(); Session session = jsch.getSession("user", "sftp.example.com", 22); session.setPassword("password"); session.setConfig("StrictHostKeyChecking", "no"); session.connect(); Channel channel = session.openChannel("sftp"); channel.connect(); ChannelSftp sftpChannel = (ChannelSftp) channel; SftpATTRS attrs = sftpChannel.stat("file.txt"); long creationTime = attrs.getCTime(); // 获取创建时间(秒级时间戳) Date creationDate = new Date(creationTime * 1000L); System.out.println("创建时间: " + creationDate); ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值