为什么JavaFX Image无法直接从FileInputStream读取文件本身?

时间:2018-08-06 02:20:13

标签: java image javafx filenotfoundexception fileinputstream

我正在编写一个交易程序,允许用户上传自己的图像供其他客户在查看其发布的列表时查看。图像文件(.png或.jpeg文件)是在请求时从服务器发送的。

似乎使用FileInputStream作为新Image的参数时,尝试打开该映像的客户端正在自己的计算机上查找该文件(检查它自己的文件系统),而不是直接读取该文件本身。已从服务器发送给它。

在我发布的示例中,让我们假设它是在IDE中而不是作为JAR运行的。发送文件的服务器程序可以从其“ src”目录成功访问“ avatar.png”。

我在下面构建了一个最小的可执行示例,该示例由服务器和客户端组成,以表示即将出现的现实问题。服务器和客户端示例在本地网络上的不同计算机上运行。该示例复制了问题。

从FileInputStream文档中:

FileInputStream is meant for reading streams of raw bytes such as image data.

该示例引发以下异常:

java.io.FileNotFoundException: avatar.png (No such file or directory)

这表明客户端正在其自己的文件系统上查找“ avatar.png”。

例如,服务器:

public class ImageTesterServer {

public static void main(String[] args) {

    ImageTesterServer server = new ImageTesterServer();
    server.sendImage();

}


private void sendImage()
{
    ServerSocket server = null;
    Socket client = null;

    try {
        // Accept client connection, create new File from the 'avatar.png' image, and send to client
        server = new ServerSocket();
        System.out.println("Awaiting client connection...");

        client = server.accept();
        System.out.println("Client connected.");

        File imageFile = new File("avatar.png");
        ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
        oos.writeObject(imageFile);

        System.out.println("Sent image file.");

    } catch (IOException e) {
        e.printStackTrace();
    }
    finally {  // Close sockets
        try {
            if (client != null)
                client.close();
            if (server != null)
                server.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}

}

客户:

public class ImageTesterClient extends Application {

public static void main(String[] args)
{
    Application.launch(args);
}

@Override
public void start(Stage primaryStage)
{
    ImageTesterClient client = new ImageTesterClient();
    Image avatar = client.getServerFile();   // Retrieve the image's file from the server
    ImageView picture = new ImageView(avatar);

    StackPane root = new StackPane();
    root.getChildren().add(picture);

    Scene scene = new Scene(root);
    primaryStage.setScene(scene);
    primaryStage.show();
}

private Image getServerFile()
{
    Socket socket = null;
    ObjectInputStream ois;

    try {

        socket = new Socket("192.168.1.147", 5000);   // Open new socket connection to server on another local network computer
        ois = new ObjectInputStream(socket.getInputStream());
        File imageFile = (File)ois.readObject();
        Image avatar = new Image(new FileInputStream(imageFile));
        return avatar;

    } catch (IOException | ClassNotFoundException ex) {
        ex.printStackTrace();
    }
    finally {  // Close the socket if not null
        try {
            if (socket != null)
                socket.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    return null;
}

}

如何强制客户端映像使用从服务器接收到的文件(avatar.png)本身,而不是尝试查看自己的文件系统?

1 个答案:

答案 0 :(得分:4)

File类不代表文件的内容。。它只是文件路径的代表。造成混淆的原因是File类被视为过时(尽管不建议使用)的许多原因之一,并已由Path类取代。

因此,当您执行oos.writeObject(imageFile);时,您不是在发送文件的内容,而只是发送文件的路径。显然,一台计算机上存在文件路径并不能保证同一路径在另一台计算机上有效。

您将必须单独发送文件内容。一种方法是打开FileInputStream,将其包装在BufferedInputStream中,然后使用该BufferInputStream的transferTo方法:

oos.writeObject(imageFile);
try (InputStream stream =
    new BufferedInputStream(new FileInputStream(imageFile))) {

    stream.transferTo(oos);
}

在客户端,使用文件的长度确定要读取的字节数:

File imageFile = (File) ois.readObject();
long length = imageFile.length();

Path imagePath = Files.createTempFile(null, imageFile.getName());
try (FileChannel imageChannel = FileChannel.open(imagePath, 
    StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {

    imageChannel.transferFrom(Channels.newChannel(ois), 0, length);
}

Image avatar = new Image(imagePath.toUri().toString());