我需要从Swift中的二进制.hgt文件中读取高程数据。我找到this result for c,但我无法将其迁移到Swift。
#include <stdio.h>
#define SIZE 1201
signed short int matrix[SIZE][SIZE] = {0};
int main(int argc, const char * argv[])
{
FILE *fp = fopen("N49E013.hgt", "rb");
unsigned char buffer[2];
for (int i = 0; i < SIZE; ++i)
{
for (int j = 0; j < SIZE; ++j)
{
if (fread(buffer, sizeof(buffer), 1, fp) != 1)
{
printf("Error reading file!\n");
system("PAUSE");
return -1;
}
matrix[i][j] = (buffer[0] << 8) | buffer[1];
}
}
fclose(fp);
}
答案 0 :(得分:3)
#define SIZE 1201
这定义了一个名为'SIZE'的常量,所以这样做:
let size = 1201
下:
FILE *fp = fopen("N49E013.hgt", "rb");
这将打开一个文件供阅读。我们能做到这一点。在'defer'块中关闭文件,这样无论如何,文件都会在我们完成后关闭。
// change the path below to the correct path
let handle = try FileHandle(forReadingFrom: URL(fileURLWithPath: "/path/to/N49E013.hgt"))
defer { handle.closeFile() }
现在,构建矩阵。我们想要从文件中读取size
个数组,每个数组都有size
个元素。原来使用了两个嵌套的for循环,但Swift支持函数式编程结构,我们可以用它来更优雅地做到这一点:
let matrix = try (0..<size).map { _ in
try (0..<size).map { _ -> Int in
// Unfortunately, FileHandle doesn't have any decent error-reporting mechanism
// other than Objective-C exceptions.
// If you need to catch errors, you can use fread as in the original,
// or use an Objective-C wrapper to catch the exceptions.
let data = handle.readData(ofLength: 2)
if data.count < 2 { throw CocoaError(.fileReadCorruptFile) }
return (Int(data[0]) << 8) | Int(data[1])
}
}
认为应该这样做。
答案 1 :(得分:0)
我最近正在实施相同的问题,但是发现Charles Srstka提供的解决方案有点慢。在2016年末的15英寸MBP上加载一个文件大约需要10秒钟。
我进行了一些微调,使用直接访问内存并按行而不是2个字节读取它使速度提高了约50倍。
static let size = 1201
static func read(from path: String) throws -> [[UInt16]] {
let handle = try FileHandle(forReadingFrom: URL(fileURLWithPath: path))
defer { handle.closeFile() }
// Calculate all the necessary values
let unitSize = MemoryLayout<UInt16>.size
let rowSize = size * unitSize
let expectedFileSize = size * rowSize
// Get fileSize
let fileSize = handle.seekToEndOfFile()
// Check file size
guard fileSize == expectedFileSize else {
throw CocoaError(.fileReadCorruptFile)
}
// Go back to the start
handle.seek(toFileOffset: 0)
// Iterate
let matrix: [[UInt16]] = (0..<size).map { _ in
// Read a row
let data = handle.readData(ofLength: rowSize)
// With bytes...
let row: [UInt16] = data.withUnsafeBytes { (bytes: UnsafePointer<UInt16>) -> [UInt16] in
// Get the buffer. Count isn't using rowSize because it calculates number of bytes based on data type
let buffer = UnsafeBufferPointer<UInt16>(start: bytes, count: size)
// Create an array
return Array<UInt16>(buffer)
}
// Return row, swapping from Little to Big endian
return row.map { CFSwapInt16HostToBig($0) }
}
return matrix
}