5

So, I am trying to store 3 longs to a file, but it will a lot of data so I convert them to byte arrays and save them. My current method for saving them:

try (FileOutputStream output = new FileOutputStream(path, true)) {
                    //Put the data into my format
                    byte[] data = new byte[24];
                    main.getLogger().log(Level.INFO, "Saving most sig bits");
                    System.arraycopy(ByteUtils.longToBytes(uuid.getMostSignificantBits()), 0, data, 0, 8);
                    System.arraycopy(ByteUtils.longToBytes(uuid.getLeastSignificantBits()), 0, data, 8, 8);
                    System.arraycopy(ByteUtils.longToBytes(player.getTokens()), 0, data, 16, 8);
                    //Write data in the format
                    output.write(data);
                }

longToBytes method:

private static ByteBuffer buffer = ByteBuffer.allocate(8);

public static byte[] longToBytes(long x) {
    System.out.println(x);
    buffer.putLong(0, x);
    return buffer.array();
}

The byte array gets saved to the file, but the first byte gets truncated. the print statement in longToByes prints 8 three times.

The original longs are:

-9089798603852198353, -5339652910133477779, 5992

If I print the byte array I get:

-127, -38, -116, 84, 97, -116, 78, 47, -75, -27, -67, -8, 11, -100, -2, 109, 0, 0, 0, 0, 0, 0, 23, 104 (24 bytes)

But in the file I see: ÚŒTaŒN/µå½ø(VT symbol)œþm(nul)(nul)(nul)(nul)(nul)(nul)(etb)h which is 23 bytes (the first box doesn't show in notepad++)

but if I read it using

bytes = IOUtils.toByteArray(new FileReader(file));

I see:

64, -38, -116, 84, 97, -116, 78, 47, -75, -27, -67, -8, 11, -100, -2, 109, 0, 0, 0, 0, 0, 0, 23, 104 (24 bytes)

-127 is replaced with 64 somehow.

I concat the byte with "" to print it btw.

1 Answer 1

5

Do not use FileReader to read raw bytes from file. Use FileInputStream instead.

The problem with FileReader is that it reads chars, not bytes, from the file, by trying to decode the bytes using some character encoding (the default one if none was given).

bytes = IOUtils.toByteArray(new FileInputStream(file));

Alternatively you can use DataOutputStream to write long directly to an output stream and use DataInputStream to read from an input stream.

try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) {
    out.writeLong(uuid.getMostSignificantBits());
    out.writeLong(uuid.getLeastSignificantBits());
    out.writeLong(player.getTokens());
}

try (DataInputStream in = new DataInputStream(new FileInputStream(file))) {
    long uuidMSB = in.readLong();
    long uuidLSB = in.readLong();
    long tokens = in.readLong();
}
Sign up to request clarification or add additional context in comments.

4 Comments

I totally forgot that this causes a problem, thanks!
If you are going to write lot's of data, you should add a buffer to your streams to increase performance, e.g. DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))) and DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(file))) respectively. Then you do not need to handle a buffer like your data array in your code manually.
The data is going to be written over time, like 150 longs at once, about 1-10 times an hour, is refactoring my code a ton worth the performance?
Nevermind, I need to append in the middle of a file, so a DataOutputStream is off the table I think.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.