質問

So in the process of making an RPG in Java, I found that it would be nice to make a program that would allow me to create a map and save it without having to edit the numbers of a byte array. I need to be able to save the map to a text file such, that it can be read and recreated in the RPG. However I cant figure out how to write a 2D byte array to a file.

For example:

byte[][] map = new byte[][]{ {0,0,0,0,0}, {1,1,1,0,0} };

I want the text file to be able to output something like this:

0 0 0 0 0
1 1 1 0 0

How exactly would I go about writing the contents of a 2d byte array to a text file?

役に立ちましたか?

解決

The most simple way IMO:

// create your output stream. Use the current running directory for your project
FileOutputStream fout = new FileOutputStream(new File(System.getProperty("user.dir"), "test.txt"));
// print it out so you know where it is... maybe?
System.out.println(new File(System.getProperty("user.dir"), "test.txt"));

byte[][] map = new byte[][] { { 0, 0, 0, 0, 0 }, { 1, 1, 1, 0, 0 } };
// loop through your map, 2d style
for (int i = 0; i < map.length; i++) {
    for (int j = 0; j < map[i].length; j++) {
        // get the string value of your byte and print it out
        fout.write(String.valueOf(map[i][j]).getBytes());
    }
    // write out a new line. For different systems the character changes
    fout.write(System.getProperty("line.separator").getBytes());
}
// close the output stream
fout.close();

他のヒント

You could have a go with a MappedByteBuffer, it is designed to be efficient/fast for IO operations:

    //Bytes
    byte[][] map = new byte[][]{ {0,0,0,0,0}, {1,1,1,0,0} };

    //Path to Desktop in this case
    Path pathway = Paths.get(System.getProperty("user.home")).resolve("Desktop").resolve("MyNewFile.txt");

    //Get size of file we will need, this is the size of each array (5 bytes) * num of arrays
    // + line separator space * number of arrays as is one for each line separation 
    int size = ((map[0].length * map.length)) + System.lineSeparator().getBytes().length * map.length;

    //Random access file for MappedByteBuffer.  Put in try() for autoclose
        try(RandomAccessFile raf = new RandomAccessFile(pathway.toFile(), "rw")){
            //MappedByteBuffer for speed 
            MappedByteBuffer mBuff = raf.getChannel().map(MapMode.READ_WRITE, 0, size);
            for(int i = 0; i < map.length; i++) {
                for(int j = 0; j < map[i].length; j++) {
                    mBuff.put(String.valueOf(map[i][j]).getBytes()); //Write value
                }
                mBuff.put(System.lineSeparator().getBytes()); //Write line break
            }
    } catch (IOException io) {
        System.out.println("IO Error: " + io.getMessage());
    }

You could use an ObjectOutputStream wrapping a FileOutputStream to write your 2D array to file, and then use an ObjectInputStream wrapping a FileInputStream to read it back in again. Note: This won't give you a plain text file that you can read and modify by opening it manually, if that's what you need then this isn't suitable for you.

Here's an example of how to do it:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Serialization {
    public static void main(String[] args) {
        byte[][] toSerialize = new byte[][] {{0,0,0,0,0}, {1,1,1,0,0}};
        byte[][] readArray;

        try {
            ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("my_file.dat"));
            oos.writeObject(toSerialize);
            oos.close();

            ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("my_file.dat"));
            readArray = (byte[][]) ois.readObject();

            for (int i = 0; i < readArray.length; i++) {
                for (int j = 0; j < readArray[i].length; j++) {
                    System.out.print(readArray[i][j] + " ");
                }
                System.out.println();
            }
            ois.close();
        } catch (Exception e) {}
    }
}

In practice, you'd want to separate reading and writing into separate methods, probably save() and load(). I would also strongly advise that you don't catch (Exception e) like I have.

You may also wish to consider using a seed to generate your map and storing that instead of writing the entire map to file, however implementing that is another matter entirely.

This is a very optimistic implementation not checking any cases where errors may occur. It is just an example using byte array steams instead of files. But it should work as is when replacing byte array streams with file input and output streams. Make it more robust by checking malformed file formats.

The idea is to precede each row with the length of it, followed by the bytes of the row. Your maps do have uniform column sizes, hence you may save the length of each column only once. Just Tweak it to your liking. Have fun:

public static void main(String[] args) throws Exception {
    byte[][] dungeon = new byte[][] {
        {0,0,0,0,0},
        {1,1,1,0,0}
    };
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    saveMap(os, dungeon);
    ByteArrayInputStream in = new ByteArrayInputStream(os.toByteArray());
    byte[][] maze = loadMap(in);
}

private static void saveMap(OutputStream saveStream, byte[][] dungeon) throws Exception {
    try (BufferedOutputStream os = new BufferedOutputStream(saveStream)) {
        for (int row=0; row<dungeon.length; row++) {
            os.write(toBytes(dungeon[row].length));
            os.write(dungeon[row]);
        }
    }
}

private static byte[][] loadMap(InputStream saveStream) throws Exception {
    List<byte[]> rows = new ArrayList<>();
    try (BufferedInputStream in = new BufferedInputStream(saveStream)) {
        while (in.available() != 0) {
            byte[] column = new byte[toInt(in.read(), in.read())];
            for (int idx = 0; idx < column.length; idx++) {
                column[idx] = (byte) in.read();
            }
            rows.add(column);
        }
    }
    return rows.toArray(new byte[rows.size()][]);
}

private static byte[] toBytes(int value) {
    return new byte[] { (byte) (value >>> 8), (byte) value };
}

private static int toInt(int high, int low) {
    return (high << 8) | (0x00FF & low);
}

Make one nested for loop.

For example:

for(int i = 0; i < array.length; i++) { // first dimension (x)
    for(int v = 0; v < array2.length; v++) { // second dimension (y)
        array[i][v]....
    }
}
final PrintWriter writer = new PrintWriter("your-file-name.txt", "UTF-8");
final StringBuilder arrayContent = new StringBuilder();

for(byte outer[] : map) {
    for(byte inner : outer) {
        arrayContent.append(inner);
    }
    arrayContent.append("\n");
}
writer.write(arrayContent.toString());
writer.close();

You have to handle exceptions from PrintWriter as well, but it depends if you want to throw them or catch them in your method.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top