Read and write back fit file adds extra bytes

Hello,

I'm on FIT SDK version 21.84.00. I'm working on a Java tool to crop fit files (e.g. because the activity wasn't stopped during the recording for hours after the real end of the activity).

I think I may have some issues here and there, but first and foremost, I think that again simply reading and writing back the fit file is not working as it should. 

The original file is downloaded from Strava and is 96KB and the one I'm saving back to disk is 113KB. Here are the files:

Now, the Java code to write back the file is taken (more or less) from the tutorial. I did not change any message in the file (just read and then write back).

FileEncoder fileEncoder;
try {
fileEncoder = new FileEncoder(filePath.toFile(), com.garmin.fit.Fit.ProtocolVersion.V2_0);
} catch (FitRuntimeException e) {
throw new FitSerializationException(e);
}

FitMessages fitMessages = fit.getFitMessages();

// Then for each message type

List<Mesg> messages = //... e.g.  fitMessages.getFileIdMesgs();


for (int i = 0; i <messages.size(); i++) {
final Mesg mesg = messages.get(i);
// remove computed fields that were not in the original file
mesg.removeExpandedFields();

fileEncoder.write(mesg);
}

I don't get where these extra bytes come from. Any hint?

May it be that Strava doesn't use the Garmin fit SDK to persist the messages into a fit file and so maybe they also use different field types (e.g. Short instead of Integer, etc.)?

  • Search the protocol doc for "Figure 16" for an explanation of component expansion. In the example, Di2 gear shift events are stored in the file as a single uint32 field and then expanded in to four 1 byte fields. Calling mesg.removeExpandedFields(); before writing the message to the file removes the four one byte fields. There are other fields that do the same thing. But I do not think that would account for the change in file size that you are seeing. I would not get too hung up on the file size if the end result does what you need it to do.
    https://developer.garmin.com/fit/protocol/ 

    When re-encoding a file, you want to make sure that you do not change the original order of the messages. Take a look at this question from a while ago, it may help you.
    https://forums.garmin.com/developer/fit-sdk/f/discussion/284218/data-loss-after-decoding-and-then-encoding-again-a-fit-file

    That said, I would not use the FitDecoderExample as your starting point because you will not be able to write the messages out in the order that they appeared in the original file. Instead, I would start with the DecodeExample, add an encoder to it, and implement a single listener that listend for Mesgs. You can replace the MesgBroadcaster with your listener class. The OnMesg() method would look something like this. 

    @Override

    public void onMesg(Mesg mesg) {

       mesg.removeExpandedFields(); // remove computed fields that were not in the original file

       encoder.write(mesg);

    }

    Then add the logic for where you want to trim the file. From looking at your file, the logic might be something like the following pseudo code.

    @Override

    public void onMesg(Mesg mesg) {

       mesg.removeExpandedFields(); // remove computed fields that were not in the original file

       if(mesg.getNum() == MesgNum.RECORD) {

         RecordMesg recordMesg = new RecordMesg(mesg);

         if(recordMesg.getHeartRate() != null) {

              encoder.write(mesg); // or encoder.write(recordMesg) should not matter.

         }

    }

    The problem with this code is, there will still be Lap and Session messages with incorrect durations.