In Swift, how can I read an existing binary in an array?

As part of my projects, I have a binary data file consisting of a large series of 32-bit integers that one of my classes reads during initialization. In my C ++ library, I read it with the following initializer:

Evaluator::Evaluator() { m_HandNumbers.resize(32487834); ifstream inputReader; inputReader.open("/path/to/file/7CHands.dat", ios::binary); int inputValue; for (int x = 0; x < 32487834; ++x) { inputReader.read((char *) &inputValue, sizeof (inputValue)); m_HandNumbers[x] = inputValue; } inputReader.close(); }; 

and when transferring to Swift, I decided to read the entire file into one buffer (this is only about 130 MB), and then copied the bytes from the buffer.

So, I did the following:

 public init() { var inputStream = NSInputStream(fileAtPath: "/path/to/file/7CHands.dat")! var inputBuffer = [UInt8](count: 32478734 * 4, repeatedValue: 0) inputStream.open() inputStream.read(&inputBuffer, maxLength: inputBuffer.count) inputStream.close() } 

and it works fine when I debug it, I see that inputBuffer contains the same byte array as my hex editor. Now I would like this data to be effective. I know that it is stored in any format that you call it, where the least significant bytes are first (that is, the Number 0x00011D4A is represented as "4A1D 0100" in the file). I am tempted to simply iterate over it manually and calculate the byte values ​​manually, but I wonder if it is possible to quickly transfer an array from [Int32] and read these bytes. I tried using NSData, for example:

  let data = NSData(bytes: handNumbers, length: handNumbers.count * sizeof(Int32)) data.getBytes(&inputBuffer, length: inputBuffer.count) 

but this did not seem to load the values ​​(all values ​​were still null). Can someone help me convert this byte array to some Int32 values? It would be best to convert them to Int (i.e. a 64-bit integer) in order to maintain the same variable sizes in the project.

+5
source share
2 answers

Not sure about your identity, but I use the following function. Unlike your code, NSRanges used of the actual type required, not the length of the bytes. This procedure reads one value at a time (this is for ESRI files whose contents vary by field), but should be easily adapted.

 func getBigIntFromData(data: NSData, offset: Int) -> Int { var rng = NSRange(location: offset, length: 4) var i = [UInt32](count: 1, repeatedValue:0) data.getBytes(&i, range: rng) return Int(i[0].bigEndian)// return Int(i[0]) for littleEndian } 
+3
source

Grimxn provided the basis for solving my problem, which showed me how to read buffer sections into an array; he then showed me a way to read the entire buffer completely. Instead of having to convert all elements of the array to Int without the need, I simply read the array in the buffer as UInt32 and casted to Int in a function that accesses this array.

So far, since I do not yet have my utility class, I integrated the Grimxn code directly into my initializer. The class initializer now looks like this:

 public class Evaluator { let HandNumberArraySize = 32487834 var handNumbers: [Int32] public init() { let data = NSData(contentsOfFile: "/path/to/file/7CHands.dat")! var dataRange = NSRange(location: 0, length: HandNumberArraySize * 4) handNumbers = [Int32](count: HandNumberArraySize, repeatedValue: 0) data.getBytes(&handNumbers, range: dataRange) println("Evaluator loaded successfully") } ... } 

... and the function that references them now:

 public func cardVectorToHandNumber(#cards: [Int], numberToUse: Int) -> Int { var output: Int output = Int(handNumbers[53 + cards[0] + 1]) for i in 1 ..< numberToUse { output = Int(handNumbers[output + cards[i] + 1]) } return Int(handNumbers[output]) } 

Thanks to Grimxn and thanks again to StackOverflow for helping me very real!

+2
source

Source: https://habr.com/ru/post/1215154/


All Articles