在 FTP/Database 连接期间删除文件失败

Deleting file during FTP/Database connection failed

我的程序旨在加载图像、调整大小、保存、发送到 FTP 服务器,然后删除调整大小的图像。完整代码 - HERE

我遇到的问题是在从名为 AddBreedBuilder.java 的文件中按下 finish 按钮后:程序发送调整大小的文件到服务器,冻结约 1 秒,它正在尝试删除调整大小的文件(但这是不可能的)。

我尝试使用(目前这部分已从 java 文件中删除,第 165 行):File fileToDelete = new File(imgPath); boolean success = fileToDelete.delete();success总是 false。删除此文件的唯一方法是不要 运行 sendToFTP().

据我所知,我的程序在文件删除操作中正在使用这个文件,所以无法删除。

我的问题是:是否可以延迟文件删除直到程序解冻? 或者也许有办法在不保存的情况下发送调整大小的文件?

From what I think, my program is using this file during file delete operation, so it cannot be deleted.

没错。

原因是您的 sendToFTP 方法打开了它发送到服务器的文件,但它没有(永远)关闭它。由于文件仍处于打开状态,Windows 不会让应用删除它

解决方案:修改您的 sendToFTP 方法,使 FileInputStream 始终 关闭。

除了您提出的问题之外,代码本身还有一些问题,它会影响问题的答案。我稍后会解决这些问题。但是,首先要直接解决您的问题:

  1. 是的。您可以通过启动一个处理 FTP 传输的新线程来执行此操作,因为传输是作为 GUI 事件的结果启动的,因此它不会冻结您的应用程序。 (处理 GUI 的事件分派线程只启动新线程而不等待它完成。)在 sendToFTP() 中,执​​行:

    public static void sendToFTP(String fileName, String name) {
        Thread sender = new Thread() {
            public void run() {
                FTPClient client = new FTPClient();
                try {
                    FileInputStream fis = new FileInputStream(new File(fileName));
    
                    client.connect("serwer1978625.home.pl");
                    client.login("nissmel@chooseyourpuppy.pl", MyBreed.getPassword());
    
                    client.changeWorkingDirectory("/breeds");
                    client.setFileType(FTP.BINARY_FILE_TYPE);
    
                    client.storeFile(name, fis);
                    // client.rename(fileName, name); // not necessary
                    client.logout();
                    // At this point you must close the FileInputStream, since that is what is using the file, as you noticed.
                    fis.close();
                    // TODO: your code to delete the file comes in here, if everything goes well
                    // Alternatively, you could do these in the finally block to run irrespective of how the above code executes
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
                finally {
                    try {
                        client.disconnect();
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
    
        };
             // the event dispatch thread only starts the sender thread and exits this function,
        // hence no freezing occurs
        sender.start();
    }
    

    然后在调用函数中,buildAdd()

    // ...
    sendToFTP(imgPath, userBreedInfo[0] + ".jpg");
    // ...
    
  2. 您绝对可以发送文件(更准确地说,文件内容)而无需生成文件。您可以直接将 BufferedImage 提供给 sendToFTP() 方法,然后将其转换为 client.storeFile() 所需的 InputStream。在这种情况下,如果您在本地计算机上不需要它,您甚至根本不需要首先存储该文件。

    public static void sendToFTP(BufferedImage bimage, String name) {
          // ... some code
          // Here we need an input stream for storeFile(), so we get that from an output stream
          // produced in turn by the buffered image
          ByteArrayOutputStream outStream = new ByteArrayOutputStream();
          ImageIO.write(bimage, "png", outStream);
          InputStream is = new ByteArrayInputStream(outStream.toByteArray());
          // ... some code
          client.storeFile(name, is);
          // ... rest of code
    }
    

然后在调用函数中,buildAdd()

    // ...
    sendToFTP(bimage, userBreedInfo[0] + ".jpg");
    // ...

请注意 sendToFTP() 第二版签名的变化。你可以用不同的方式玩这个想法,而是用这个 InputStream 替换 buildAdd() 中的文件写入调用,然后将流传递给 sendToFTP().

备注 您可以使用 try-with-resources 习惯用法来确保上面使用的流自动关闭:请参阅 here 例如。

解决的其他问题:

  1. 存储在 FTP 端点后无需重命名文件:只需 第一次使用最终名称。
  2. 一定要关闭流。这就是导致您报告错误的原因。
  3. 在更好的情况下,无需首先在本地系统上创建文件(即在 buildAdd() 内)。