为什么在NetFSMountURLSync命令行的参数中不使用瑞典字符?

时间:2016-11-06 17:11:05

标签: swift xcode macos

我尝试过我的第一个Swift程序。它应该从带有参数和装载服务器卷的shell脚本运行。当我从Xcode启动程序时,在卷名(例如å,ä,ö)中有瑞典字符的参数,程序就可以正常工作。如果我从命令行启动程序,并在卷名中使用带有瑞典字符的参数,则挂载失败,它会在挂载点创建一个文件夹,并在“/ Volumes”中使用正确的名称。

为什么瑞典字符的参数不能在命令行中起作用?

代码:

import Foundation
import NetFS

func mountShare(serverAddress: String, shareName: String, userName: String, password: String) {
    let fm = FileManager.default
    let mountPoint = "/Volumes/".appendingFormat(shareName)
    var isDir : ObjCBool = false
    if fm.fileExists(atPath: mountPoint, isDirectory: &isDir) {
        if isDir.boolValue {
            unmount(mountPoint, 0)
            print("Unmounted: \(mountPoint)")
        }
    }
    let sharePathRaw = "\(serverAddress)/\(shareName)"
    let sharePathWithPercentEscapes = sharePathRaw.addingPercentEncoding( withAllowedCharacters: .urlQueryAllowed)
    let sharePath = NSURL(string: sharePathWithPercentEscapes!)
    let kNAUIOptionKey = "UIOption"
    let kNAUIOptionNoUI = "NoUI"
    let mount_options = NSMutableDictionary()
    mount_options[kNAUIOptionKey] = kNAUIOptionNoUI
    NetFSMountURLSync(sharePath as CFURL!, nil, userName as CFString!, password as CFString!, mount_options, nil, nil)
}

let argCount = CommandLine.argc
if argCount == 5 {
    let serverUrl = CommandLine.arguments[1]
    let shareName = CommandLine.arguments[2]
    let userName = CommandLine.arguments[3]
    let password = CommandLine.arguments[4]
    mountShare(serverAddress: "\(serverUrl)", shareName: "\(shareName)", userName: "\(userName)", password: "\(password)")
} else {
    print("Wrong number of arguments.")
}

从命令行起作用的示例:

mountVolume "afp://my.server.com" "myVolume" "user" "password"

从命令行启动程序的示例不起作用:

mountVolume "afp://my.server.com" "myVolumeÅÄÖ" "user" "password"

更多信息: 我试图打印出所有变量来比较值,当我从Xcode运行程序替代命令行时没有区别。但是,NetFSMountURLSync在命令行上以代码2而不是0退出。

2 个答案:

答案 0 :(得分:0)

如果您在将连接字符串的相关部分中的所有特殊字符传递给NSURL的初始化之前,它是否有效?

let encodedShareName = shareName.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
let sharePathRaw = "\(serverAddress)/\(encodedShareName!)"

答案 1 :(得分:0)

首先,您应该修复构建URL的方式。使用NSURLComponents而不是连接和转义/引用字符串。从服务器URL字符串创建NSURLComponents,然后从共享名称设置其path属性,然后使用其url属性获取URL对象。

其次,您需要检查NetFSMountURLSync()的返回代码,以深入了解失败的原因。

第三,您的共享名称中的瑞典字符可以用两种不同的方式表示。例如,“Å”可能是单个Unicode字符,U + 00C5 LATIN CAPITAL LETTER A WITH RING ABOVE。以UTF-8编码,即字节0xC3 0x85。或者,它可能是两个Unicode字符:一个普通的A(U + 0041 LATIN CAPITAL LETTER A),然后是一个上面的组合环(U + 030A COMBINING RING ABOVE)。该序列的UTF-8将是0x41 0xCC 0x8A。

您输入角色的两个不同位置(Xcode的控制台窗格与终端窗口)可能会为相同的击键产生不同的实际字符。这意味着网址不一样。

同样的事情适用于您的共享名称中的其他瑞典字符。

您可以使用时髦的技巧在命令行中输入正确的字符,例如在$'\x41\xCC\x8A'中使用bash来获取第二种形式的“Å”。

由文件服务器决定它是否将两条路径视为相同。您的程序要么必须熟悉有问题的服务器并转换为其约定,要么尝试各种规范化策略(例如使用decomposedStringWithCanonicalMappingprecomposedStringWithCanonicalMapping)作为回退,如果挂载尝试失败,因为共享名称是不对的。