2015-03-11 16 views
5

Projelerimin bir parçası olarak, sınıflarımdan birinin başlatılmasında okudukları geniş bir 32 bit tam sayı serisinden oluşan bir ikili veri dosyası var. Benim C++ kütüphanesinde, aşağıdaki başlatıcısı ile okunduğunda:Swift'de, var olan bir ikili dosyayı bir dizide nasıl okurum?

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(); 
}; 

ve Swift için taşıma içinde, ben (yalnızca yaklaşık 130 MB var) bir tampon içine dosyanın tamamını okumak ve sonra bayt kopya çıkışı için karar Tamponun

Yani, şunları yaptık:

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() 
} 

ve bunu hata ayıklama zaman ben INPUTBUFFER benim onaltılık editörü olması gerektiği diyor bayt aynı diziyi içeren görebilirsiniz ki çalışıyor. Şimdi, bu verileri oradan etkin bir şekilde almak istiyorum. En az anlamlı baytların ilk olduğu yerde (yani dosyada 0x00011D4A '4A1D 0100' olarak belirtilir) onu çağırdığınız her hangi bir formatta saklandığını biliyorum. Ben sadece elle yineleme ve bayt değerleri elle hesaplamak için cazip değilim, ama ben hızlı bir yol varsa [Int32] bir dizi geçirebilir ve bu baytlar okumak var mı merak ediyorum. NSData kullanarak çalıştı, gibi:

Ancak bu değerler yüklenmemiş gibi görünüyordu (tüm değerler hala sıfırdı). Bu bayt dizisini bazı Int32 değerlerine dönüştürmeme yardımcı olabilir misiniz? Daha da iyisi, değişken boyutlarımın proje boyunca aynı kalmasını sağlamak için onları Int (yani 64 bit tamsayı) haline dönüştürmek olacaktır.

cevap

3

Endian-ness'inizden emin değilim, ancak aşağıdaki işlevi kullanıyorum. Kodunuzdaki fark, bayt uzunlukları yerine gerçek gerekli türden NSRanges kullanıyor. Bu rutin, bir defada bir değer okur (içeriği alana göre değişebilen ESRI dosyaları için), ancak kolayca uyarlanabilir olmalıdır.

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 
} 
+0

Bu işlevi kullanmayı denedim ve sıfırdan başka bir şey elde edemiyorum. Data.getBytes ifadesinin verileri giriş arabelleğinden doğru şekilde yüklemediğini sanmıyorum. İşleviniz iyi işleyebilir, ancak şu anda hiç bir fikrim yok. Herhangi bir neden görüyor musunuz, girişBuffer non-sıfırlar içeriyor biliyorum, neden benim data.getBytes deyim çalışmıyor? – Charles

+1

'data.getBytes (& inputBuffer ...)' * * 'den veriyi okur ve *' inputBuffer 'yerine başka bir şekilde döndürmez. Dosyayı 'NSData' içine okumanız ve doğru boyuttaki tamsayılar dizisine okumanız gerekiyor. – Grimxn

+0

Buna dayanarak, verileri basitçe veri dosyamdaki yolla basitçe başlatmamı basitleştirdim: 'veri ver = NSData (contentOfFile:" /path/to/file/7CHands.dat ")!'Ve bu veri yükleme kadar bir çekicilik gibi çalışır gibi görünüyor, daha sonra fonksiyonunuza basit bir çağrı (ortaya çıktığı gibi, küçük-Hindistan'da) ve her şey gemi şeklindedir. Bu DOES uzun bir süre alıyor, ancak .. Sürüm salınımında bile, C + + anlık iken montaj için 90 saniye sürüyor. İki dil arasındaki fark gerçekten bu kadar önemli mi, yoksa bir yerdeki bir yapı eksik mi? – Charles

2

Grimxn bir diziye tampon bölümleri okuma gösterdi benim sorun için bir çözüm, bel kemiğini oluşturur; Daha sonra bana bütün tamponu bir kerede okumak için bir yol gösterdi. Dizinin tüm öğelerini gereksiz yere Int'a dönüştürmek yerine, diziyi UInt32 olarak arabelleğe okuyorum ve bu diziye erişen işlevde döküm işlemini Int yaptım.

Şimdilik, henüz tanımlanmış bir program sınıfım olmadığından Grimxn'in kodunu doğrudan başlatıcımla bütünleştirdim.

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") 
    } 

... 

} 

... ve onları başvuran işlevi artık: sınıf başlatıcısı şimdi şöyle

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]) 
} 

Grimxn sayesinde ve teşekkür kez daha StackOverflow bir çok gerçek bana yardım için yol!

+0

Harika! Referans fonksiyonunuzun Abonelik protokolüne göz atın. Bu gerekli değil, ancak işleri daha da sıkılaştırabilir ... https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html – Grimxn

İlgili konular