package fsutil import ( "fmt" "io" "os" "github.com/gookit/goutil/x/basefn" ) // ************************************************************ // temp file or dir // ************************************************************ // OSTempFile create a temp file on os.TempDir() // // Usage: // // fsutil.OSTempFile("example.*.txt") func OSTempFile(pattern string) (*os.File, error) { return os.CreateTemp(os.TempDir(), pattern) } // TempFile is like os.CreateTemp, but can custom temp dir. // // Usage: // // // create temp file on os.TempDir() // fsutil.TempFile("", "example.*.txt") // // create temp file on "testdata" dir // fsutil.TempFile("testdata", "example.*.txt") func TempFile(dir, pattern string) (*os.File, error) { return os.CreateTemp(dir, pattern) } // OSTempDir creates a new temp dir on os.TempDir and return the temp dir path // // Usage: // // fsutil.OSTempDir("example.*") func OSTempDir(pattern string) (string, error) { return os.MkdirTemp(os.TempDir(), pattern) } // TempDir creates a new temp dir and return the temp dir path // // Usage: // // fsutil.TempDir("", "example.*") // fsutil.TempDir("testdata", "example.*") func TempDir(dir, pattern string) (string, error) { return os.MkdirTemp(dir, pattern) } // ************************************************************ // write, copy files // ************************************************************ // MustSave create file and write contents to file, panic on error. // // - data type allow: string, []byte, io.Reader // // default option see NewOpenOption() func MustSave(filePath string, data any, optFns ...OpenOptionFunc) { basefn.MustOK(SaveFile(filePath, data, optFns...)) } // SaveFile create file and write contents to file. will auto create dir. // // - data type allow: string, []byte, io.Reader // // default option see NewOpenOption() func SaveFile(filePath string, data any, optFns ...OpenOptionFunc) error { opt := NewOpenOption(optFns...) return WriteFile(filePath, data, opt.Perm, opt.Flag) } // WriteData Quick write any data to file, alias of PutContents func WriteData(filePath string, data any, fileFlag ...int) (int, error) { return PutContents(filePath, data, fileFlag...) } // PutContents create file and write contents to file at once. Will auto create dir // // data type allows: string, []byte, io.Reader // // Tip: file flag default is FsCWTFlags (override write) // // Usage: // // fsutil.PutContents(filePath, contents, fsutil.FsCWAFlags) // append write // fsutil.Must2(fsutil.PutContents(filePath, contents)) // panic on error func PutContents(filePath string, data any, fileFlag ...int) (int, error) { f, err := QuickOpenFile(filePath, basefn.FirstOr(fileFlag, FsCWTFlags)) if err != nil { return 0, err } return WriteOSFile(f, data) } // WriteFile create file and write contents to file, can set perm for a file. // // data type allows: string, []byte, io.Reader // // Tip: file flag default is FsCWTFlags (override write) // // Usage: // // fsutil.WriteFile(filePath, contents, fsutil.DefaultFilePerm, fsutil.FsCWAFlags) func WriteFile(filePath string, data any, perm os.FileMode, fileFlag ...int) error { flag := basefn.FirstOr(fileFlag, FsCWTFlags) f, err := OpenFile(filePath, flag, perm) if err != nil { return err } _, err = WriteOSFile(f, data) return err } // WriteOSFile write data to give os.File, then close file. // // data type allows: string, []byte, io.Reader func WriteOSFile(f *os.File, data any) (n int, err error) { switch typData := data.(type) { case []byte: n, err = f.Write(typData) case string: n, err = f.WriteString(typData) case io.Reader: // eg: buffer var n64 int64 n64, err = io.Copy(f, typData) n = int(n64) default: _ = f.Close() panic("WriteFile: data type only allow: []byte, string, io.Reader") } if err1 := f.Close(); err1 != nil && err == nil { err = err1 } return n, err } // CopyFile copy a file to another file path. func CopyFile(srcPath, dstPath string) error { srcFile, err := os.OpenFile(srcPath, FsRFlags, 0) if err != nil { return err } defer srcFile.Close() // create and open file dstFile, err := QuickOpenFile(dstPath, FsCWTFlags) if err != nil { return err } defer dstFile.Close() _, err = io.Copy(dstFile, srcFile) return err } // MustCopyFile copy file to another path. func MustCopyFile(srcPath, dstPath string) { err := CopyFile(srcPath, dstPath) if err != nil { panic(err) } } // UpdateContents read file contents, call handleFn(contents) handle, then write updated contents to file func UpdateContents(filePath string, handleFn func(bs []byte) []byte) error { osFile, err := os.OpenFile(filePath, os.O_RDWR|os.O_TRUNC, 0600) if err != nil { return err } defer osFile.Close() // read file contents if bs, err1 := io.ReadAll(osFile); err1 == nil { bs = handleFn(bs) _, err = osFile.Write(bs) } else { err = err1 } return err } // CreateSymlink creates a symbolic link func CreateSymlink(target, linkPath string) error { // Check if the link already exists if IsFile(linkPath) { // Remove existing link/file if err := os.Remove(linkPath); err != nil { return fmt.Errorf("failed to remove existing symlink: %w", err) } } return os.Symlink(target, linkPath) }