Swift, How to write [Any] to file and read back in?

I have some data that I extract some information from/ Generally it consists of a header containing some mixed format data (text and integer) followed by several lines of mixed format (Int, Double) information.

EX: Header: " VERSION C3    EARTH     VARIABLE 1 (XYZ)       *T**0   1007 TERMS" from which I parse out ["C3", "EARTH", 1, 0, 1007] this is followed by 1007 lines containing numbers similar to: [3310, 232, 0, 0, 11, -21,  2,  0,  0,  0, -1,  0,  0,  1, -0.00000001572, -0.00000001245, 0.00000002005, 4.16423892775, 6303.67498687370]

The input is all textual and to speed things up needs to be saved as binary data for input. That's the easy part -- read it in and parse it into arrays of type Any. Plists are too slow. Here is little code fragment of what I am trying to do:

     var targetFile: Data = Data()
     // read source file data (there is a try-catch here ignored in the code fragment)
     let inputData = String ( contentsOf:  sourceFileUrl )
     sourceFileByLines = inputData.components( separatedBy: "\n" )
     // multiple headers followed by multiple lines of data, repeated 
     // header loop starts here
     getKeyInfomationFromHeaderLine ( line: sourceFileByLines! [ nextline ], theVersion: &version, body: &aBody , currentVariable: &variable, aT0Power: &t0Power, aTermCount: &termCount )
     var headerValues: [Any] = [String(version), String(aBody), variable, t0Power, termCount]
     targetfile += Data ( bytes: &headerValues, count: headerValues.count * MemoryLayout<[Any]>.stride )
     // Start loop to process term data line.
     // Build binary line
     for i in 0...13 {
          nextLineBinary [ i ] = Int ( nextLineSource [ i ] )!
     }
     for i in 14...18 {
         nextLineBinary [ i ] = Double ( nextLineSource [ i ] )!
     }
     targetfile += Data ( bytes: &nextLineBinary, count: nextLineBinary.count * MemoryLayout<[Any]>.stride )
     // increment & decrement loop control-variables
     // End loop for data lines
     // End loop for headers

All the variables are defined and the loops are proper and run to completion. But when I read the data into an [[Any]] array the data is confused (extra data is found, especially in the header values).

So the question is how should I be encoding, writing, reading, decoding and storing that data?

Any suggestions appreciated.

TIA,

ClarkW

Replies

You should convert everything to String and when reading convert back to Int where needed.

The input is all textual and to speed things up needs to be saved as binary data for input.

How efficient does that processing needs to be? Unless you call it thousands of times in a second, users would not feel the difference than using more stable and easy to use serialization like JSON.

Plists are too slow. 

How slow is it compared to the required speed? Can you clarify how you have evaluated the required speed?


And your way of saving or retrieving binary data is completely wrong:

targetfile += Data ( bytes: &headerValues, count: headerValues.count * MemoryLayout<[Any]>.stride )

With this usage of Data(bytes:count:), Swift copies the internal structure into the Data as is. Do you know how Swift.Array is represented in memory precisely? How is Swift.String? How is Any? They all may contain some pointers internally, so the contents pointed by the pointers also needs to be exist in the serialized binary. And even if you successfully save the pointees, you cannot retrieve them as you cannot modify such internal pointers.

But when I read the data into an [[Any]] array the data is confused (extra data is found, especially in the header values).

You were just lucky (or unlucky in a meaning) that your app does not crash on reading.


You should better re-consider if you really need such binary data for input.

If you insist on using binary data, you can define a C-struct:

#define MAX_VERSION_LEN 32
#define MAX_BODY_LEN 32
#define INT_VALUE_LEN 14
#define DOUBLE_VALUE_LEN 5
typedef struct InputData {
    char version[MAX_VERSION_LEN];
    char body[MAX_BODY_LEN];
    long intValues[INT_VALUE_LEN];
    double doubleValues[DOUBLE_VALUE_LEN];
    // ...and more...
} InputData;

and import this struct into your Swift project, parse the input for this struct.