Why does a JavaFX Image not read the file itself directly from a FileInputStream?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Why does a JavaFX Image not read the file itself directly from a FileInputStream?



I'm writing a trading program that allows users to upload their own images for other clients to view when looking at their posted listing. The image file (.png or .jpeg file) is sent from the server when requested.



It seems that when using a FileInputStream as the parameter for a new Image, the client attempting to open the image is looking for that file on their own computer (checking it's own file system) instead of directly reading the image file itself that has been sent to it from the server.



In the example I am posting, let's assume that this is ran in the IDE and not as a JAR. The server program who is sending the file is able to access "avatar.png" successfully from its 'src' directory.



I have built a minimal executable example below, consisting of a server and client to represent the realistic issue at hand. The server and client examples were ran on separate computers on a local network. The example replicates the issue.



From the FileInputStream documentation:


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



The example throws the following exception:


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



Which shows that the client is looking for 'avatar.png' on it's own file system.



For example, the server:


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();








The client:


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




How do I force the client Image to use the File (avatar.png) itself that has been received from the server, instead of it attempting to look on it's own file system?




1 Answer
1



The File class does not represent a file’s contents. It is merely a representation of a file path. This confusion is one of many reasons the File class is considered obsolete (though not deprecated), and has been replaced by the Path class.



So, when you do oos.writeObject(imageFile);, you are not sending the contents of the file, only the path of that file. Obviously, the existence of a file path on one computer does not guarantee that the same path is valid on another computer.


oos.writeObject(imageFile);



You will have to send the file’s content separately. One way to do this is to open a FileInputStream, wrap it in a BufferedInputStream, and use that BufferInputStream’s transferTo method:


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

stream.transferTo(oos);



And on the client side, use the File’s length to determine how many bytes to read:


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());






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard