0

I need to write a pixel array to disk and read that file back in the same application. For some reason, the files don't write to disk until the application terminates. (Only then do they show up in the directory to which they're saved). I'm writing this application in IntelliJ IDEA if that is in any way useful to know.

How do I ensure that the file is written to disk immediately? Here is my code:

protected void savePixelstoPNG(int[] pixels, String fileName) {
    BufferedImage image = new BufferedImage(getMapWidth(), getMapHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics graphics = image.getGraphics();

    for(int y = 0; y < getMapHeight(); y++) {
        for(int x = 0; x < getMapWidth(); x++) {
            graphics.setColor(new Color(pixels[x + y * getMapWidth()]));
            graphics.fillRect(x, y, 1, 1);
        }
    }

    try {
        File file = new File(fileName);
        ImageIO.write(image, "PNG", file);
    } catch(IOException e) {
        e.printStackTrace();
    }
}

EDIT: I inspected the folders and they in fact ARE being written immediately to disk. However, these changes are NOT reflected in the project directory (The files are saved into a java package) until the application terminates. So when I go to read those files after saving them (within the same application lifetime) the application can't find the files, even though they exist on disk.

EDIT 2: Here is the code that I'm using to read the file from the classpath using a relative directory path. The initial resources are read from the classpath. When they are updated, they are written to different directory in the classpath so the original resources are not overwritten, since the original resources are supposed to be initially read each time the application is run anew:

void myLoadMethod() {
        loadMapTiles("resource/tilemap_1-1.png");
        loadTriggerTiles("resource/triggermap_1-1.png");
}


protected void loadMapTiles(@NotNull String path) {
        URL url = getClass().getClassLoader().getResource(path);
        loadTiles(url, mapTiles);
}

protected void loadTriggerTiles(@NotNull String path) {
        URL url = getClaass().getClassLoader().getResource(path);
        loadTiles(url, triggerTiles);
}

protected void loadTiles(@NotNull URL url, @Nullable int[] dest) {
        try {
            System.out.println("Trying to load: " + url.toString() + "...");
            BufferedImage map = ImageIO.read(url);
            int[] pixels = new int[mapWidth * mapHeight];
            map.getRGB(0, 0, mapWidth, mapHeight, pixels, 0, mapWidth);
            System.arraycopy(pixels, 0, dest, 0, dest.length);
            System.out.println("Success!");
        } catch (IOException e) {
            System.out.println("failed...");
            e.printStackTrace();
        }
    }
}

Note that mapTiles and triggerTiles are fields contained within the class that holds loadMapTiles loadTriggerTiles and loadTiles

Skywarp
  • 989
  • 3
  • 15
  • 32
  • AFAIK but the static call to `ImageIO#write` does that automatically – Skywarp Oct 11 '17 at 17:45
  • How do you try to read them in? Do you assume the file to be on the class path, or from outside? Because "the files are saved into a java package" it could be that you write to the (source) directory, but try to read from the class path, and they only get copied over into the classpath once you start a new run in IntelliJ. – cello Oct 11 '17 at 17:55
  • Yes! I am reading from classpath using a URL instantiated with a relative directory. I wrote to absolute directory because I couldn't figure out how to write to a relative directory. I couldn't get it to recognize a relative directory (kept getting directory not found) So I guess I need to figure out how to write it to a relative directory? – Skywarp Oct 11 '17 at 18:04
  • I 'm understanding correctly, you cannot save resources to the classpath? https://stackoverflow.com/questions/4714645/how-can-i-save-a-file-to-the-class-path#4714719 – Skywarp Oct 11 '17 at 18:32

1 Answers1

1

You should differentiate between the source files and classpath.

Sources usually reside in some kind of src directory. E.g. for Maven project the standard is src/main/java for *.java files and src/main/resources for other resources *.properties, etc.

But later java files are compiled and *.class files are copied to some output directory. E.g. for Maven this is target/..., many other tools have bin or output as compiled class folders. The resources are saved at the same location.

It seems that you are writing files to src and trying to read them from other location (e.g. Class#getResourceAsStream(path) will read data from classpath). The fact that you can read the file next app run makes me think that on the next build it is copied to output directory and becomes "visible" to your app.

On your code

URL url = getClass().getClassLoader().getResource(path);

Constructs a URL to file that is expected to be on classpath (most probably in ${projectRoot}/target/classes/${path}).

While

File file = new File(fileName);

creates a file in path relative to execution directory (most probably relative to ${projectRoot}).

Generally ClassLoader#getResource(path) should be used only to get static resources on your classpath.

For building paths on disk use Paths#get(path). If you absolutely need a URL you can do it this way:

Paths.get(path).toURI().toURL();
Aleh Maksimovich
  • 2,622
  • 8
  • 19
  • I added the code used to read the file under EDIT2 of the original question. The write code is contained in the original question, so hopefully it's all there – Skywarp Oct 11 '17 at 19:02
  • You should be careful about the base for your relative locations. Can you use absolute? Or pass base directory as parameter? – Aleh Maksimovich Oct 11 '17 at 19:24
  • I have no problem using absolute. However the issue I'm running into with absolute is that I have to specify the directory all the way to the root directory of my entire filesystem, not back to the project root. So for example `/home/user/IdeaProjects/MyProject/src/my_image.png` I must have something configured incorrectly somewhere. I'm marking your answer though because your explanation makes sense. – Skywarp Oct 11 '17 at 19:39