2016-11-27 3 views
-1

Я написал этот код Swift, который использует Glibc для загрузки текстовых файлов в строки, но иногда он добавляет ненужные символы, такие как \U{7F} или в конец строки (в том же файле), и я не знаю почему. Ни одна из ошибок проверки функций Glibc не вызывает никаких предупреждений. Это просто неслучайно, даже если оно используется в одном файле.Почему этот код чтения файла дает нежелательную информацию в конце файла?

public typealias Cpath = String 
public typealias Unixpath = String 
public typealias CString = UnsafeMutablePointer<CChar> 

public func unix_path(_ path:Cpath) -> Unixpath 
{ 
    guard path.characters.count > 1 
    else { 
     return path 
    } 
    let path_i0 = path.startIndex 
    let path_i2 = path.index(path_i0, offsetBy: 2) 
    var expanded_path:Unixpath = path 
    if path[path.startIndex..<path_i2] == "~/" { 
     expanded_path = String(cString: getenv("HOME")) + 
         path[path.index(path_i0, offsetBy: 1)..<path.endIndex] 
    } 
    return expanded_path 
} 

public func open_text_file(_ path:Cpath) -> String? 
{ 
    let path = unix_path(path) 

    guard let f:UnsafeMutablePointer<FILE> = fopen(path, "rb") 
    else { 
     print("Error, could not open file '\(path)'") 
     return nil 
    } 
    defer { fclose(f) } 

    let fseek_status = fseeko(f, 0, SEEK_END) 
    guard fseek_status == 0 
    else { 
     print("Error, fseeko() failed with error code \(fseek_status)") 
     return nil 
    } 

    let n = ftello(f) 
    guard 0..<CLong.max ~= n 
    else { 
     print("Error, ftello() returned file size outsize of allowed range") 
     return nil 
    } 
    rewind(f) 

    guard let raw_buffer:UnsafeMutableRawPointer = malloc(n*MemoryLayout<CChar>.size) 
    else { 
     print("Error, could not allocate memory buffer") 
     return nil 
    } 
    defer { free(raw_buffer) } 

    let n_read = fread(raw_buffer, MemoryLayout<CChar>.size, n, f) 
    guard n_read == n 
    else { 
     print("Error, fread() read \(n_read) characters out of \(n)") 
     return nil 
    } 
    let cchar_buffer:CString = raw_buffer.assumingMemoryBound(to: CChar.self) 
    return String(cString: cchar_buffer) 
} 

ответ

0

Я нашел эту проблему, я опуская часовой (\U{00}), который, как предполагается прийти в конце строки C. Без него конструктор String(cString:) просто пылесосил до тех пор, пока не обнаружил в системной памяти естественный x00 байт. Вот правильная форма:

... 

// n + 1 to leave room for sentinel 
let cchar_buffer:CString = CString.allocate(capacity: n + 1) 
defer { cchar_buffer.deallocate(capacity: n + 1) } 

let n_read = fread(cchar_buffer, MemoryLayout<CChar>.size, n, f) 
guard n_read == n 
else { 
    print("Error, fread() read \(n_read) characters out of \(n)") 
    return nil 
} 
cchar_buffer[n] = 0 // cap with sentinel 
return String(cString: cchar_buffer)