Golang中处理Whitespace路径错误的方法

Golang中处理Whitespace路径错误的方法 大家好,我是Go语言的新手。在使用包含空格的文件路径时,我遇到了错误。 如何解决这个问题。

16 回复

有解决这个问题的方案吗?

更多关于Golang中处理Whitespace路径错误的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你是如何读取并传递路径的?

如果你直接硬编码路径,它能正常工作吗?

包含空格的文件?很容易解决,重命名它,这样就不会再有空格了。

其他问题?请展示你遇到的相关代码和错误信息。

bufio 包中的 ReadLine 是一个很好的解决方案 👍 👌
我改用 filepath 包中的 func Ext(path string) string 方法来过滤列表,这样就不会处理像 my.txt.pdf 这样的文件了。

感谢先生

但是当文件名包含空格时也会出现这个错误,不仅仅是文件夹的情况。

请看:

输入路径! D:\wanted\GOtut\projects\subtitles\New1 aab.txt ----- 完成 aac.txt ----- 完成 读取数据错误:打开 aad 1.txt: 系统找不到指定的文件。 退出状态 1

eng443:

错误列表:打开 D:\GO\New 1: 系统找不到指定的文件。

我注意到这些路径与首帖中的路径不同,你确定这些路径确实存在吗?

另外你注意到硬编码路径和其他方式输入的路径在错误信息中的区别了吗?硬编码路径完整显示,而另一个路径在空格处被截断。所以极有可能是你读取输入的方式有误,或者对输入进行了某些错误处理空格的后处理操作。

通过:

mDir = filepath.FromSlash(mDir)

当硬编码路径时,两种情况都会出现错误

带空格的路径: 路径是 D:\GO\New 1 错误列表:打开 D:\GO\New 1:系统找不到指定的文件。 退出状态 1

不带空格的路径: 路径是 D:\GO\New1 错误列表:打开 D:\GO\New1:系统找不到指定的文件。 退出状态 1

我担心这可能只是巧合。

目前你从给定路径创建工作项列表,然后通过.txt过滤这个列表(这也会尝试处理像my.txt.pdf这样的文件!),然后尝试在当前工作目录中打开它们,因为你既没有将工作目录切换到给定目录,也没有将给定路径与找到的文件名连接起来。

所以我的假设是,你实际在运行程序的目录中有aab.txtaac.txt文件,但没有aad 1.txt文件。


最后但同样重要的是,一般来说尽量避免在文件名中使用空格和变音符号,甚至尽量只使用小写字母。

要小心这一点,你应该优先使用 path.Join 来拼接路径。


关于 Scan 问题有两种解决方案:

  1. 编写一个合适的命令行界面,将目标作为命令行参数传入。根据所使用的 shell,调用时记得转义空格。
  2. 不要使用 scan,而是使用 bufio 中的 ReadLine,如下面这篇 Stack Overflow 帖子所示:go - 如何在控制台中从标准输入读取?- Stack Overflow

是的,我看到了错误信息中的差异。但我认为这种差异不是由于输入路径的方式造成的,而是由于路径中包含空格。没有空格的路径会完整显示,而另一个路径在空格处被截断。当文件名包含空格时也会出现类似的错误

输入路径! D:\wanted\GOtut\projects\subtitles\New1 aab.txt ----- 完成 aac.txt ----- 完成 读取数据错误:open aad 1.txt: 系统找不到指定的文件。 退出状态 1

手动输入:

eng443: 错误列表:打开 D:\wanted\GOtut\projects\subtitles\New:系统找不到指定的文件。

硬编码:

eng443: 错误列表:打开 D:\GO\New 1:系统找不到指定的文件。

请对比两者,硬编码的路径被完整打印出来了。


我还找到了问题所在,原因是 fmt.Scanln(重点强调):

Scan 函数扫描从标准输入读取的文本,将连续的空格分隔值存储到后续参数中。

所以这个函数会在空格处截断。如果路径确实存在,os.Open 应该不会处理空格时出现问题。

func main() {
    fmt.Println("hello world")
}

以下是代码:

func listOfFiles(dir string) ([]string, error) {
file, err := os.Open(dir)
if err != nil {
fmt.Println("Error list:", err)
os.Exit(1)
}
return file.Readdirnames(-1)
}

进行了两次测试,一次路径中没有空格,另一次路径包含空格。两个文件夹都存在。

请输入路径 D:\wanted\GOtut\projects\subtitles\New1\

aaa.srt ----- 完成

====================== 请输入路径 D:\wanted\GOtut\projects\subtitles\New 1 错误列表:打开 D:\wanted\GOtut\projects\subtitles\New: 系统找不到指定的文件。 退出状态 1

你说得对,在运行程序的目录中确实有 aab.txtaac.txt 文件,但没有 aad 1.txt 文件。

所以我编辑了读写文件的函数代码,改为:

func (d data) saveToFile(filename string) error {
    return ioutil.WriteFile(mDir + filename, []byte(d.tostring()), 0666)
}

func readFromFile(filename string) data {
    bs, err := ioutil.ReadFile(mDir + filename)
    if err != nil {
        fmt.Println("Error read data:", err)
        os.Exit(1)
    }

    s := strings.Split(string(bs), "\n")
    return data(s)
}

这样所有文件都被修改了。

总之,问题确实如你所说,是 fmt.Scanln 造成的。

能否请你提供一个完整且自包含的示例来展示你的问题?

我无法复现该问题:

package main

import (
	"fmt"
	"os"
)

func listOfFiles(dir string) ([]string, error) {
	file, err := os.Open(dir)
	if err != nil {
		fmt.Println("Error list:", err)
		os.Exit(1)
	}
	return file.Readdirnames(-1)
}

func main() {
	files, err := listOfFiles("./a 1")
	fmt.Printf("%#v; %v\n", files, err)

	files, err = listOfFiles("./a1")
	fmt.Printf("%#v, %v\n", files, err)
}
$ ls {a1,"a 1"}                         
a1:
f1  f2

'a 1':
f1  f2
$ go run file.go
[]string{"f1", "f2"}; <nil>
[]string{"f1", "f2"}, <nil>
$ go version
go version go1.10 linux/amd64

这可能是Windows/Linux系统差异造成的…因此我明天到办公室后会立即在Windows机器上尝试。

这是完整的源文件。

package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

type data []string

var mDir string

func main() {
	for {

		fmt.Println("Type the path!")
		fmt.Scanln(&mDir)
		mDir = filepath.FromSlash(mDir)
		data1, _ := listOfFiles(mDir)
		for i := 0; i < len(data1); i++ {
			if strings.Contains(data1[i], ".txt") {
				d1 := readFromFile(data1[i])
				d1.modify()
				d1.saveToFile(data1[i])
				fmt.Println(data1[i], " ----- done")
			}
		}
		fmt.Println("======================")
	}
}

func listOfFiles(dir string) ([]string, error) {
	file, err := os.Open(dir)
	if err != nil {
		fmt.Println("Error list:", err)
		os.Exit(1)
	}
	return file.Readdirnames(-1)
}

func (d data) modify() {
	for i := 0; i < len(d)-1; i += 8 {
		s1 := d[i+6]
		d[i+6] = d[i+5]
		d[i+5] = d[i+4]
		d[i+4] = d[i+3]
		d[i+3] = s1
	}
}

func (d data) tostring() string {
	return strings.Join([]string(d), "\n")
}

func (d data) saveToFile(filename string) error {
	return ioutil.WriteFile(filename, []byte(d.tostring()), 0666)
}

func readFromFile(filename string) data {
	bs, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Println("Error read data:", err)
		os.Exit(1)
	}

	s := strings.Split(string(bs), "\n")
	return data(s)
}

在Go语言中处理包含空格的文件路径时,最常见的问题是没有正确转义或引用路径,导致系统将空格解释为参数分隔符。这通常发生在调用外部命令或使用某些文件操作函数时。以下是几种解决方法,包括示例代码。

1. 使用双引号转义路径

在Windows系统中,路径中的空格需要用双引号包围,以防止命令行解析错误。在Go中,可以通过字符串拼接或fmt.Sprintf来添加双引号。

示例代码:

package main

import (
    "fmt"
    "os/exec"
)

func main() {
    // 假设路径包含空格,例如 "C:\Program Files\example.txt"
    path := `C:\Program Files\example.txt`
    
    // 使用双引号转义路径
    escapedPath := fmt.Sprintf(`"%s"`, path)
    
    // 示例:使用 exec.Command 执行命令(如 type 命令在 Windows 中显示文件内容)
    cmd := exec.Command("cmd", "/c", "type", escapedPath)
    output, err := cmd.Output()
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    fmt.Printf("File content: %s\n", output)
}

2. 使用 filepath 包处理路径

Go的filepath包提供跨平台的路径处理函数,如filepath.Clean可以规范化路径,但它不会自动处理空格转义。在传递路径给外部命令时,仍需手动转义。

示例代码:

package main

import (
    "fmt"
    "os/exec"
    "path/filepath"
)

func main() {
    // 原始路径包含空格
    rawPath := "C:/Program Files/example.txt"
    
    // 使用 filepath.Clean 清理路径(在Windows上,它会转换为反斜杠)
    cleanPath := filepath.Clean(rawPath)
    fmt.Printf("Cleaned path: %s\n", cleanPath) // 输出: C:\Program Files\example.txt
    
    // 转义路径用于命令
    escapedPath := fmt.Sprintf(`"%s"`, cleanPath)
    cmd := exec.Command("cmd", "/c", "echo", escapedPath)
    output, err := cmd.Output()
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }
    fmt.Printf("Output: %s", output) // 输出: "C:\Program Files\example.txt"
}

3. 直接使用Go标准库的文件操作

如果使用Go内置的文件操作(如os.Open),路径中的空格通常不会导致问题,因为这些函数直接处理字符串路径。

示例代码:

package main

import (
    "fmt"
    "os"
)

func main() {
    // 路径包含空格
    path := "C:/Program Files/example.txt" // 或使用反斜杠 "C:\\Program Files\\example.txt"
    
    // 使用 os.Open 打开文件
    file, err := os.Open(path)
    if err != nil {
        fmt.Printf("Error opening file: %v\n", err)
        return
    }
    defer file.Close()
    
    // 读取文件内容示例
    data := make([]byte, 100)
    n, err := file.Read(data)
    if err != nil {
        fmt.Printf("Error reading file: %v\n", err)
        return
    }
    fmt.Printf("Read %d bytes: %s\n", n, string(data[:n]))
}

关键点总结

  • 当路径用于外部命令时(如通过exec.Command),必须用双引号转义包含空格的路径。
  • Go内置文件函数(如os.Openos.Stat)直接处理路径字符串,无需额外转义。
  • 在Windows上,使用反斜杠\或正斜杠/作为路径分隔符均可,filepath包会自动处理。

如果问题涉及特定场景(如网络路径或第三方库),请提供更多细节以便进一步分析。

回到顶部