首页  >  文章  >  后端开发  >  在 GO 中整理您的下载

在 GO 中整理您的下载

Linda Hamilton
Linda Hamilton原创
2024-10-31 05:44:30965浏览

Organizador de seus downloads em GO

大家好,离子又来了。

害怕学习人工智能有一天会完成的事情让我感到非常痛苦。但是,如果“解决问题”仍然是对未来人类的要求,为什么不坚持呢?

这次我又带来了一个教程。比第一个没啥用。那么我们来定义一下“问题”的结构,因为我们已经知道一件事:那些没有问题的人,是因为他们看起来不够。对于那些还没有找到它们的人来说,创建它们只是时间问题。

项目结构

程序最简单的结构是:

  • 扫描文件夹(例如下载文件夹或其他目录)
  • 识别相关目录中每个文件的类型
  • 将文件移动到与其类型对应的子文件夹(图像、视频、文档...)

启动项目

创建一个目录并导航到它:

mkdir organizador
cd organizador

创建一个 Organizer.go 文件并启动其模块:

touch organizador.go
go mod init organizador.go

你应该有或多或少像这样的东西:

~/organizador
.
├── go.mod
└── organizador.go

第 1 部分:检查目录是否存在

让我们定义源目录dirOrigem,我们将在其中执行组织。定义后,我们检查它是否确实存在,否则我们将返回错误:

package main

import (
    "fmt"
    "os"
)

// Defina o deretório o qual você quer organizar como variável global
var dirOrigem string := "/Users/User/Downloads" // Troque o diretório 

func main() {

    // Verificar se o diretório existe, caso contrário, retornar erro
    if _, err := os.Stat(dirOrigem); os.IsNotExist(err) {
        fmt.Println("BAD DIR :( \nDiretório não encontrado: ", dirOrigem)
        return
    } else {
        // Imprimir mensagem caso o diretório exista
        fmt.Println("GOOD DIR :) \nDiretório encontrado: ", dirOrigem)
    }
}

现在,让我们对上面的代码进行一些考虑:

  • os.Stat函数返回两个类型为os.FileInfo和错误err的值。
  1. FileInfo 是一个返回详细文件信息的接口,在本例中我们不需要。因此,为了忽略这个接口,我们使用_,。但是,我们不想忽略错误: if _, err := ...
  2. 我们将错误 err 作为参数传递给 os.IsNotExist() 函数,因为如果目录不存在,os.Stat() 函数将返回 NOT NULL 错误,从而导致os.IsNotExist() 返回 true,执行我们的消息:BAD DIR :(
  3. 如果 os.IsNotExist() 返回 false,我们将从 else 条件打印消息:GOOD DIR :)

第 2 部分:回调函数概念太疯狂了,伙计!

你有没有注意到,我们在这里一点一点地享受机械键盘声音的比特和字节。 _查卡查卡繁荣! _

现在我们要创建一个回调函数。这是我从未真正了解过的东西,或者从来没有足够的好奇心去质疑我是否在前 golang 生活中的任何 Python 代码中使用过这个概念。

回调函数是一个带有参数传递给另一个函数的函数。

如果您已经熟悉这个概念,那么恭喜您,否则,恭喜您。换句话说,恭喜你!

现在让我们创建一个 filepath.Walk 回调函数,它将作为参数传递给另一个函数。

mkdir organizador
cd organizador
touch organizador.go
go mod init organizador.go

但是等等,filepath.Walk 是如何调用回调函数的?

当您调用 filepath.Walk(sourcedir, listFiles) 时,filepath.Walk 函数会执行遍历 sourcedir 中的所有文件和子目录的繁重工作。

对于找到的每个文件或目录,它都会使用三个参数调用 listFiles 函数:

  • path:当前文件或目录的完整路径。
  • info:一个 os.FileInfo 对象,包含文件/目录的信息(例如名称、是否是目录、大小等)。
  • err:如果访问此文件或目录时出现问题,则会出现错误。

Go 自动理解 listFiles 必须接收这三个参数,因为 filepath.Walk 期望一个完全遵循此签名的函数:

~/organizador
.
├── go.mod
└── organizador.go

请注意,Walk 函数返回一个错误!这是相关的!

这就是为什么我们将函数 filepath.Walk(dirOrigem,listarArquivos) 等同于错误:

package main

import (
    "fmt"
    "os"
)

// Defina o deretório o qual você quer organizar como variável global
var dirOrigem string := "/Users/User/Downloads" // Troque o diretório 

func main() {

    // Verificar se o diretório existe, caso contrário, retornar erro
    if _, err := os.Stat(dirOrigem); os.IsNotExist(err) {
        fmt.Println("BAD DIR :( \nDiretório não encontrado: ", dirOrigem)
        return
    } else {
        // Imprimir mensagem caso o diretório exista
        fmt.Println("GOOD DIR :) \nDiretório encontrado: ", dirOrigem)
    }
}

毕竟,因为它返回一个错误,所以它是一个错误XD

实际例子

以下更详细地介绍了每一步发生的情况:

func main() { 
// Restante do código
.
.
.

// Percorrer e listar os arquivos no diretório dirOrigem
    err := filepath.Walk(dirOrigem, listarArquivos)
    if err != nil {
        fmt.Println("Erro ao percorrer o diretório: ", err)
    }
}

对于 dirOrigem 中的每个文件或目录,filepath.Walk 将调用 listFiles,就好像它是这样的:

// Função que lista os arquivos do diretório
func listarArquivos(caminho string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }

    // Ignorar diretórios e exibir apenas arquivos
    if !info.IsDir() && !strings.HasPrefix(info.Name(), ".") {
        fmt.Println("Arquivo encontrado: ", info.Name())
    }
    return nil
}

在此示例中,对于每个调用:

  • path:接收文件或目录的路径。
  • 信息:包含有关此项目的信息(例如名称和类型)。
  • err:用于捕获访问文件/目录时的任何特定错误。

回调函数

listFiles 是 filepath.Walk 使用这些值自动调用的回调函数。这样,我们就不需要担心设置path、info和err值; filepath.Walk 已经为我们做到了这一点。

PHE!

现在在你的终端中进行顽皮的测试:

// Função Walk()
func Walk(root string, walkFn WalkFunc) error

// Tipo WalkFunc
type WalkFunc func(path string, info os.FileInfo, err error) error

你可以得到结果:

err := filepath.Walk(dirOrgiem, listarArquivos)

或者:

//Percorrer e listar os arquivos no diretório
err := filepath.Walk(dirOrigem, listarArquivos)

在这种情况下,我只是在“下载”中添加了一个额外的“s”,这样原始目录就会不正确。

现在删除 listFiles 函数,因为我们不会使用它。

开个玩笑,我们只是要更改她的名字并添加其他逻辑。

第 3 部分:组织!=组织

组织得很好,组织得很棒。

在我的精彩观察之后,让我们继续我们真正感兴趣的部分:组织整个事情。

人生的一个讽刺是,在整理文件之前,我们必须先整理一下下一步的想法。

我们的下一个功能基本上需要:

  • 根据 dirOrigem 目录中每个文件的扩展名创建子文件夹(如果不存在)。
  • 根据扩展名将文件移动到各自的文件夹中。
  • 但是如果文件已经在组织子文件夹中,则不应再次创建它们。

让我们了解一下这段代码的每个部分的作用:

mkdir organizador
cd organizador

组织文件函数的结构

为目录结构中找到的每个文件或文件夹调用organizeFiles函数。它检查根据扩展名组织每个文件的条件,创建子文件夹并在必要时移动文件。

touch organizador.go
go mod init organizador.go

这里,organizeFiles 函数采用三个参数:

  • path:当前文件或目录的完整路径。
  • info:文件或目录信息,从类型 os.FileInfo.
  • 获取
  • err:尝试访问该项目时可能发生的错误。

首先检查访问文件/目录时是否出现错误。如果是,则立即返回。

过滤文件并忽略隐藏目录

~/organizador
.
├── go.mod
└── organizador.go

此片段进行两项检查:

  • !info.IsDir():检查该项目是否不是目录(即,它是文件)。
  • !strings.HasPrefix(info.Name(), "."):检查文件名是否不以“.”开头,忽略基于 Unix 的系统上的隐藏文件。

如果满足两个条件,则文件将显示为 fmt.Println。

识别文件扩展名并创建子文件夹名称

package main

import (
    "fmt"
    "os"
)

// Defina o deretório o qual você quer organizar como variável global
var dirOrigem string := "/Users/User/Downloads" // Troque o diretório 

func main() {

    // Verificar se o diretório existe, caso contrário, retornar erro
    if _, err := os.Stat(dirOrigem); os.IsNotExist(err) {
        fmt.Println("BAD DIR :( \nDiretório não encontrado: ", dirOrigem)
        return
    } else {
        // Imprimir mensagem caso o diretório exista
        fmt.Println("GOOD DIR :) \nDiretório encontrado: ", dirOrigem)
    }
}

这里:

  • strings.ToLower(filepath.Ext(info.Name())):提取文件扩展名(例如.txt)并将其转换为小写以确保一致性。
  • subfolder := filepath.Join(sourcedir, extension[1:]):创建文件将移动到的子文件夹的完整路径。扩展名[1:]去掉扩展名中的起始点(.),形成子文件夹的名称,如txt。

如果子文件夹尚不存在,则创建它

func main() { 
// Restante do código
.
.
.

// Percorrer e listar os arquivos no diretório dirOrigem
    err := filepath.Walk(dirOrigem, listarArquivos)
    if err != nil {
        fmt.Println("Erro ao percorrer o diretório: ", err)
    }
}

这里,函数:

  • 使用 os.Stat 检查子文件夹是否已存在。
  • 如果子文件夹不存在 (os.IsNotExist(err)),则使用 os.Mkdir(subfolder, os.ModePerm) 创建它。
  • os.ModePerm 设置新文件夹的默认权限。如果创建文件夹时出错,则会显示并返回。

设置文件目标路径

mkdir organizador
cd organizador

此时,destinationPath 代表文件将被移动的最终路径。它是使用 filepath.Join 构造的,用于将子文件夹路径连接到文件名。

检查文件是否已位于目标文件夹中

touch organizador.go
go mod init organizador.go
  • 此代码片段将目标路径与当前文件路径进行比较。如果它们相同,则意味着该文件已位于正确的子文件夹中,因此会被忽略并显示一条消息 (fmt.Printf)。
  • 否则,os.Rename(path, destinationPath) 会将文件移动到子文件夹。如果移动过程中出现错误,则返回。

最终总结

功能:

  1. 滚动目录,检查每个项目。
  2. 忽略隐藏的目录和文件。
  3. 确定文件扩展名以及目标子文件夹。
  4. 创建子文件夹(如果尚不存在)。
  5. 将文件移至子文件夹,除非该文件已存在。

使用 filepath.Walk(dirOrigem, OrganizeFiles) 将此函数传递给目录中的每个文件,使它们全部自动组织。

这段代码非常适合作为文件组织函数,因为它在单个函数中处理创建和移动逻辑 - 一种高效且有组织的结构形式。

回购:https://github.com/ionnss/organizador


***地球上的又一天,
离子

以上是在 GO 中整理您的下载的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn