如何将FileChooser上传的文件保存到项目中的目录中?

Moh*_* S. -1 javafx intellij-idea filechooser

因此,正如帖子标题所述,我正在寻求一种方法,可以将使用 FileChooser 上传到项目目录中的文件表示出来。

更具体地说,我正在上传图像,我想将它们保存在我的项目中,以便将来使用它们。这是一个示例代码:

控制器:

package org.example;

import javafx.fxml.FXML;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.FileChooser;

import java.io.File;

public class PrimaryController {

    @FXML
    private ImageView image;

    @FXML
    void handleUploadImage() {

        FileChooser fileChooser = new FileChooser();
        fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Image Files", "*.jpg", "*.jpeg", "*.png", "*.svg"));
        File file = fileChooser.showOpenDialog(null);
        if (file != null) {
            image.setImage(new Image(String.valueOf(file)));
        } else {
            System.out.println("It's null");
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.Cursor?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-background-color: linear-gradient(to right, #1c92d2, #f2fcfe);" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.PrimaryController">
   <children>
      <ImageView fx:id="image" fitHeight="200.0" fitWidth="200.0" layoutX="200.0" layoutY="100.0" onMouseClicked="#handleUploadImage" pickOnBounds="true" preserveRatio="true">
         <image>
            <Image url="@../../images/upload.png" />
         </image>
         <cursor>
            <Cursor fx:constant="HAND" />
         </cursor>
      </ImageView>
   </children>
</AnchorPane>

Run Code Online (Sandbox Code Playgroud)

我的目录:

图像

我想将图像保存为/resources/images. 我怎样才能这样做呢?

jew*_*sea 5

背景信息

该文件没有被“上传”。该术语通常指将文件发送到托管云服务或 FTP 站点等操作。您的代码选择通过本地计算机的文件系统可用的文件。然后你想用它做点什么。可能将其复制到本地的另一个位置。我想您可能会选择将该过程称为“上传”,但是对我来说,这个术语似乎不太合适。

通常,当部署 JavaFX 应用程序时,其所有代码和资源将打包在一起,例如打包在 jar 文件、安装程序或 jlink 映像中。您的项目源代码的资源目录将不存在,但它的内容将被复制到包中。在运行时向该位置添加额外的资源是一个未定义的操作,因为您并不真正知道资源将去往何处。

建议的替代方案:保存到已知的本地文件位置

您可能想要做的是将文件复制到计算机上的已知位置并从那里访问它。一种方法是.myapp在用户的主目录下创建一个目录(例如 ),将所选文件复制到该目录中,然后根据需要从那里读取和写入文件。您可以使用java 系统属性确定用户的主目录。

替代方案:使用首选项 API

您可以使用Java Preferences API,而不是使用用户主目录下的自定义应用程序目录。

该包允许应用程序存储和检索用户和系统首选项以及配置数据。该数据持久存储在依赖于实现的后备存储中。有两棵独立的首选项节点树,一棵用于用户首选项,一棵用于系统首选项。

有关如何执行此操作的详细讨论超出了本答案的范围,但网上有大量围绕它的教程。

制造商教程中有一个从 JavaFX 应用程序使用 Java Preferences API 的示例。

常问问题

这确实没有任何意义。如果我愿意允许用户上传图像然后将图像保存在我的电脑或项目中的某个位置,我必须做什么?

据推测,您的“项目”是您在问题中显示的源代码目录。如前所述,该目录在运行时在本地开发环境之外不可用。因此,您无法在运行时将文件保存到项目中,因为它不存在。相反,您需要“将图像保存在我的电脑上的某个位置”。一种方法是遵循我提供的有关将图像放置在应用程序在用户主目录中创建的特定于应用程序的子目录中的建议。

该解决方案在全球范围内有效吗?就像这个项目不仅仅适合我,这意味着它将被发送给一些其他人,这样他们就不会拥有我保存文件的目录。

他们将有一个用户目录,因为这就是操作系统的工作方式。这可以从我链接的系统属性中获得。如果您按照应用程序的路线,根据需要在用户目录下创建和使用特定于应用程序的子目录,那么您可以放心,所需的目录将存在。对于不同位置的操作系统中的存储还有其他约定,但我真的建议仅使用用户目录下的应用程序特定目录,除非您需要执行其他操作。还有其他选项,例如上传到云托管图像服务,但除非需要,否则不要这样做。

另外,在项目中,我将使用的所有图像放置在目录中存在的目录中,例如 /resources/images ,我需要将图像保存在其中。

正如所解释的,您不能在运行时动态地执行此操作。您需要将动态添加的图像放置在其他位置(例如,在用户本地目录、云服务、共享数据库等下)。您需要从同一个位置读取这些文件。如果将它们放在用户目录下,则可以使用文件 URL 或文件 API 而不是 getResource 来读写文件。

示例应用程序

该应用程序使用用户的主目录来存储所选的头像图像。

应用程序将使用应用程序附带的应用程序资源中的默认头像。如果用户选择要使用的新图像,则可以更改默认头像。

当前使用的头像被复制到存储在 的文件中<user.home>/.avatar/avatar.png

此答案中提供了用于默认图像的自定义图标图像:

这个解决方案可能与您需要的不同,也许您需要一个用于任意图像集的文件上传服务,例如相册,而不是像头像这样的单个图像。但希望此处显示的信息为您提供了如何继续解决您的确切问题的具体示例。

uploadCustomAvatar中的方法采用AvatarServiceanInputStream作为参数。因此,如果需要,可以采用该方法从本地图像文件之外的其他位置(例如,Web URL)获取自定义图像。

默认头像

默认

上传的自定义头像

在此输入图像描述

AvatarApp.java

import javafx.application.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;

public class AvatarApp extends Application {
    private static final String APP_DIR = ".avatar";

    private AvatarService avatarService;

    @Override
    public void init() {
        LocalStorage localStorage = new LocalStorage(APP_DIR);
        avatarService = new AvatarService(localStorage);
    }

    @Override
    public void start(Stage stage) throws Exception {
        ImageView avatar = new ImageView(avatarService.getAvatarImage());
        avatar.imageProperty().bind(avatarService.avatarImageProperty());
        avatar.setFitWidth(AvatarService.DIMENSIONS);
        avatar.setFitHeight(AvatarService.DIMENSIONS);
        avatar.setPreserveRatio(true);

        Button changeAvatarButton = new Button("Change...");
        changeAvatarButton.setOnAction(e -> uploadCustomAvatar(stage));

        VBox layout = new VBox(10, avatar, changeAvatarButton);
        layout.setStyle("-fx-background-color: linen; -fx-font-size: 16px");
        layout.setAlignment(Pos.CENTER);
        layout.setPadding(new Insets(10));

        stage.setScene(new Scene(layout));
        stage.show();
    }

    private void uploadCustomAvatar(Stage owner) {
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Choose your avatar");
        fileChooser.getExtensionFilters().addAll(
                new FileChooser.ExtensionFilter(
                        "PNG Image Files", "*.png"
                )
        );

        File selectedFile = fileChooser.showOpenDialog(owner);
        if (selectedFile != null) {
           try (
                   InputStream inputStream = new BufferedInputStream(
                           Files.newInputStream(selectedFile.toPath())
                   )
           ) {
               avatarService.uploadCustomAvatar(inputStream);
            } catch (IOException ex) {
                System.out.println("Unable to upload avatar");
                ex.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Run Code Online (Sandbox Code Playgroud)

AvatarService.java

import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.scene.image.Image;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Objects;

class AvatarService {
    public static final double DIMENSIONS = 96;

    private static final String DEFAULT_AVATAR_RESOURCE = "Dragon-icon.png";
    private static final String AVATAR_FILENAME = "avatar.png";

    private final Path avatarPath;
    private final ReadOnlyObjectWrapper<Image> avatarImage = new ReadOnlyObjectWrapper<>();

    public AvatarService(LocalStorage localStorage) {
        avatarPath = localStorage.getLocalStoragePath().resolve(AVATAR_FILENAME);

        if (!Files.exists(avatarPath)) {
            copyDefaultAvatar();
        }

        refreshImage();
    }

    private void copyDefaultAvatar() {
        try {
            Files.copy(
                    Objects.requireNonNull(
                            AvatarApp.class.getResourceAsStream(
                                    DEFAULT_AVATAR_RESOURCE
                            )
                    ),
                    avatarPath
            );
        } catch (IOException e) {
            System.out.println("Unable to initialize default avatar");
            e.printStackTrace();
            Platform.exit();
        }
    }

    public void uploadCustomAvatar(InputStream inputStream) {
        try {
            Files.copy(
                    inputStream,
                    avatarPath,
                    StandardCopyOption.REPLACE_EXISTING
            );

            refreshImage();
        } catch (IOException e) {
            System.out.println("Unable to upload custom avatar");
            e.printStackTrace();
        }
    }

    public Image getAvatarImage() {
        return avatarImage.get();
    }


    public ReadOnlyObjectProperty<Image> avatarImageProperty() {
        return avatarImage.getReadOnlyProperty();
    }

    private void refreshImage() {
        avatarImage.set(
                new Image(
                        "file:" + avatarPath.toAbsolutePath()
                )
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

本地存储.java

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

class LocalStorage {
    private Path localStoragePath;

    public LocalStorage(String name) {
        try {
            String userDir = System.getProperty("user.home");

            localStoragePath = Paths.get(userDir, name);
            if (!Files.isDirectory(localStoragePath)) {
                Files.createDirectory(localStoragePath);
            }
        } catch (IOException ex) {
            System.out.println("Unable to initialize local storage");
            ex.printStackTrace();
            Platform.exit();
        }
    }

    public Path getLocalStoragePath() {
        return localStoragePath;
    }
}
Run Code Online (Sandbox Code Playgroud)