How to check if a file or directory is hidden in Go

Checking the hidden status of a file or directory is dependent on the operating system that the code is running on. For Unix-based operating systems such as Linux or macOS, all you need to do is check if the first character of the file is a dot character. On Windows, it’s a little more complicated than that

Detect hidden files and directories in Linux and macOS

In Linux and Unix-like operating systems, any file or folder that starts with a dot character (such as .local or .bashrc), commonly called a dotfile, is treated as hidden by file managers and commands such as ls. This makes it really easy to detect a hidden file in Go source code:

hidden_unix.go
// +build !windows

const dotCharacter = 46

func isHidden(path string) bool {
	if path[0] == dotCharacter {
		return true
	}

	return false
}

All you need to do is check if the first character of the filename is a period. If it is, the file is hidden. Otherwise, it’s not. Note that 46 is the character code of a period, which is why it is used in the comparison.

Detect hidden files and directories in Windows

For Windows, the hidden status of a file or directory is not determined by whether or not it starts with a dot character. Rather, it’s determined by a Hidden file attribute which is manipulated through the attrib command. You can also view and set the status of this attribute through the file properties dialog.

Windows properties dialog

Therefore, checking if a file is hidden in Windows involves checking the status of the Hidden attribute as shown below:

hidden_windows.go
// +build windows

package main

import (
	"path/filepath"
	"syscall"
)

const dotCharacter = 46

// isHidden checks if a file is hidden on Windows.
func isHidden(path string) (bool, error) {
	// dotfiles also count as hidden (if you want)
	if path[0] == dotCharacter {
		return true, nil
	}

	absPath, err := filepath.Abs(path)
	if err != nil {
		return false, err
	}

	// Appending `\\?\` to the absolute path helps with
	// preventing 'Path Not Specified Error' when accessing
	// long paths and filenames
	// https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd
	pointer, err := syscall.UTF16PtrFromString(`\\?\` + absPath)
	if err != nil {
		return false, err
	}

	attributes, err := syscall.GetFileAttributes(pointer)
	if err != nil {
		return false, err
	}

	return attributes&syscall.FILE_ATTRIBUTE_HIDDEN != 0, nil
}

When using the code, make sure you set build constraints on the files where these functions are placed so that they will only be included in the build for the relevant operating system.

Thanks for reading, and happy coding!