golang学习十五:文件操作

os包结构介绍

  • • Go语言标准库中os包提供了不依赖平台的操作系统接口

  • • 设计为Unix风格的,而错误处理是go风格的,失败的调用会返回错误值而非错误码。通常错误值里包含更多信息

  • • os包及子包功能

-- os 包
  --os/exec 包,负责执行外部命令.
  --os/signal对输入信息的访问
  --os/user 通过名称或ID 查询用户账户
  • • 在os/user中提供了User结构体,表示操作系统用户

    • • Uid 用户id

    • • Gid 所属组id

    • • Username 用户名

    • • Name 所属组名

    • • HomeDir 用户对应文件夹路径

// User represents a user account.
type User struct {
    // Uid is the user ID.
    // On POSIX systems, this is a decimal number representing the uid.
    // On Windows, this is a security identifier (SID) in a string format.
    // On Plan 9, this is the contents of /dev/user.
    Uid string
    // Gid is the primary group ID.
    // On POSIX systems, this is a decimal number representing the gid.
    // On Windows, this is a SID in a string format.
    // On Plan 9, this is the contents of /dev/user.
    Gid string
    // Username is the login name.
    Username string
    // Name is the user's real or display name.
    // It might be blank.
    // On POSIX systems, this is the first (or only) entry in the GECOS field
    // list.
    // On Windows, this is the user's display name.
    // On Plan 9, this is the contents of /dev/user.
    Name string
    // HomeDir is the path to the user's home directory (if they have one).
    HomeDir string
}
  • • 在os/user中的Group表示用户所属组

    • • Gid 组的id

    • • Name 组的名称

// Group represents a grouping of users.
//
// On POSIX systems Gid contains a decimal number representing the group ID.
type Group struct {
    Gid  string // group ID
    Name string // group name
}
  • • 整个os/user包中内容比较少,提供了两个错误类型和获取当前用户,查找用户

type UnknownUserError
  func (e UnknownUserError) Error() string
type UnknownUserIdError
  func (e UnknownUserIdError) Error() string
type User
  func Current() (*User, error)
  func Lookup(username string) (*User, error)
  func LookupId(uid string) (*User, error)

代码示例

  • • 可以获取当前用户或查找用户后获取用户信息

   //获取当前登录用户
   //u,_:=user.Current()
   /*
   Lookup()参数是用户名,按照用户名查找指定用户对象
   注意:必须使用完整名称不可以只写zhang
    */

   u, _ := user.Lookup(`LAPTOP-APM56maishuren`)
   fmt.Println(u.Name)
   fmt.Println(u.Gid)
   fmt.Println(u.HomeDir)
   fmt.Println(u.Uid)
   fmt.Println(u.Username)

os包内容介绍

  • • 使用os包中内容进行操作系统文件或目录

  • • File结构体表示操作系统文件(夹)

// File represents an open file descriptor.
type File struct {
    *file // os specific
}
// file is the real representation of *File.
// The extra level of indirection ensures that no clients of os
// can overwrite this data, which could cause the finalizer
// to close the wrong file descriptor.
type file struct {
    pfd     poll.FD
    name    string
    dirinfo *dirInfo // nil unless directory being read
}
  • • 操作系统的文件都是有权限控制的,包含可读,可写等,在os包中FileMode表示文件权限,本质是uint32,可取值都以常量形式提供

// A FileMode represents a file's mode and permission bits.
// The bits have the same definition on all systems, so that
// information about files can be moved from one system
// to another portably. Not all bits apply to all systems.
// The only required bit is ModeDir for directories.
type FileMode uint32
// The defined file mode bits are the most significant bits of the FileMode.
// The nine least-significant bits are the standard Unix rwxrwxrwx permissions.
// The values of these bits should be considered part of the public API and
// may be used in wire protocols or disk representations: they must not be
// changed, although new bits might be added.
const (
    // The single letters are the abbreviations
    // used by the String method's formatting.
    ModeDir        FileMode = 1 << (32 - 1 - iota// d: is a directory
    ModeAppend                                     // a: append-only
    ModeExclusive                                  // l: exclusive use
    ModeTemporary                                  // T: temporary file; Plan 9 only
    ModeSymlink                                    // L: symbolic link
    ModeDevice                                     // D: device file
    ModeNamedPipe                                  // p: named pipe (FIFO)
    ModeSocket                                     // S: Unix domain socket
    ModeSetuid                                     // u: setuid
    ModeSetgid                                     // g: setgid
    ModeCharDevice                          // c: Unix character device, when ModeDevice is set
    ModeSticky                                     // t: sticky

    // Mask for the type bits. For regular files, none will be set.
    ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice

    ModePerm FileMode = 0777 // Unix permission bits
)
  • • FIleInfo是一个interface表示文件的信息

// A FileInfo describes a file and is returned by Stat and Lstat.
type FileInfo interface {
    Name() string       // base name of the file
    Size() int64        // length in bytes for regular files; system-dependent for others
    Mode() FileMode     // file mode bits
    ModTime() time.Time // modification time
    IsDir() bool        // abbreviation for Mode().IsDir()
    Sys() interface{}   // underlying data source (can return nil)
}

资源路径

  • • 在获取系统资源时资源路径分为相对路径和绝对路径

  • • 相对路径:在Go语言中相对路径用于是GOPATH,也就是项目的根目录

  • • 绝对路径:磁盘根目录开始表示资源详细路径的描述

代码示例

  • • Go语言标准库中提供了两种创建文件夹的方式

    /*
    要求文件夹不存在且父目录必须存在,才能创建
     */

    //error := os.Mkdir("D:/godir", os.ModeDir)
    //if error != nil {
    // fmt.Println("文件夹创建失败",error)
    // return
    //}
    //fmt.Println("文件夹创建成功")


    /*
    如果文件夹已经存在,不报错,保留原文件夹
    如果父目录不存在帮助创建
     */

    error := os.MkdirAll("D:/godir/a/b", os.ModeDir)
    if error != nil {
        fmt.Println("文件夹创建失败",error)
        return
    }
    fmt.Println("文件夹创建成功")
  • • 创建空文件

    /*
    创建文件时要求文件目录必须已经存在
    如果文件已经存在则会创建一个空文件覆盖之前的文件
     */

    file, err := os.Create("D:/godir/test.txt")
    if err != nil {
        fmt.Println("文件创建失败,", err)
        return
    }
    fmt.Println("文件创建成功",file.Name())
  • • 重命名文件或文件夹

    /*
    第一个参数:原文件夹名称,要求此路径是必须存在的
    第二个参数:新文件夹名称
     */

    err := os.Rename("D:/godir""D:/godir1")
    if err != nil {
        fmt.Println("重命名文件夹失败,", err)
        return
    }
    fmt.Println("文件夹重命名成功")

    /*
    重命名文件和重命名文件夹用法相同
     */

    err = os.Rename("D:/godir1/test.txt""D:/godir1/test1.txt")
    if err != nil {
        fmt.Println("重命名文件失败,", err)
        return
    }
    fmt.Println("文件重命名成功")
  • • 获取文件(夹)信息

    f, err := os.Open("D:/godir1/test1.txt")
    defer f.Close() //文件打开后要关闭,释放资源
    if err != nil {
        fmt.Println("打开文件失败", err)
        return
    }
    fileInfo, err := f.Stat()
    if err != nil {
        fmt.Println("获取文件信息失败", err)
        return
    }
    fmt.Println(fileInfo.Name())    //文件名
    fmt.Println(fileInfo.IsDir())   //是否是文件夹,返回bool,true表示文件夹,false表示文件
    fmt.Println(fileInfo.Mode())    //文件权限
    fmt.Println(fileInfo.ModTime()) //修改时间
    fmt.Println(fileInfo.Size())    //文件大小
  • • 删除文件或文件夹

    /*
    删除的内容只能是一个文件或空文件夹且必须存在
     */

    //err := os.Remove("D:/godir1/a")
    //if err != nil {
    // fmt.Println("文件删除失败", err)
    // return
    //}
    //fmt.Println("删除成功")

    /*
    只要文件夹存在,删除文件夹.
    无论文件夹是否有内容都会删除
    如果删除目标是文件,则删除文件
     */

    err := os.RemoveAll("D:/godir1/a.txt")
    if err != nil {
        fmt.Println("删除失败", err)
        return
    }
    fmt.Println("删除成功")

输入流

  • • 流(stream)是应用程序和外部资源进行数据交互的纽带

  • • 流分为输入流和输出流,输入和输出都是相对于程序,把外部数据传入到程序中叫做输入,反之叫做输出流

  • • 输入流(Input Stream),输入流(Output Stream) 平时所说的I/O流

  • • 在Go语言标准库中io包下是Reader接口表示输入流,只要实现这个接口就属于输入流

// Reader is the interface that wraps the basic Read method.
//
// Read reads up to len(p) bytes into p. It returns the number of bytes
// read (0 <= n <= len(p)) and any error encountered. Even if Read
// returns n < len(p), it may use all of p as scratch space during the call.
// If some data is available but not len(p) bytes, Read conventionally
// returns what is available instead of waiting for more.
//
// When Read encounters an error or end-of-file condition after
// successfully reading n > 0 bytes, it returns the number of
// bytes read. It may return the (non-nil) error from the same call
// or return the error (and n == 0) from a subsequent call.
// An instance of this general case is that a Reader returning
// a non-zero number of bytes at the end of the input stream may
// return either err == EOF or err == nil. The next Read should
// return 0, EOF.
//
// Callers should always process the n > 0 bytes returned before
// considering the error err. Doing so correctly handles I/O errors
// that happen after reading some bytes and also both of the
// allowed EOF behaviors.
//
// Implementations of Read are discouraged from returning a
// zero byte count with a nil error, except when len(p) == 0.
// Callers should treat a return of 0 and nil as indicating that
// nothing happened; in particular it does not indicate EOF.
//
// Implementations must not retain p.
type Reader interface {
    Read(p []byte) (n int, err error)
}

代码演示

  • • 可以使用strings包下的NewReader创建字符串流

    r := strings.NewReader("hello 世界")
    b := make([]byte, r.Size())//创建字节切片,存放流中数据,根据流数据大小创建切片大小
    n, err := r.Read(b)//把流中数据读取到切片中
    if err != nil {
        fmt.Println("读取失败,", err)
        return
    }
    fmt.Println("读取数据长度,", n)

    fmt.Println("流中数据",string(b))//以字符串形式输入切片中数据
  • • 最常用的是文件流,把外部文件中数据读取到程序中

    f, err := os.Open("D:/go.txt")//打开文件
    defer f.Close()
    if err != nil {
        fmt.Println("文件读取失败,", err)
        return
    }
    fileInfo, err := f.Stat()//获取文件信息
    if err != nil {
        fmt.Println("文件信息获取失败,", err)
        return
    }
    b := make([]byte, fileInfo.Size())//根据文件中数据大小创建切片
    _, err = f.Read(b)//读取数据到切片中
    if err != nil {
        fmt.Println("文件流读取失败:", err)
        return
    }
    fmt.Println("文件中内容为:"string(b))//以字符串形式输入切片中数据

输入流

  • • 输入流就是把程序中数据写出到外部资源

  • • Go语言标准库中输出流是Writer接口

// Writer is the interface that wraps the basic Write method.
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p))
// and any error encountered that caused the write to stop early.
// Write must return a non-nil error if it returns n < len(p).
// Write must not modify the slice data, even temporarily.
//
// Implementations must not retain p.
type Writer interface {
    Write(p []byte) (n int, err error)
}

代码操作

  • • 注意:输入流时不要使用os.Open()因为这种方式获取的文件是只读的

    fp := "D:/go.txt"
    /*
    第三个参数表示文件权限
    第 1 位在权限中总是为 0
    第 2 位为 0 表示文件不可以被读, 为 1 表示可以被读
    第 3 位为 0 表示文件不可以被写, 为 1 表示可以被写
    第 4 位为 0 表示文件不可以被执行, 为 1 表示可以被执行
    整理如下:
       0(0000): 不可读写,不能被执行
       1(0001): 不可读写,能被执行
       2(0010): 可写不可读,不能被执行
       3(0011): 可写不可读,能被执行
       4(0100): 可读不可写,不能被执行
       5(0101): 可读不可写,能被执行
       6(0110): 可读写,不能执行
       7(0111): 可读写,可执行

    0666:
    第一个 0 表示这个数是 八进制
    第一个 6 表示文件拥有者有读写权限,但没有执行权限
    第二个 6 表示文件拥有者同组用户有读写权限,但没有执行权限
    第三个 6 表示其它用户有读写权限,但没有执行权限

     */


    //第二个参数表示文件内容追加
    //第三个参数表示创建文件时文件权限
    f, err := os.OpenFile(fp, os.O_APPEND, 0660)
    defer f.Close()
    if err != nil {
        fmt.Println("文件不存在,创建文件")
        f, _ = os.Create(fp)
    }

    /*
    内容中识别特殊字符
    rn 换行
    t 缩进
     */


    /*
    使用文件对象重写的Writer接口,参数是[]byte
     */

    f.Write([]byte("使用Writer接口写数据rn"))

    /*
    使用stringWriter接口的方法,参数是字符串,使用更方便
     */

    f.WriteString("写了t一段rn内容123")
    fmt.Println("程序执行结束")

ioutil包

  • • ioutil包下提供了对文件读写的工具函数,通过这些函数快速实现文件的读写操作

  • • ioutil包下提供的函数比较少,但是都是很方便使用的函数

func NopCloser(r io.Reader) io.ReadCloser
func ReadAll(r io.Reader) ([]byte, error)
func ReadFile(filename string) ([]byte, error)
func WriteFile(filename string, data []byte, perm os.FileMode) error
func ReadDir(dirname string) ([]os.FileInfo, error)
func TempDir(dir, prefix string) (name string, err error)
func TempFile(dir, prefix string) (f *os.File, err error)

代码演示

  • • 打开完文件后可以使用ReadAll把文件中所有内容都读取到

    f, err := os.Open("D:/go.txt")
    defer f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
    b, err := ioutil.ReadAll(f)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("文件中内容:n"string(b))
  • • 也可以直接读取文件中内容

    b, err := ioutil.ReadFile("D:/go.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(string(b))
  • • 写文件也很简单,直接使用WriteFile函数即可,但是源码中已经规定此文件只能是可写状态,且不是尾加数据

    err := ioutil.WriteFile("D:/abc.txt", []byte("内容123123"), 0666)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("数据写入成功")
  • • 还提供了快速获取某个文件夹中所有文件信息的函数

    fs,_:=ioutil.ReadDir("D:/")
    for _,n := range fs {
        fmt.Println(n.Name())
    }


原文始发于微信公众号(杂食的程序员):golang学习十五:文件操作

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/247281.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!