| Crates.io | add_ext |
| lib.rs | add_ext |
| version | 0.1.2 |
| created_at | 2026-01-11 05:37:37.548357+00 |
| updated_at | 2026-01-11 05:41:00.991339+00 |
| description | Append extensions to file paths / 为文件路径追加扩展名 |
| homepage | https://github.com/js0/rust/tree/main/add_ext |
| repository | https://github.com/js0/rust.git |
| max_upload_size | |
| id | 2035244 |
| size | 46,711 |
add_ext provides utilities for appending extensions to file paths. When a path already has an extension, the new extension is appended after the existing one, preserving the original extension.
Note: Unlike the standard library's Path::with_extension() which replaces the existing extension, add_ext appends the new extension while preserving the original one.
use std::path::PathBuf;
use add_ext::add_ext;
// Standard library behavior (replaces extension)
PathBuf::from("test.json").with_extension("tmp"); // -> "test.tmp"
// add_ext behavior (appends extension)
add_ext("test.json", "tmp"); // -> "test.json.tmp"
// Path without extension
let path = PathBuf::from("test");
assert_eq!(add_ext(&path, "tmp"), PathBuf::from("test.tmp"));
// Path with extension
let path = PathBuf::from("test.json");
assert_eq!(add_ext(&path, "tmp"), PathBuf::from("test.json.tmp"));
// Nested path
let path = PathBuf::from("dir/subdir/file.txt");
assert_eq!(add_ext(&path, "bak"), PathBuf::from("dir/subdir/file.txt.bak"));
// Empty extension
let path = PathBuf::from("file");
assert_eq!(add_ext(&path, ""), PathBuf::from("file."));
// Multiple dots
let path = PathBuf::from("archive.tar.gz");
assert_eq!(add_ext(&path, "tmp"), PathBuf::from("archive.tar.gz.tmp"));
flowchart TD
A[Input Path] --> B{Has Extension?}
B -->|No| C[Append .ext]
B -->|Yes| D[Append .ext after existing]
C --> E[Return PathBuf]
D --> E[Return PathBuf]
The add_ext function accepts any type that can be converted into PathBuf and any type that can be referenced as OsStr. The implementation directly manipulates the underlying OsString by pushing a dot and the extension, ensuring original extensions are preserved.
add_ext/
├── Cargo.toml
├── Cargo.lock
├── src/
│ └── lib.rs
├── tests/
│ └── main.rs
└── readme/
├── en.md
└── zh.md
add_extpub fn add_ext(path: impl Into<PathBuf>, ext: impl AsRef<OsStr>) -> PathBuf
Appends an extension to a path while preserving existing extensions.
Parameters:
path: Target path to extendext: Extension to add (without leading dot)Returns:
PathBuf: Extended pathExamples:
use add_ext::add_ext;
add_ext("test", "tmp"); // -> "test.tmp"
add_ext("file.json", "bak"); // -> "file.json.bak"
add_ext("archive.tar.gz", "tmp"); // -> "archive.tar.gz.tmp"
add_ext("file", ""); // -> "file."
File extensions have been used since the early days of computing to indicate file types. The concept originated with CP/M (Control Program for Microcomputers), created by Gary Kildall of Digital Research Inc. in the mid-1970s. Kildall, often called "the father of the personal computer operating system," designed CP/M with an 8.3 filename format (8 characters for the name, 3 for the extension), where the dot separated the filename from its type identifier. This design later influenced MS-DOS, which Microsoft developed for IBM's first personal computer in 1981.
The practice of appending multiple extensions (e.g., .tar.gz) emerged from Unix's modular design philosophy. The tar (tape archive) utility, developed in the early 1970s at AT&T Bell Laboratories, was designed to bundle multiple files into a single archive but did not include compression. When compression utilities like gzip (created in 1992 by Jean-loup Gailly) became popular, users would first create a .tar archive, then compress it with gzip, resulting in .tar.gz. This two-step process was a historical artifact—modern formats like ZIP and RAR combine archiving and compression in a single operation. The double extension convention persists today as a testament to Unix's "do one thing well" philosophy, where each tool performs a specific task and can be chained together using pipes.
This library follows that tradition, allowing developers to chain extensions for purposes like temporary files, backups, or versioned outputs, while preserving the original extension information.
This project is an open-source component of js0.site ⋅ Refactoring the Internet Plan.
We are redefining the development paradigm of the Internet in a componentized way. Welcome to follow us:
add_ext 提供为文件路径追加扩展名的工具。当路径已有扩展名时,新扩展名会追加在现有扩展名之后,保留原始扩展名。
注意: 与标准库的 Path::with_extension() 替换现有扩展名不同,add_ext 会追加新扩展名并保留原始扩展名。
use std::path::PathBuf;
use add_ext::add_ext;
// 标准库行为(替换扩展名)
PathBuf::from("test.json").with_extension("tmp"); // -> "test.tmp"
// add_ext 行为(追加扩展名)
add_ext("test.json", "tmp"); // -> "test.json.tmp"
// 无扩展名路径
let path = PathBuf::from("test");
assert_eq!(add_ext(&path, "tmp"), PathBuf::from("test.tmp"));
// 有扩展名路径
let path = PathBuf::from("test.json");
assert_eq!(add_ext(&path, "tmp"), PathBuf::from("test.json.tmp"));
// 嵌套路径
let path = PathBuf::from("dir/subdir/file.txt");
assert_eq!(add_ext(&path, "bak"), PathBuf::from("dir/subdir/file.txt.bak"));
// 空扩展名
let path = PathBuf::from("file");
assert_eq!(add_ext(&path, ""), PathBuf::from("file."));
// 多点路径
let path = PathBuf::from("archive.tar.gz");
assert_eq!(add_ext(&path, "tmp"), PathBuf::from("archive.tar.gz.tmp"));
flowchart TD
A[输入路径] --> B{已有扩展名?}
B -->|否| C[追加 .ext]
B -->|是| D[在现有扩展名后追加 .ext]
C --> E[返回 PathBuf]
D --> E[返回 PathBuf]
add_ext 函数接受任何可转换为 PathBuf 的类型和任何可引用为 OsStr 的类型。实现通过直接操作底层 OsString,推入点号和扩展名,确保原始扩展名被保留。
add_ext/
├── Cargo.toml
├── Cargo.lock
├── src/
│ └── lib.rs
├── tests/
│ └── main.rs
└── readme/
├── en.md
└── zh.md
add_extpub fn add_ext(path: impl Into<PathBuf>, ext: impl AsRef<OsStr>) -> PathBuf
为路径追加扩展名,同时保留现有扩展名。
参数:
path: 要扩展的目标路径ext: 要添加的扩展名(不含前导点)返回:
PathBuf: 扩展后的路径示例:
use add_ext::add_ext;
add_ext("test", "tmp"); // -> "test.tmp"
add_ext("file.json", "bak"); // -> "file.json.bak"
add_ext("archive.tar.gz", "tmp"); // -> "archive.tar.gz.tmp"
add_ext("file", ""); // -> "file."
文件扩展名自计算早期就开始用于标识文件类型。这一概念起源于 CP/M(Control Program for Microcomputers,微型计算机控制程序),由 Digital Research 公司的 Gary Kildall 在 1970 年代中期创建。Kildall 常被称为"个人计算机操作系统之父",他设计的 CP/M 采用 8.3 文件名格式(8 个字符用于文件名,3 个用于扩展名),其中点号将文件名与类型标识符分隔开。这一设计后来影响了 MS-DOS,微软在 1981 年为 IBM 的第一台个人计算机开发了 MS-DOS。
追加多个扩展名(如 .tar.gz)的做法源于 Unix 的模块化设计哲学。tar(tape archive,磁带归档)工具由 AT&T 贝尔实验室在 1970 年代早期开发,旨在将多个文件打包成单个归档文件,但不包含压缩功能。当 gzip 等压缩工具(1992 年由 Jean-loup Gailly 创建)变得流行时,用户会先创建 .tar 归档文件,然后用 gzip 压缩,结果就是 .tar.gz。这个两步过程是历史遗留产物——现代格式如 ZIP 和 RAR 将归档和压缩合并为单个操作。双扩展名约定延续至今,见证了 Unix 的"做一件事并做好"哲学,每个工具执行特定任务,可以通过管道链式组合使用。
本库遵循这一传统,允许开发者为临时文件、备份或版本化输出等目的链式添加扩展名,同时保留原始扩展名信息。
本项目为 js0.site ⋅ 重构互联网计划 的开源组件。
我们正在以组件化的方式重新定义互联网的开发范式,欢迎关注: