You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Swift中实现类C的结构体二进制文件读写?

Swift 实现 C 语言 fwrite/fread 结构体读写文件的等效方案

要在Swift中实现和C语言fwrite/fread完全等效的结构体文件读写,核心是保证Swift结构体的内存布局与C完全一致,再通过原始字节操作完成读写。以下是对应你提供的C代码的完整实现:

1. 定义匹配C内存布局的Swift结构体

C语言中结构体默认会有内存对齐填充,Swift默认的结构体布局规则和C一致;如果需要严格紧凑布局(对应C的#pragma pack(1)),可以使用@_packed属性。这里先匹配你未开启pack的C结构体布局:

import Foundation

// 与C的Creature结构体内存布局完全匹配
struct Creature {
    var legs: Int8
    var eyes: Int8
    var hair: Int32
}

// 如果需要对应C的#pragma pack(1)紧凑布局,添加@_packed属性:
// @_packed struct Creature {
//     var legs: Int8
//     var eyes: Int8
//     var hair: Int32
// }

2. 写入结构体到文件(等效fwrite)

通过withUnsafeBytes获取结构体的原始字节指针,将其转换为Data后写入文件,效果和C的fwrite完全一致:

func writeCreatureToFile(_ creature: Creature, path: String) throws {
    // 将结构体转换为原始字节Data
    let data = withUnsafeBytes(of: creature) { Data($0) }
    
    // 写入文件(对应C的wb+模式:读写、覆盖创建、二进制模式)
    try data.write(to: URL(fileURLWithPath: path), options: [.atomic, .withoutOverwriting])
}

3. 从文件读取结构体(等效fread)

读取文件的全部字节后,用withUnsafeMutableBytes将字节复制到结构体实例中,对应C的fread:

func readCreatureFromFile(path: String) throws -> Creature {
    // 读取文件全部字节
    let data = try Data(contentsOf: URL(fileURLWithPath: path))
    
    // 验证字节数是否匹配结构体大小
    guard data.count == MemoryLayout<Creature>.size else {
        throw NSError(domain: "FileError", code: 1, userInfo: [NSLocalizedDescriptionKey: "文件字节数与结构体大小不匹配"])
    }
    
    // 将字节转换为结构体实例
    var creature = Creature()
    _ = withUnsafeMutableBytes(of: &creature) { data.copyBytes(to: $0) }
    
    return creature
}

完整测试代码

对应你提供的C主函数逻辑:

func main() {
    let filePath = "/Users/name/Desktop/code/testing.txt"
    
    // 定义测试结构体
    let birthday = Creature(legs: 6, eyes: 3, hair: 258)
    
    // 写入文件
    do {
        try writeCreatureToFile(birthday, path: filePath)
        print("结构体写入成功")
    } catch {
        print("写入错误:\(error.localizedDescription)")
        return
    }
    
    // 读取文件
    do {
        let shake = try readCreatureFromFile(path: filePath)
        print("Legs: \(shake.legs) Eyes: \(shake.eyes) Hair: \(shake.hair)")
    } catch {
        print("读取错误:\(error.localizedDescription)")
    }
}

// 执行测试
main()

关键注意事项

  • 内存布局一致性:如果你的C结构体开启了#pragma pack(1),必须给Swift结构体添加@_packed属性,否则读写的字节会因为填充不匹配而出错。可以通过MemoryLayout<Creature>.size验证大小是否和C的sizeof(struct Creature)一致。
  • 字节序问题:如果文件需要跨平台读写(比如从x86设备写到ARM设备),需要手动处理Int32的字节序(大端/小端),可以用Int32(bigEndian:)或Int32(littleEndian:)转换,对应你C代码中注释的reverseByteOrder逻辑。
  • 文件模式:Swift的write(to:options:)中,.atomic保证写入的原子性,.withoutOverwriting对应C的wb+中的创建覆盖行为;如果需要追加写入,可以调整选项为.append。

内容的提问来源于stack exchange,提问作者aar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 11:34:54