Skip to Content
Course content

190: Working with File Extensions and Base Names

Click on the "Edit" button in the top corner of the screen to edit your slide content.

When you're building tools that touch the filesystem, you'll quickly realize that paths are messy. You've got absolute paths, relative paths, and the headache of different separators on Windows versus Linux. Instead of trying to split strings manually with strings.Split, we use the path/filepath package. It's designed to handle these cross-platform quirks for you.

How do I strip away the folder path to get just the filename?

If you have a path like /home/user/projects/app/config.yaml, you usually don't care about the directories; you just want config.yaml. For this, I always use filepath.Base(). It looks at the path and returns the last element.

package main

import (
	"fmt"
	"path/filepath"
)

func main() {
	fullPath := "/var/log/system/auth.log"
	filename := filepath.Base(fullPath)
	fmt.Println(filename) // Output: auth.log
}

One thing to keep in mind: if the path ends in a separator, Base will return the name of the last directory. It's a helpful detail, but it can trip you up if you're expecting a file and accidentally pass it a directory path.

How do I actually isolate the file extension?

Checking file types is a common task—say, ensuring a user only uploaded a .png or .jpg. The filepath.Ext() function is the way to go here. Just be careful: Ext() returns the extension including the leading dot.

package main

import (
	"fmt"
	"path/filepath"
)

func main() {
	file := "vacation_photo.jpg"
	ext := filepath.Ext(file)
	
	fmt.Println(ext) // Output: .jpg

	if ext == ".jpg" || ext == ".jpeg" {
		fmt.Println("This is a JPEG image!")
	}
}

I've seen a lot of developers try to slice the string manually to remove that dot, but if you're just comparing the extension to a known value, it's easier to just include the dot in your comparison string.

What's the easiest way to get the filename without the extension?

This is where Go is surprisingly minimal. There isn't a single filepath.BaseWithoutExt() function. To get just the "stem" of the filename (like vacation_photo from vacation_photo.jpg), you have to combine Base() and Ext().

The trick is to get the base name, find the length of the extension, and then slice the base name string to remove that trailing portion.

package main

import (
	"fmt"
	"path/filepath"
)

func main() {
	path := "/etc/nginx/nginx.conf"
	
	base := filepath.Base(path) // "nginx.conf"
	ext := filepath.Ext(path)   // ".conf"
	
	// We slice the base string from the start up to 
	// the total length minus the length of the extension.
	nameWithoutExt := base[:len(base)-len(ext)]
	
	fmt.Println(nameWithoutExt) // Output: nginx
}

I usually wrap this logic in a small helper function in my projects because I use it so often. It keeps the main business logic clean and prevents me from writing that slicing math over and over again.




📋 Practical Task

Exercise: Log File Archive Renamer

You are building a log rotation tool. Your task is to take a slice of full file paths and generate a new slice of "archive names." For every file, you must remove the directory path and the .log extension, and append _backup.bak to the end.

Example:
Input: "/var/log/syslog.log" → Output: "syslog_backup.bak"
Input: "C:\logs\app_error.log" → Output: "app_error_backup.bak"

Write a function ArchiveName(path string) string that implements this logic using the path/filepath package. Test it with a slice of at least three different paths to ensure it handles different folder depths correctly.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.